Docs

Deploy

Pick a deployment target, then follow the guide for it.

Open Markdown

Proa builds one release binary plus a public/ directory. Every target below runs that same artifact, usually as a Docker image. The choice is not about Proa. It is about how much of the platform you want to operate yourself.

Pick a target

RailwayCoolifyDocker, self-managed
Who owns the machineRailwayYou, one VPSYou
Who compiles RustRailwayYour VPS, or GitHub ActionsYou
Preview URL per pull requestOne toggle, domains auto-provisioned, deleted on mergeYes: wildcard DNS + GitHub App + URL templateBuild it yourself
TLS certificatesAutomaticAutomaticCaddy or nginx, renewal yours
Zero-downtime swapHealth-check gatedHealth-check gatedYours
RollbackOne clickOne clickRetag and restart
SecretsService variablesApp env + BuildKit secretsYours
Logs and metricsBuilt inBuilt inShip them yourself
Beside an existing Rails or Django appAwkwardPossibleNative, this is the sidecar shape
Floor costUsage-basedOne VPSOne VPS
Escape hatchIt is your DockerfileIt is your DockerfileYou are already there

Start with Railway unless you have a reason not to. Rust release builds are heavy, and Railway runs them for you. Coolify source builds run on your own VPS, which is why the Coolify guide recommends building in GitHub Actions and deploying a prebuilt image instead.

Choose Coolify when you want a fixed monthly bill, data residency on hardware you control, or several apps sharing one box.

Choose Docker when you are running Proa as a sidecar next to an existing app, deploying into Kubernetes, Nomad, or ECS, or working somewhere a PaaS is not an option. Read the next section first.

What self-managed Docker costs you

Plain Docker is the most flexible target and the most expensive one. Flexibility is not the tradeoff. Labour is.

A platform is roughly ten features in a trench coat. Take it away and you own all ten:

You now buildBecause otherwise
Reverse proxy and TLS renewalNothing terminates HTTPS
Zero-downtime container swapEvery deploy drops in-flight requests
Health-check gating before cutoverA broken build takes production with it
RollbackRecovery means finding the previous image tag under pressure
Secret injectionTokens end up in a .env on the box
Log shipping and retentiondocker logs is your only forensics, until the container restarts
Metrics and alertingYou learn about outages from users
Restart-on-crash policyOne panic ends the deployment
Image garbage collectionThe disk fills, quietly, around week six
Preview environmentsReviewers test on main

None of these are hard. All of them are yours forever, and they are why a cheap VPS is rarely cheaper than a managed platform once your time is priced in.

Take Docker anyway when the alternative does not exist: the sidecar shape in the Rails and Django / Flask migrations puts Proa on the same host as your existing app, routed by your existing proxy. No platform models that well.

What every target needs

Whatever you pick, the app must:

Verify all five before you deploy anywhere:

docker run --rm -p 3000:3000 -e PORT=3000 my-site
curl -fsS http://127.0.0.1:3000/healthz
curl -fsS http://127.0.0.1:3000/static/styles.css -o /dev/null
docker run --rm my-site env | grep -c GITHUB_TOKEN   # expect 0

Build a release binary with proa build --locked --artifact-out <path>, which runs the asset build and the linked RSJS pipeline (a plain cargo build --release skips the assets and fails at link time on any crate with islands), and make the GitHub token available to that build step in CI while the Proa repository is private. The exported binary and public/ are the deployable artifact; the token is never needed at runtime.

Next steps

Search

Type at least 2 characters