Why self-host Temporal on a VPS
Temporal solves a problem that few tools truly address: execution durability. A Temporal workflow can last seconds or months, wait for a human event, automatically retry a failed step, and resume exactly where it stopped even if the server restarted in the meantime. It is not a no-code tool: you write the workflow code in an SDK, and Temporal guarantees its deterministic re-execution. Self-hosting on a VPS is relevant when your workflows drive critical operations (payments, provisioning, microservice orchestration) and you want to avoid the dependency and cost of Temporal's managed cloud. The self-hosted server gives you the same engine, under your control, with your own SLAs. Be warned: Temporal is more demanding than the other tools in this series, it is a full-fledged infrastructure.
Concrete benefits of self-hosting
- Native durability: workflow state survives crashes and restarts.
- Automatic retries and timeouts on each activity, with no plumbing code.
- Workflows written in your language: Go, Java, Python or TypeScript.
- Complete Web UI to inspect the execution history step by step.
- Independence from the managed cloud: your data and your SLAs on your side.
- Ideal for sagas, provisioning and microservice orchestration.
Technical requirements
Temporal is made up of several services (frontend, history, matching, worker) plus a database. For a development or small production environment, the official docker-compose with PostgreSQL runs on 2 vCPU and 4 GB of RAM, but aim for 4 vCPU / 8 GB for serious production, because the Temporal services and the database consume together. For real volumes, Temporal recommends Cassandra and a search engine (Elasticsearch) for advanced Visibility queries, which requires more resources. Plan for Docker, Docker Compose, a domain (temporal.yourdomain.com) and open port 7233 (gRPC) on the internal network side, and 8080 for the Web UI.
Deploy Temporal with Docker Compose
Clone the docker-compose repository
Temporal provides a dedicated repository: git clone https://github.com/temporalio/docker-compose.git /opt/temporal && cd /opt/temporal. It contains several variants (PostgreSQL, Cassandra, with or without Elasticsearch).
Choose the PostgreSQL variant
To start reasonably, use docker-compose-postgres.yml. It deploys PostgreSQL, the multi-service Temporal server and the Web UI. Adjust the database password and the allocated resources.
Launch the Temporal server
Start with docker compose -f docker-compose-postgres.yml up -d. The server automatically applies the schema (auto-setup). Check the health with docker compose logs -f temporal then test the CLI: tctl --address temporal:7233 cluster health.
Secure the Web UI behind a proxy
The Web UI (port 8080) does not handle authentication by default. Place it behind Caddy with HTTPS and protection (basic auth or SSO): temporal.yourdomain.com { basicauth { ... } reverse_proxy localhost:8080 }. Never expose port 7233 gRPC publicly.
Configure a namespace
Create a dedicated application namespace rather than using default: tctl --namespace prod namespace register --retention 72h. The retention determines how long the workflow history remains viewable.
Connect a test worker
From your application (the Python SDK for example), connect a worker to temporal.yourdomain.com:7233, register a simple workflow and an activity, and launch an execution. Check its history step by step in the Web UI.
In self-hosting, keep a close eye on the retention and the database size: every event of every workflow is persisted, and an overly long history or millions of executions can inflate PostgreSQL quickly. Set a reasonable namespace retention (for example 72h to 7 days) and enable archiving if you need to keep the history beyond that. For production, separate the application workers (your code) from the Temporal server on distinct containers, or even distinct VPSs, so that a saturated worker never degrades the orchestration cluster.