Back to articles
Technology Insight

Scaling Resilient Distributed Workflows: Deploying Temporal.io on Docker VPS for Long-Running Business Processes

May 30, 2026

Introduction to Modern Workflow Orchestration

In modern enterprise software architecture, managing long-running, distributed, and stateful background processes is a notorious challenge. Traditional microservices relying on ad-hoc message queues, cron jobs, and complex database state tracking often suffer from reliability issues, race conditions, and poor visibility. When a step fails midway through a 14-day customer onboarding sequence or an intricate financial settlement pipeline, recovering gracefully without data corruption requires monumental engineering effort.

This is where Temporal.io shifts the paradigm. Temporal is an open-source, durable execution platform that enables developers to build highly reliable applications without needing to write complex error-handling and state-persistence logic. By ensuring that application state is automatically preserved, Temporal allows workflows to run for seconds, days, or even years. In this guide, we will explore how to architect, deploy, and secure a production-ready Temporal.io system on a Virtual Private Server (VPS) leveraging Docker and Docker Compose.

Understanding the Temporal Architecture

Before diving into the deployment manifest, it is crucial to understand the component blueprint of a Temporal system. Temporal splits execution into two primary layers: the Temporal Server (the orchestrator) and the Temporal Workers (your application code).

  • Temporal Cluster: Consists of internal services including the Frontend, Matching, History, and Worker services. It manages state transitions, queues tasks, and maintains execution history.
  • Persistence Layer: The database back-end where the Temporal Cluster stores workflow mutable state and history. Supported engines include PostgreSQL, MySQL, and Cassandra.
  • Visibility Layer: An optional but highly recommended database (typically Elasticsearch or OpenSearch) that allows advanced querying and filtering of workflows via the web UI or CLI.
  • Temporal Workers: Hosted on your own infrastructure, these workers poll the Temporal Cluster for tasks, execute your business logic, and return the results.
Key Architecture Insight: Your business logic never runs inside the Temporal Server itself. The server acts strictly as an orchestrator, scheduling tasks and recording history, while your external workers execute the code. This decoupling ensures massive scalability and isolation.

Prerequisites for VPS Deployment

To successfully set up Temporal on your VPS, ensure your environment meets the following baseline requirements:

  1. A VPS running a clean installation of a modern Linux distribution (e.g., Ubuntu 22.04 LTS or newer).
  2. Minimum hardware specifications: 2 vCPUs, 4GB RAM, and SSD storage (Temporal can be resource-intensive under heavy database writes).
  3. Docker Engine (v20.10+) and Docker Compose (v2.0+) installed and properly configured.
  4. A registered domain or subdomain pointing to your VPS IP address if you intend to secure the Web UI with SSL/TLS.

Step-by-Step Production Setup with Docker Compose

For a robust VPS deployment, we will construct a production-leaning Docker Compose configuration utilizing PostgreSQL as our primary persistence engine. While Temporal provides default development templates, our configuration focuses on structured volume mapping and environment variables suited for stability.

Step 1: Project Directory and Network Isolation

First, access your VPS via SSH and initialize a dedicated working directory for your Temporal infrastructure:

mkdir -p /opt/temporal-orchestrator
cd /opt/temporal-orchestrator
container_net="temporal-network"

Step 2: Crafting the Docker Compose Manifest

Create a file named docker-compose.yml. This file coordinates the PostgreSQL database, the initialization schema runner, the main Temporal server instance, and the management Web UI.

version: '3.8'

networks:
  temporal-network:
    driver: bridge

volumes:
  postgres_data:
    driver: local

services:
  postgres:
    image: postgres:15-alpine
    container_name: temporal-postgres
    environment:
      POSTGRES_USER: temporal
      POSTGRES_PASSWORD: SecurePassword123!
      POSTGRES_DB: temporal
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - temporal-network
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U temporal"]
      interval: 10s
      timeout: 5s
      retries: 5

  temporal-admin-tools:
    image: temporalio/admin-tools:1.24.2
    container_name: temporal-admin-tools
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
    networks:
      - temporal-network
    depends_on:
      postgres:
        condition: service_healthy
    stdin_open: true
    tty: true

  temporal:
    image: temporalio/auto-setup:1.24.2
    container_name: temporal-server
    ports:
      - "7233:7233"
    volumes:
      - ./dynamicconfig:/etc/temporal/config/dynamicconfig
    environment:
      - DB=postgresql
      - DB_PORT=5432
      - POSTGRES_USER=temporal
      - POSTGRES_PWD=SecurePassword123!
      - POSTGRES_SEEDS=postgres
      - DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development_sql.yaml
    networks:
      - temporal-network
    depends_on:
      postgres:
        condition: service_healthy

  temporal-ui:
    image: temporalio/ui:2.24.0
    container_name: temporal-ui
    ports:
      - "8080:8080"
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
    networks:
      - temporal-network
    depends_on:
      - temporal

Step 3: Initializing and Starting the Services

The temporalio/auto-setup image is highly advantageous for VPS deployment as it automatically runs the required database schema migrations before launching the core server daemons. Start your cluster in detached mode using the following command:

docker compose up -d

Verify that all containers are functioning optimally by auditing the log output:

docker compose logs -f temporal

Once you observe logs indicating that the Frontend and History services have started successfully, your cluster is active. You can navigate to http://your-vps-ip:8080 to view the Temporal Web UI dashboard.

Securing Your Temporal Cluster

Deploying Temporal on a public VPS without additional security measures exposes critical orchestration APIs to malicious actors. To harden your setup for production workloads, adhere to these essential practices:

1. Reverse Proxy and SSL Termination

Do not expose port 8080 or port 7233 directly to the public internet. Instead, utilize a reverse proxy like Nginx or Traefik equipped with Let\'s Encrypt SSL certificates to handle incoming traffic securely. Restrict access to the Web UI via basic authentication or integrated OAuth/OIDC providers.

2. Firewall Hardening via UFW

Configure your system firewall to block unauthenticated external requests to your backend ports. Your external application workers will need access to port 7233 (mTLS gRPC port). If your workers run outside the VPS, explicitly whitelist their origin IP addresses using UFW:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow from [Worker_IP_Address] to any port 7233 proto tcp
sudo ufw enable

3. mTLS (Mutual TLS) Implementation

For enterprise-grade installations, configure mTLS within the Temporal Server settings. This guarantees that only authorized workers holding a valid cryptographic certificate can communicate with the cluster, preventing unauthorized task interception or injection.

Connecting a Worker to Your New Cluster

With the server cluster active on your VPS, you can instantiate a localized worker using one of Temporal\'s SDKs (Go, Java, TypeScript, Python, or .NET). Below is a conceptual example using the TypeScript SDK to connect to your remote VPS instance:

import { Worker } from '@temporalio/worker';
import * as activities from './activities';

async function run() {
  const worker = await Worker.create({
    workflowsPath: require.resolve('./workflows'),
    activities,
    taskQueue: 'critical-business-queue',
    connectionOptions: {
      address: 'your-vps-domain.com:7233',
      // Include TLS configuration credentials here for production
    },
  });

  await worker.run();
}

run().catch((err) => {
  console.error('Worker execution crash:', err);
  process.exit(1);
});

Conclusion and Next Steps

By shifting your background processing model to Temporal.io via Docker, you eliminate the complexity of manual retry states, timeout trackers, and distributed saga orchestrations. Your infrastructure is now capable of executing highly nested, fault-tolerant business logic seamlessly.

As you scale, consider transitioning your storage layer to a managed database instance with automated daily snapshots, implementing Elasticsearch for advanced UI visibility filtering, and setting up Prometheus/Grafana monitoring to keep a finger on the pulse of your workflow execution velocities.

Scaling Resilient Distributed Workflows: Deploying Temporal.io on Docker VPS for Long-Running Business Processes | DPTCloud