Requirements
The machine, the operating system, and the two values you have to decide before running the installer.
The machine
| Floor | Recommended | |
|---|---|---|
| RAM | 2 GB — the installer refuses below this | 4 GB |
Free disk on / | 20 GB — the installer refuses below this | 40 GB |
| CPU | 1 vCPU | 2 vCPU |
Below 4 GB the installer warns and continues. Builds are the memory spike, and the warning is about builds rather than about the platform sitting idle.
The operating system
- Ubuntu 22.04, Ubuntu 24.04, or Debian 12. The installer reads
/etc/os-releaseand refuses any other distribution. - amd64 or arm64. Images are published for both and for nothing else.
- Root access for the length of the install.
The installer takes care of everything else — it installs Docker Engine and the Compose v2 plugin if they are missing, creates a 2 GB swapfile if there is no swap, caps the Docker daemon's log files, widens the default address pool, and configures the firewall.
Docker's address pool matters more than it sounds. The default yields roughly
31 bridge networks, and each application gets one. The installer sets a
10.100.0.0/16 base with a /24 size at install time because retrofitting it
later means tearing down every network.
What you have to decide
Two values have no safe default, and the installer reads both from the environment:
A hostname that resolves to this machine — STHORA_HOSTNAME. The portal
is served on it, and it is what the agent on any second machine dials back
to. Create the A record before you install, so the certificate can be
issued on the first attempt.
An email address for the certificate authority — STHORA_ACME_EMAIL.
Let's Encrypt sends expiry warnings there and refuses addresses on reserved
domains, so ops@example.com will not do.
Everything else the installer generates itself.
Optional, and decided later
| A wildcard base domain | STHORA_BASE_DOMAIN. Set it and every application also answers on <slug>.<baseDomain> with no DNS step per application. |
| An SMTP relay | Alerts and password resets go out over it. Without one the platform still runs: sends are skipped and logged, and alerts stay in-app and on webhooks. |
| A GitHub App | Optional. Deploy keys work against every host with nothing registered anywhere; an App adds a repository picker and deployment status on the commit. |
Ports
Inbound 22, 80, and 443 — the installer configures ufw to allow those three and deny
everything else. Port 80 is not optional even if you only serve HTTPS: the ACME HTTP-01
challenge needs it.
Docker publishes ports by writing iptables rules that bypass ufw's chains.
Never start a container by hand with -p on this box — the firewall will
report a port as closed while it is open. Applications deployed through the
platform publish nothing.