Maran

beta · 23 September 2026

Maran 1.0.0-beta.1 — the first installable release

The first release you can install on a server: accounts as real Linux users, websites, PHP versions, SSL, databases, file transfer and backups — published as a beta, with the boundary stated.

The first release that installs on a server and runs a hosting account end to end. It is published as a beta, and the word is meant literally: do not put somebody else's customers on it yet.

The software installs, runs, and does what its screens say. Three things a paid hosting product has to be trusted about have been exercised only in this project's own containers — no certificate has been issued by a real certificate authority, no disk limit has been enforced by a real filesystem, and no restore has been run on real hardware. Those are not known bugs; they are claims nobody has yet verified in the place that counts.

Installing it

bash
curl -sSL https://get.maran.innovayse.com | sudo bash

The installer downloads the artifacts named in a manifest signed with the project's release key, and refuses anything whose signature or checksum does not match. The manifest and the artifacts it names are published at releases.maran.innovayse.com, and the source at the tag this was built from is on GitHub.

Check what the installer will do before running it as root, the same way you would with any script that takes your server: fetch it, read it, then run it.

The files, and checking them yourself

Everything the installer downloads is published at releases.maran.innovayse.com, listed in a manifest signed with the project's release key.

FileSizeSHA-256
agent-x86_64.tar.gz2.9 MBf9a57621ef349cb1bfc2df5f7f812685fb3a5a690834b18bd1ae8df2493fbadc
api-x86_64.tar.gz25.4 MB6f367807e265d06bee9db37d692d0748c5fb815967965c0e59675a0b8468c799
frontend-x86_64.tar.gz340 KB27879087ddb1a0d1e05e92b9b0b4dec6da21a99263388a74e122681ada828009

The signed list is manifest.json with manifest.json.sig beside it, and integrity-manifest.json records every file inside those archives rather than only the archives.

If you would rather not pipe anything into a root shell, the same install without the pipe:

bash
curl -O https://releases.maran.innovayse.com/installer/maran-installer.tar.gz
tar -xzf maran-installer.tar.gz
sudo bash installer/install.sh --channel beta

The public key the installer verifies against ships inside that package at installer/keys/release-signing.pub. Worth saying plainly: a signature checked against a key downloaded from the same host proves only that both came from the same place. To do better, compare that key against the copy in the repository.

What a server gets

  • Hosting accounts that are real Linux users. Creating one provisions the system user, the home directory and the plan's disk quota on the host; suspend, reactivate and delete reach the host too. The agent acts first and the database row follows, so the panel never claims an account the server does not have.
  • Websites — static, PHP and reverse-proxy — with domain aliases and a document root inside the account's home. The agent renders the configuration, makes the server's own validator check the result, and rolls it back if the validation or the reload refuses, so a bad render cannot take a server's other sites down.
  • Several PHP versions side by side, each account with its own pool per version, running as that account's Linux user. Customers may change a whitelisted subset of settings; anything outside the list is refused rather than quietly dropped.
  • SSL over ACME with an HTTP-01 challenge, uploads of your own material, and a renewal pass thirty days before expiry. Key material is written to a root-only store outside every account's home, because a site's PHP runs as that customer.
  • Databases with a dedicated user each, per-plan limits and a size reading. The password is generated, shown once and never stored, so recovery is a reset rather than a retrieval.
  • File transfer — SFTP served by the host's own OpenSSH, each login chrooted into a jail with the account's real home mounted inside it, carrying the account's own uid and no shell. FTPS ships installed but switched off: nothing listens until an administrator turns it on.
  • Backups, an append-only audit journal of every sign-in and every mutation, live log tailing, the firewall, monitoring, and the maran command-line tool.
  • Panel sign-in with Argon2id, short-lived access tokens, refresh rotation where a reused token revokes the whole family, TOTP with recovery codes, and sessions you can revoke individually or everywhere at once.

What it deliberately does not do

DNS, mail, and a web database manager. Each is absent by decision rather than unfinished: a database manager is planned as a separate deployable with its own address and its own authentication rather than half-built here.

Before you install it anywhere that matters

Three limitations are worth knowing in advance, because an operator would otherwise find them out the hard way.

  • No certificate has been issued by a real authority. The whole path does run end to end — registration, order, HTTP-01 challenge served and validated, finalise, download — against pebble, Let's Encrypt's own test server, with the issued certificate's serial matching the one read back out of the PEM. That exercise found a real defect no test had: the client sent no User-Agent, which pebble refuses on every request and Let's Encrypt tolerates. What is still owed is the authority itself: not their rate limits, not validation from the public internet, not their chain. The renewal branch is not exercised at all, because the test forces a fresh challenge every run. HTTP-01 only — no wildcards, which arrive with DNS management.
  • Dropping a database is final. There is no snapshot, no recycle bin and no delay, and nothing in the drop path consults the backup module. A database is restorable only from a backup that already existed.
  • The SSH daemon's jail configuration is watched, and the watch has a stated edge. The installer writes the block that makes a file transfer login a jailed one, and monitoring now reads that block back and raises an alert when it drifts — all four directives individually, so a block whose header survived and whose body was emptied is caught too. It reads the configuration file rather than asking the daemon, because sshd -T never prints the contents of a Match block at all. What it does not do: follow Include directives, or prove that a drifted host really grants a shell. It reports that the configuration no longer says what was written.

The threat notes covering the privileged parts were reviewed and accepted on the release date. That satisfies the project's own second-reviewer rule. It is not an external audit, and this page does not claim one.

Upgrading from 0.1.0

There is no upgrade path, and none is needed: 0.1.0 was scaffolding with no hosting features and nothing running on it to preserve.