Railway

Deploy Zitadel — Modern Open Source IAM & Identity Platform

Self-host Zitadel — modern IAM with OIDC, SAML & multi-tenancy

Deploy Zitadel — Modern Open Source IAM & Identity Platform

Just deployed

/var/lib/postgresql/data

Just deployed

Deploy and Host Zitadel on Railway

Zitadel is a modern, open-source identity and access management (IAM) platform — a cloud-native alternative to Keycloak, Auth0, and Okta with first-class OIDC, SAML, passkeys, MFA, and multi-tenancy. Its API-first design and clean console make enterprise-grade identity approachable without a dedicated DevOps team, and its event-sourced architecture gives a full audit trail of every identity action. This template deploys Zitadel v4 on PostgreSQL with the masterkey and external-domain settings self-hosting depends on.


What This Template Deploys

ServicePurpose
ZitadelThe IAM core (Go) and Login V2 UI (Next.js), console, and API on port 8080
PostgreSQLThe event store and all identity, org, and project data

Both run on Railway's private network. Zitadel v4 is event-sourced — PostgreSQL is the single source of truth — and Railway provides the HTTPS that Zitadel expects to sit behind.


About Hosting

Zitadel is powerful and modern, but self-hosting it has three specifics that determine success — this template handles all three.

ZITADEL_MASTERKEY must be exactly 32 characters, and losing it means total data loss. The masterkey encrypts all secrets at rest. If it's lost or changed, every encrypted value becomes permanently unrecoverable, and a wrong length fails init. Generate a 32-character key, set it once, and back it up offline. This template supplies it via --masterkeyFromEnv so it stays stable across redeploys.

PostgreSQL only — CockroachDB support was dropped in v4. Older Zitadel guides reference CockroachDB, but as of v4, PostgreSQL is the sole supported backend. This template uses Postgres, which is current; anything still wired for CockroachDB is out of date.

The v4 Login UI shares the core's network context. Zitadel v4 splits into a Go core and a Next.js Login V2 UI. The login UI depends on a machine token (PAT) the core generates during first init and must reach the core over the shared network, with ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED=true enabling the new flow. This template wires the core and login UI so authentication works out of the box — the piece a naive Zitadel deployment gets stuck on.

Set the external domain and let Railway handle TLS. ZITADEL_EXTERNALDOMAIN must be your Railway domain and ZITADEL_EXTERNALSECURE=true (traffic is HTTPS), but ZITADEL_TLS_ENABLED=false — Railway terminates TLS at its proxy, so Zitadel must not. This template sets all three.

Typical cost: ~$10–20/month on Railway for Zitadel and Postgres, more if you scale CPU for heavy login traffic. Zitadel hashes passwords with bcrypt/argon2 (deliberately CPU-intensive), so allocate generously for production login load. Zitadel is Apache-2.0 and free to self-host.


How It Compares

Zitadel (self-hosted)KeycloakAuth0 / OktaAuthentik
Cost modelFlat infraFlat infraPer active userFlat infra
ArchitectureEvent-sourced, API-firstTraditionalManagedTraditional
Multi-tenancyNative, first-classVia realmsEnterprise tierBuilt-in
Machine-to-machine authFirst-classYesYesYes
Audit trailFull (event-sourced)PartialVendorYes
Self-hostableYesYesNoYes

Keycloak is the established open-source IAM but XML-heavy and dated in developer experience. Auth0 and Okta are managed and per-user priced. Zitadel's distinction is a modern, event-sourced, API-first platform with native multi-tenancy and strong machine-to-machine support — a full audit trail of every identity action, self-hosted at infrastructure-only cost.

Deploy in Under 5 Minutes

  1. Click Deploy on Railway — Zitadel and PostgreSQL build, and the core runs its init (~4 minutes)
  2. Confirm ZITADEL_MASTERKEY is set to a 32-character value — and save it somewhere safe
  3. Confirm ZITADEL_EXTERNALDOMAIN is your Railway domain, ZITADEL_EXTERNALSECURE=true, and ZITADEL_TLS_ENABLED=false
  4. Open your domain and log in with the initial admin credentials from the config
  5. Create organizations, projects, and applications, and connect your services via OIDC or SAML

Change the initial admin password immediately after first login.

Common Use Cases

  • Modern IAM for your stack — OIDC, SAML, and OAuth2 SSO across all your applications from one platform
  • Multi-tenant SaaS identity — native multi-tenancy makes Zitadel a strong auth backend for products serving many organizations
  • Machine-to-machine auth — first-class service-account and API authentication for backend and microservice communication
  • Audited identity — an event-sourced record of every identity and access change for compliance

Configuration

VariableRequiredDescription
ZITADEL_MASTERKEYRequiredExactly 32 characters. Encrypts all secrets at rest — losing it means total data loss
ZITADEL_EXTERNALDOMAINRequiredYour Railway public domain
ZITADEL_EXTERNALSECURERequiredtrue — traffic is served over HTTPS
ZITADEL_TLS_ENABLEDRequiredfalse — Railway terminates TLS, so Zitadel must not
ZITADEL_DATABASE_POSTGRES_HOSTAuto-injectedPostgreSQL host via Railway reference variable
ZITADEL_DATABASE_POSTGRES_USER_USERNAME / _PASSWORDAuto-injectedDatabase credentials
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIREDPre-settrue — enables the v4 Login UI flow
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAMERecommendedInitial admin username
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDRecommendedInitial admin password — change after first login

ZITADEL_MASTERKEY is exactly 32 characters — back it up. It encrypts every secret in the database. A wrong length fails init; a lost or changed key means the encrypted data is unrecoverable. Generate once, keep stable, store a copy offline.

Let Railway handle TLS. Set ZITADEL_EXTERNALSECURE=true but ZITADEL_TLS_ENABLED=false — Railway terminates HTTPS at its proxy, so Zitadel serving TLS too would break connections. ZITADEL_EXTERNALDOMAIN must match your real domain.


Dependencies for Zitadel Hosting

  • Railway account — ~$10–20/month, more CPU for heavy login traffic
  • PostgreSQL (included); CockroachDB is no longer supported
  • Adequate CPU — bcrypt/argon2 hashing is CPU-bound by design
  • A domain (Railway subdomain or custom) for the external domain setting

Deployment Dependencies

Implementation Details

The template runs ghcr.io/zitadel/zitadel v4 with start-from-init --masterkeyFromEnv against a Railway PostgreSQL service. Zitadel v4 is event-sourced, so Postgres is the single source of truth — every identity, org, project, and config change is stored as an event, giving a complete audit trail. CockroachDB, supported earlier, was dropped, so Postgres is the only backend.

The masterkey must be exactly 32 characters, encrypts all secrets at rest, and must remain constant across redeploys or encrypted data becomes unrecoverable. ZITADEL_EXTERNALDOMAIN, ZITADEL_EXTERNALSECURE=true, and ZITADEL_TLS_ENABLED=false are set so Zitadel builds correct URLs while Railway handles TLS termination. The v4 Login V2 UI (ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED=true) relies on a PAT the core generates during init and communicates with the core over the shared network — wired here so login works on first deploy. Because bcrypt/argon2 hashing is intentionally CPU-intensive, login-heavy instances benefit from generous CPU. Console, OIDC, and SAML endpoints are served on port 8080 behind Railway's HTTPS.


Frequently Asked Questions

What happens if I lose the masterkey? All secrets encrypted at rest become permanently unrecoverable — a total loss of the instance's protected data. It must be exactly 32 characters, set once, kept stable, and backed up offline. This template supplies it from the environment so it persists across redeploys.

Which database does it use? PostgreSQL only. CockroachDB was supported in older versions but dropped in v4, so any guide referencing Cockroach is out of date. This template uses Postgres.

Why ZITADEL_TLS_ENABLED=false if it's secure? Railway terminates HTTPS at its proxy. Zitadel should know traffic is secure (ZITADEL_EXTERNALSECURE=true) but not try to terminate TLS itself (ZITADEL_TLS_ENABLED=false), or connections break.

Why does login use a lot of CPU? Password hashing with bcrypt/argon2 is deliberately CPU-intensive to resist brute-force attacks. Allocate more CPU for heavy concurrent logins.

How do I connect my apps? Create a project and application in the console, then integrate via OIDC or SAML using Zitadel's endpoints. Its API-first design also supports programmatic configuration.


Why Deploy Zitadel on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Zitadel on Railway you get a modern IAM platform with the hard parts solved — the 32-character masterkey set, PostgreSQL wired, the external-domain and TLS settings correct for Railway, and the v4 login UI connected. Enterprise-grade OIDC, SAML, multi-tenancy, and machine-to-machine auth, event-sourced and self-hosted, on infrastructure you own.


Template Content

More templates in this category

View Template
Keycloak
Keycloak template with keywind theme + apple and discord providers

beuz
750
View Template
lua-protector
Test deployed my project first

trianaq765-cmd's Project
31
View Template
bknd
Feature-rich yet lightweight backend

10