Install a Self-Hosted PaaS on a $5 VPS in Five Minutes (Levelrail)
You have a fresh Linux server and an app you would rather not pay Vercel or Heroku to run. This post gets a deployment platform onto that server and a first app live on it. No Kubernetes, no YAML maze.
The platform is Levelrail, a self-hosted platform I am building. It is in beta with no stable release yet, and I will flag where that matters.
TL;DR
| Step | What you do | Time |
|---|---|---|
| 1 | Check the server meets the basics | 1 min |
| 2 | Run the install command | 2 min |
| 3 | Open the dashboard with your setup token | 30 sec |
| 4 | Deploy the sample app from the wizard | 1 min |
| 5 | Point a domain at it for HTTPS | your DNS speed |
Pick your path
Levelrail ships three ways. Most people want the first one.
| Path | Pick it when | Command lives in |
|---|---|---|
install.sh |
You have a real server and want it running as a service | this post |
| Docker | Everything else on the box already runs as containers | the Docker page in the docs |
| Build from source | You are hacking on Levelrail or testing an unreleased commit | the getting started page |
What you need first
The server needs Linux on amd64 or arm64 with systemd. CI tests the install script on Ubuntu 24.04 and Debian 12. Other distros should work, but nobody has tested them.
It also needs root, curl, and ports 80 and 443 open to the internet. Port 80 matters because Let's Encrypt uses it to prove you own the domain.
For size, 1 vCPU, 1 GB of RAM and 10 GB of disk is enough to boot it. Your apps and builds need room on top, so 2 vCPU and 2 GB is more comfortable. The installer warns under 1 GB of RAM and stops under 10 GB of free disk.
Step 1: run the installer
curl -fsSL https://levelrail.com/install.sh | sudo sh
Here is what it does, in order:
preflight checks -> install Docker if missing -> download release
-> verify SHA-256 -> write systemd unit -> wait for /healthz
-> test ports 80/443 -> print URLs and setup token
It checks your OS, architecture, Docker version, RAM, disk and ports before touching anything. If a check fails, it stops and tells you why. You can push past a failed check with --force, though I would read the message first.
The script checks the binary's SHA-256 before it installs. If cosign is on the machine and the release ships a signature, it verifies that too.
Beta note: with no stable release yet, the script installs the newest pre-release. Pin one yourself with
LEVELRAIL_VERSION, or pick a channel withLEVELRAIL_CHANNEL=stableorbeta.
Checkpoint: the script ends by printing dashboard links and a one-time setup token. Keep that terminal open.
Ports 80 and 443 are the only ones the installer will never move on its own. Let's Encrypt only talks to those two. If something else already holds them, such as an old reverse proxy or another Coolify or Dokploy instance, preflight fails and tells you what to change. The dashboard port is different. The default is 8080. If something else holds it, the installer picks the next free port and prints the real number. Use the port from your own output, not the one in this post.The installer printed a port warning
Step 2: sign in with the setup token
Open the link the installer printed. It has your server's IP, the dashboard port and the token:
SERVER_IP:8080/login?setup=TOKEN
Type it into the browser with the plain HTTP scheme in front.
The token lets you create the first admin account. If you lost the terminal output, print the token again on the server:
sudo APP_DATA_DIR=/var/lib/levelrail-data levelrail setup-token
You will see a "connection is not encrypted" banner. Expect it. You stay on plain HTTP until you give the dashboard a domain in step 4.
Back up master.key in the data directory now. It protects your stored secrets, and the installer reminds you for a reason.
Step 3: let the setup wizard do the first deploy
On a fresh instance, the dashboard opens a setup wizard instead of an empty list. It walks five stages.
| Stage | What happens |
|---|---|
| Server check | Runs the same checks as levelrail-cli doctor. A failing check shows a copyable fix command. |
| Dashboard domain | Optional. Shows the exact DNS record to create, then watches DNS and the certificate. |
| Git provider | Optional. Links to each provider's connect flow. |
| First app | Deploys a sample, a template, or your own repo, and waits for a healthy status. |
| Done | Summarizes what you set up. |
Pick the sample app. It runs nginx:alpine with a health check, so it works on any server with no repo needed. The wizard waits for the readiness probe before it calls the deploy healthy. If something breaks, it shows a diagnosis and a link to the logs.
Checkpoint: the sample app shows a healthy status in the dashboard.
Step 4: put a domain on the dashboard
Use a subdomain made for the dashboard, like console.example.com. Do not reuse a domain an app already serves. One of the two will lose the conflict, silently.
In the wizard, enter the domain and an email for certificate notices. Create the A record it shows you, wait for the green checks, and the dashboard moves to HTTPS. Once you save an HTTPS dashboard URL, the server refuses plain HTTP sign-in.
Warning: if the HTTPS URL breaks later and locks you out, set
APP_ALLOW_INSECURE_LOGIN=truewithsudo systemctl edit levelrail, then restart the service.
Step 5: deploy your own app from the CLI
The app spec is one small file in your repo, app.yaml:
version: 1
services:
web:
build:
type: dockerfile
port: 8080
Set your repo and the registry path for the built image, then create and deploy with the CLI:
REPO_URL=your-git-repo-url
IMAGE_REPO=your-registry-path
levelrail-cli apps create \
--name your-app \
--file app.yaml \
--repo "$REPO_URL" \
--image-repo "$IMAGE_REPO"
Check on it with levelrail-cli apps status your-app. Tail logs with levelrail-cli apps logs your-app -f. If a deploy goes wrong, levelrail-cli apps rollback your-app returns to the previous version.
Not sure what the spec needs? Run levelrail-cli apps create --interactive and answer the prompts. Or paste a repo URL, a docker run command or a compose file into the "Import anything" box in the dashboard and read the plan before it creates anything.
What you get on day one, free
Levelrail has one edition under Apache 2.0, with no license key. The binary you just installed includes sign-in with Google, GitHub, Microsoft or any OIDC provider, TOTP two-factor and passkeys, IAM policies, an audit log you can export as CSV, scheduled backups with verification, and deploy approvals.
It does not include SAML or SCIM. If you need either, Levelrail is not ready for you yet.
What I would check before trusting it
Levelrail is beta. It has fewer users and less production time than the platforms it competes with. TLS defaults to an internal issuer, and the public Let's Encrypt path has had less field testing than the rest of the ingress. It runs only on Linux.
But we are working to get it to first stable launch soon getting it ready for production and capture benchmarks !!
Remove it cleanly
One command removes the service, the unit file and the binary, and keeps your data directory:
curl -fsSL https://levelrail.com/install.sh | sudo sh -s uninstall
Add --purge to delete the data directory too. That wipes app and deploy state and the master key, so every stored secret becomes unreadable. Containers, images and volumes your apps created stay behind until you remove them yourself.
What would make you move a side project off a managed host: price, control, or just curiosity? Tell me in the comments, and tell me what broke if the install stumbled.
Try it, and tell me what breaks
Levelrail is open source under Apache 2.0. It is young, so every bug report changes what gets built next.
glincker
/
levelrail
Self-hosted deployment platform: push to git, get a running app with TLS, logs, metrics, and rollback.
Levelrail
Read the docs at levelrail.com
Levelrail is a self-hosted, open-source deployment platform: an alternative to Heroku, Vercel, and Railway that runs on your own Linux servers. Push to a git repo and get a running app with HTTPS, logs, metrics, and one-click rollback.
It is built for people running 3 to 50 services on 1 to 10 machines who do not want to learn Kubernetes. Each server runs a small agent that talks to Docker's Engine API directly, so there is no SSH and no shelling out to the docker CLI. Metrics and logs are part of the core, not a Grafana you install afterwards.
Install
You need a Linux server (amd64 or arm64) with systemd, root access, and ports 80 and 443 open. Docker is installed for you if it is missing.
curl -fsSL https://levelrail.com/install.sh | sudo sh
The installer checks the host, starts Levelrail as…
- The other install options are in the install guide
- The first-deploy walkthrough lives in getting started
- Bugs and feature requests go in the issue tracker
If this post saved you time, a star on the repo helps other self-hosters find it.
GDS K S · thegdsks.com · building Glincker · follow on X @thegdsks
Five minutes to a running platform is only useful if the next five minutes keep it running.


Top comments (0)