Engine on Railway
Railway runs the engine image as a service built from a Docker image. One service can publish both engine ports, each on its own domain. New accounts get trial credits, and after that a service is billed by usage. A deployed service keeps running rather than sleeping, so check Railway's current pricing before you leave it unattended.
Before you start
Section titled “Before you start”- A Railway account and a project.
- A database. A Railway Postgres service in the same project works, or Supabase or Neon.
Deploy
Section titled “Deploy”- Add a service to the project from the Docker image
ghcr.io/lyeve-labs/lyeve-core:latest. Pin a release tag in production. See Docker images. - In the service's networking settings, give one public domain to port
3001(the Admin API) and one to port3002(the Content API). - Add a volume mounted at
/var/lib/lyeve, so the signing key survives a redeploy. The engine runs as uid65532, and Railway documents that an image running as a non-root user cannot write to an attached volume unless the service setsRAILWAY_RUN_UID=0, which runs the container as root. Set it, or the engine cannot write the key. In production the engine refuses to start when it cannot write the key.
Without the volume, every redeploy creates a new key and every token issued before it stops working.
Secrets
Section titled “Secrets”Set these in the service's variables:
DATABASE_URL=postgres://<user>:<password>@<host>:5432/<dbname>?sslmode=requireJWT_SECRET=<openssl rand -hex 32>ENCRYPTION_KEY=<a different openssl rand -hex 32>LYEVE_AUDIT_HMAC_KEY=<a third openssl rand -hex 32>RATE_LIMIT_RPS=100SECURE_COOKIE=trueCORS_ORIGINS=https://your-app.example.comRAILWAY_RUN_UID=0Production refuses to start without these values. Configuration lists every check.
Database
Section titled “Database”For a Railway Postgres service, use the internal connection string Railway generates, which
stays on Railway's network. Use the public one only when something outside Railway reaches the
database. Production refuses the database user postgres, so create a dedicated user for the
engine. Supported databases lists the URL forms.
Health checks
Section titled “Health checks”Set the service's health check path to /readyz. Both listeners serve /healthz, /readyz
and /startup without authentication. Do not use /api/admin/health or /api/v1/health:
they need authentication, so a check gets 401 and marks a healthy service down.
Health endpoints says what each one checks.
Verify
Section titled “Verify”curl https://<content-api-domain>/.well-known/jwks.jsoncurl https://<admin-api-domain>/api/admin/setupThe JWKS document is on the domain for port 3002, and the setup route on the domain for port
3001. A new install answers {"setup_required":true,"token_source":"log"}. The setup token is
the one-time setup_token in the service's log, or LYEVE_SETUP_TOKEN when you set it. The
quickstart continues from step 2.
- Engine on Fly.io: another host that publishes both APIs.
- Production checklist: what to confirm before real traffic.