Deploy Zitadel
Identity provider for logins, single sign-on and user accounts
Just deployed
/var/lib/postgresql/data
zitadel
Just deployed
/zitadel/bootstrap
mailpit
Just deployed
/data
Deploy and Host Zitadel on Railway
Zitadel is an open-source identity and access management platform: it gives your applications OpenID Connect, OAuth 2, SAML 2, passkeys, multi-factor authentication and an audit trail of every identity event. Written in Go and backed entirely by PostgreSQL, it is built around organizations rather than one flat user directory, so a single instance serves several tenants with their own users, branding and login policies. Teams self-host Zitadel when per-active-user bills scale with signups, when the user database must stay in their own infrastructure, or when a B2B product needs per-customer isolation.
Deploy Zitadel on Railway and the whole v4 stack arrives pre-wired. The main service runs the API, the console and the Login V2 interface behind an internal Caddy router that sends /ui/v2/login to the Next.js login app and everything else — discovery documents, token endpoints, SAML metadata, gRPC-web and Connect-RPC — to the Go API over HTTP/2 cleartext. Managed PostgreSQL holds the event store, and Mailpit catches verification, invitation and password-reset mail privately, so notifications work as soon as the deploy finishes.

Getting Started with Zitadel on Railway
Set ZITADEL_ADMIN_PASSWORD before deploying: it becomes the first administrator's password and needs eight or more characters with an uppercase letter, a lowercase letter, a digit and a symbol. Open the public URL once the deployment is green and it redirects to the login screen. Sign in as zitadel-admin@zitadel. — the organization domain is appended, so the bare zitadel-admin is not found.
The fastest way to prove the instance works is Projects → Create New Project, then add an application: pick the Web type, keep the recommended PKCE method, and enter your redirect URI. Zitadel returns a client ID at once, and /.well-known/openid-configuration already advertises the correct public issuer. Create a user under Users → New with the invitation option, then open the Mailpit URL — protected by MP_UI_AUTH — to read the invitation. Self-service registration is closed by default; enable it per organization in the login policy settings.



About Hosting Zitadel
Zitadel replaces the identity layer you would otherwise buy. It issues and validates tokens, stores users and credentials, enforces login and password policies, federates to external providers, and exposes all of it through REST and gRPC APIs plus a Terraform provider. Every change is stored as an event, so the instance keeps a queryable history of who changed what.
Key features:
- OpenID Connect, OAuth 2 and SAML 2 in one instance, with a login UI branded per organization
- Passkeys, TOTP, OTP over email or SMS, and enforced multi-factor policies
- Multi-tenant organizations with isolated users, domains, roles and settings
- Google, GitHub, GitLab, Microsoft, Apple, generic OIDC, JWT and LDAP federation
- Project roles and project grants for authorization, not just authentication
- Actions and webhooks for customizing tokens and reacting to identity events
The Zitadel service is the whole application — API, console and login UI in one container, fronted by Caddy because Railway routes by hostname while the login interface lives on a URL path. PostgreSQL is the only durable store, and Zitadel creates its own database and scoped role on first boot rather than running as the superuser. Mailpit accepts SMTP privately and shows captured mail in a web inbox.
Why Deploy Zitadel on Railway
Railway removes the infrastructure work self-hosting an identity provider usually involves.
- Managed PostgreSQL with a persistent volume, provisioned and connected for you
- HTTPS and a public domain issued automatically, which Zitadel needs as its issuer
- Private networking between the app, the database and the mail service
- A health check on the database connection, plus one-click rollbacks
Common Use Cases for Self-Hosted Zitadel
- Single sign-on across internal tools, replacing per-app logins with one account and one MFA policy
- Customer identity for a B2B SaaS product, each customer its own organization
- An OIDC provider for services that only speak OAuth — dashboards, wikis, Grafana, proxies
- Moving off a per-active-user vendor while keeping the user database in your own region
Dependencies for Zitadel
- Zitadel — built from gridalpha/zitadel-railway, which composes
ghcr.io/zitadel/zitadelandghcr.io/zitadel/zitadel-loginwithcaddy:2-alpine. Both Zitadel images are pinned to one version, since the API and login interface ship together. - PostgreSQL 18 — event store, projections and cache. Zitadel supports PostgreSQL 14 to 18.
- Mailpit —
axllent/mailpit:latest, an SMTP sink with a web inbox for notification mail.
Environment Variables Reference
| Variable | Purpose |
|---|---|
ZITADEL_MASTERKEY | Encrypts secrets at rest. Exactly 32 characters, and it must never change |
ZITADEL_ADMIN_PASSWORD | Password for the first instance administrator |
ZITADEL_ADMIN_USERNAME | Their username. Defaults to zitadel-admin |
ZITADEL_EXTERNALDOMAIN | Public hostname. Must match the domain users visit |
ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWREGISTER | false closes self-service signup |
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST | Mail host and port for notifications |
MP_UI_AUTH | Username and password for the Mailpit inbox |
Deployment Dependencies
- Source repository: github.com/zitadel/zitadel
- Container images:
ghcr.io/zitadel/zitadelandghcr.io/zitadel/zitadel-login - Docs: zitadel.com/docs
Hardware Requirements for Self-Hosting Zitadel
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB | 2 GB |
| Storage | 1 GB plus the database | 5 GB+ as the event store grows |
| Runtime | PostgreSQL 14+ | PostgreSQL 17 or 18 |
The event store only appends, so database growth tracks identity activity, not user count.
Self-Hosting Zitadel with Docker
Zitadel is one Go binary that needs only PostgreSQL. The smallest useful setup:
docker run -d --name zdb -e POSTGRES_PASSWORD=postgres postgres:18-alpine
docker run -p 8080:8080 --link zdb:db \
-e ZITADEL_DATABASE_POSTGRES_HOST=db \
-e ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD=postgres \
-e ZITADEL_DATABASE_POSTGRES_USER_PASSWORD=zitadel \
-e ZITADEL_EXTERNALSECURE=false -e ZITADEL_TLS_ENABLED=false \
ghcr.io/zitadel/zitadel:latest start-from-init --masterkey "MasterkeyNeedsToHave32Characters"
Upstream also publishes a Compose stack adding Login V2 and a Traefik proxy:
curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/.env.example
cp .env.example .env && docker compose up -d --wait
Change ZITADEL_MASTERKEY and the database passwords in .env before exposing it.
Is Zitadel Free to Self-Host?
Zitadel is open source under AGPL 3.0, so self-hosting costs nothing in licence fees and there is no per-active-user meter. Zitadel Cloud is billed per active user above a free tier, and the company sells support and commercial licences for teams needing an SLA or an alternative to the copyleft terms. On Railway you pay only for compute, database and storage.
FAQ
What is Zitadel?
Zitadel is an open-source identity and access management platform. It acts as an OpenID Connect, OAuth 2 and SAML 2 provider, storing users, credentials, organizations and authorization roles, and issuing the tokens your services validate.
What does this Railway template deploy?
Zitadel v4 with its API, console and Login V2 interface behind an internal router; a managed PostgreSQL database; and Mailpit for notification email. The public domain is generated before first boot, so the OIDC issuer is correct from the start.
Why does the template include a PostgreSQL database?
PostgreSQL is Zitadel's only persistence layer. Users, organizations, projects, tokens, policies and the event log all live there, so the database is what you back up.
Why is Mailpit part of this Zitadel template?
Zitadel emails invitation codes, verification links, password resets and passcodes, and those flows fail silently with no SMTP host. Mailpit captures them in a web inbox; point the SMTP settings at a real relay when you go live.
How do I connect my application to self-hosted Zitadel?
Register an application inside a project and pick the type matching your client. Zitadel returns a client ID and, for confidential clients, a secret. Point your OIDC library at https://your-domain/.well-known/openid-configuration.
Can I use Zitadel for multi-tenant B2B SaaS?
Yes, that is its strongest use case. Each customer becomes an organization with its own users, login policy, branding and verified domain inside one instance, and project grants decide which organizations reach which applications.
Template Content

