Deploy Temporal | Open Source Durable Workflow Engine
Durable execution on Postgres — no Elasticsearch, console behind a password
Temporal UI
Just deployed
Auth Gateway
Just deployed
Temporal
Just deployed
Postgres
Just deployed
/var/lib/postgresql
Deploy and Host Temporal on Railway
Temporal is a durable execution engine: you write ordinary code, and Temporal makes it survive crashes, restarts and week-long waits without you writing a state machine or a retry table. This template runs a complete Temporal cluster with its web console, backed by PostgreSQL and nothing else.
About Hosting Temporal
This template runs the official temporalio/auto-setup image on a pinned stable tag, with the schema created and the default namespace registered on the first boot, plus the official web console and a PostgreSQL 18 database on a persistent Railway volume. Nothing is rebuilt or forked, so upstream releases and upstream security fixes are what you get.
Three decisions shape this deployment, and all three go the other way in most self-hosted Temporal setups.
There is no Elasticsearch. Visibility — the index behind workflow search and the console's list view — lives in Postgres. Temporal's SQL visibility store supports the same list filters, so WorkflowType = "..." and ExecutionStatus = "Running" queries work out of the box. Adding Elasticsearch would roughly triple the memory footprint of the deployment for search features most self-hosted clusters never reach for.
All four Temporal roles run in one container. Frontend, history, matching and worker are separate processes in a large cluster; splitting them here would mean four billed services coordinating over the network to do what one process does over loopback. When you outgrow a single node, the SERVICES variable is how you split them.
The console is behind a password. Temporal's web UI ships no authentication short of wiring up an OIDC provider, and it can read every workflow's full history and terminate anything running. Publishing it on an open domain is not an option, so a Caddy gateway sits in front of it with HTTP basic auth and a generated password. That gateway holds the public domain; the console itself has none.
Common Use Cases
- Multi-step business processes: Payment capture, provisioning, onboarding — anything where step three failing must not lose steps one and two, and where a retry has to resume rather than restart.
- Long-running and scheduled work: Workflows that sleep for days, wait on a human approval, or run on a schedule, without a cron job and a status column pretending to be a state machine.
- Fan-out orchestration across services: Coordinate calls to APIs that fail, rate-limit or time out, with retries, timeouts and compensation expressed in your own language rather than in queue configuration.
Dependencies for Temporal Hosting
Deployment Dependencies
- Temporal Server 1.29 — frontend, history, matching and worker roles
- Temporal Web UI 2.53 behind Caddy 2.11 basic auth
- PostgreSQL 18 on a Railway volume, holding both the cluster and its visibility store
- A Temporal SDK — Go, Java, TypeScript, Python, .NET, PHP or Ruby — in the worker you deploy alongside it
Implementation Details
Workers connect to temporal.railway.internal:7233 from other services in the same Railway project. The frontend is deliberately not on a public TCP proxy. Temporal's gRPC API has no password: anyone who can reach it can read every workflow history and start or terminate workflows, and the only real protection is mutual TLS, which a template cannot generate for you. If you accept that and need external workers anyway, add a TCP proxy on port 7233 in the service's settings — but treat the resulting address as a secret.
BIND_ON_IP is ::. Railway's private network is IPv6-only, and Go leaves a wildcard socket dual-stack, so this one value is what makes the frontend reachable from the console and from your workers. 0.0.0.0 binds successfully and then nothing in the project can reach it.
TEMPORAL_BROADCAST_ADDRESS is 127.0.0.1. Temporal's roles find each other through ringpop membership, and each one advertises an address the others must be able to dial — :: is not one. Since all four roles share this container, loopback is both correct and stable, where the container's own IPv6 address changes on every deploy.
NUM_HISTORY_SHARDS is 512, and it is the one setting here you cannot change later: the shard count is written into the database on the first boot, and a different value describes a different cluster. Temporal's own docker-compose ships 4, which is a development value that permanently caps write throughput. Starting at the recommended production number costs nothing measurable while the cluster is small.
Neither Temporal nor Postgres carries a healthcheck. Railway probes healthchecks from outside over the public domain, and neither service has one — nor should. The gateway has one, at /healthz, which Caddy answers before the auth block so the probe is not the one request that needs a password.
The gateway derives Caddy's bcrypt hash from GATEWAY_PASSWORD at boot rather than storing it, so rotating the password is a matter of editing that one variable and redeploying.
Why Deploy Temporal 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 Temporal on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
Resources: idle, this deployment measures around 240 MB for the Temporal server, 240 MB for Postgres and under 40 MB for the console and gateway together — roughly 520 MB and a tenth of a vCPU, on the order of $8 a month of usage before your own workers. The Temporal server is what grows under load; give it room before Postgres. Workflow history is what fills the volume, so DEFAULT_NAMESPACE_RETENTION (72 hours here) is the dial that matters most for storage.
Template Content
Temporal UI
temporalio/ui:2.53.1Auth Gateway
caddy:2.11.4-alpineTemporal
temporalio/auto-setup:1.29.7Postgres
postgres:18.4-alpine