Deploying Windmill.dev on a VPS: The High-Performance Workflow Engine Replacing n8n and Temporal
Introduction: The Evolution of Workflow Automation
In the modern DevOps and software engineering landscape, workflow orchestration has become a core architectural pillar. For years, development teams have relied on tools like n8n for low-code automation and Temporal for complex, code-first stateful orchestration. However, a significant gap has persisted between these two paradigms: low-code platforms often lack developer-centric guardrails, while code-first frameworks introduce immense infrastructure complexity.
Enter Windmill.dev—an open-source, ultra-fast, and developer-first alternative that bridges this gap. Built on Rust and Postgres, Windmill offers the raw speed and resource efficiency that modern VPS (Virtual Private Server) deployments require, serving as a viable, high-performance replacement for both n8n and Temporal. This guide provides a comprehensive overview of Windmill's architecture and a step-by-step technical blueprint for deploying it on a self-hosted VPS.
Why Windmill.dev is Replacing n8n and Temporal
Before diving into the deployment mechanics, it is essential to understand why engineering teams are shifting their workloads to Windmill. Choosing a workflow engine requires balancing performance, maintainability, and ease of use.
1. The Performance Paradox: Rust vs. Node.js and Go
While n8n is highly intuitive, its Node.js architecture can become a bottleneck under heavy concurrent loads, leading to high memory consumption. Temporal, on the other hand, is incredibly robust but requires a complex ecosystem of workers, matching engines, and external databases (like Cassandra or Elasticsearch) just to operate efficiently. Windmill circumvents these limitations by utilizing a Rust-based core. It executes scripts in Python, TypeScript, Go, Bash, and Rust with minimal overhead, delivering sub-millisecond scheduling latency and exceptional throughput on minimal hardware footprints.
2. Developer-First Experience with True Code-First Flexibility
Unlike traditional low-code platforms that lock users into proprietary visual builders, Windmill treats code as a first-class citizen. Every step in a Windmill workflow is simply a standard script with typed inputs and outputs. Windmill automatically generates UI forms based on your code's type definitions (such as Pydantic models in Python or TypeScript interfaces). This allows developers to build complex logic using git-controlled code while allowing non-technical stakeholders to trigger workflows via clean, auto-generated user interfaces.
Pre-requisites for VPS Deployment
To ensure a production-ready, highly available Windmill instance, your VPS should meet the following minimum specifications:
- CPU: 2 vCPUs (Dedicated CPU threads are recommended for high-throughput production workloads).
- RAM: 4 GB minimum (8 GB recommended if running intensive Python or TypeScript heavy runtimes).
- Storage: 40 GB SSD/NVMe.
- OS: Ubuntu 22.04 LTS or Ubuntu 24.04 LTS.
- Network: A static public IP address with ports 80 and 443 open.
- Domain: A registered domain or subdomain (e.g.,
windmill.yourcompany.com) pointed to your VPS IP via an A record.
Step-by-Step Guide: Deploying Windmill via Docker Compose
The most reliable and maintainable method to deploy Windmill on a self-hosted VPS is using Docker Compose. This encapsulates the web frontend, the worker pool, and the backend database into isolated, easily upgradable containers.
Step 1: System Update and Docker Installation
First, connect to your VPS via SSH and update the system packages to their latest versions:
sudo apt update && sudo apt upgrade -yNext, install Docker and the Docker Compose plugin if they are not already present on your system:
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL [https://download.docker.com/linux/ubuntu/gpg](https://download.docker.com/linux/ubuntu/gpg) | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] [https://download.docker.com/linux/ubuntu](https://download.docker.com/linux/ubuntu) $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.p/docker.list > /dev/null
sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -yStep 2: Configuring the Windmill Environment
Create a dedicated directory for your Windmill installation to keep configuration files organized:
mkdir -p /opt/windmill && cd /opt/windmillWindmill requires a configuration file to define environment variables, database credentials, and security keys. Create a .env file within this directory:
DATABASE_URL=postgres://windmill_user:secure_password_here@db:5432/windmill?sslmode=disable
WM_SECRET_KEY=generate_a_long_random_string_here
DATABASE_PASSWORD=secure_password_here
BASE_URL=[https://windmill.yourcompany.com](https://windmill.yourcompany.com)Security Note: Always replacesecure_password_hereandgenerate_a_long_random_string_herewith strong, cryptographically secure values to safeguard your workflow state and secrets store.
Step 3: Writing the Docker Compose File
Create a docker-compose.yml file in the same directory. This configuration sets up PostgreSQL as the state store, the Windmill server to handle API traffic, and Windmill workers to execute asynchronous tasks:
version: '3.8'
services:
db:
image: postgres:15-alpine
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_USER: windmill_user
POSTGRES_DB: windmill
healthcheck:
test: ["CMD-SHELL", "pg_isready -U windmill_user -d windmill"]
interval: 5s
timeout: 5s
retries: 5
windmill-server:
image: ghcr.io/windmill-labs/windmill:main
restart: unless-stopped
ports:
- "8000:8000"
environment:
- DATABASE_URL=${DATABASE_URL}
- WM_SECRET_KEY=${WM_SECRET_KEY}
- BASE_URL=${BASE_URL}
depends_on:
db:
condition: service_healthy
windmill-worker:
image: ghcr.io/windmill-labs/windmill:main
restart: unless-stopped
environment:
- DATABASE_URL=${DATABASE_URL}
- WM_SECRET_KEY=${WM_SECRET_KEY}
- MODE=worker
depends_on:
db:
condition: service_healthy
volumes:
db_data:Step 4: Launching the Services
With the environment and compose configuration ready, initialize the containers in detached mode:
sudo docker compose up -dVerify that all containers are running correctly by checking their status:
sudo docker compose psSecuring Your Instance with an Nginx Reverse Proxy and Let's Encrypt
Exposing port 8000 directly to the internet is unsecure. To protect data in transit, we must place Windmill behind an Nginx reverse proxy secured with Let's Encrypt SSL certificates.
1. Install Nginx and Certbot
sudo apt install nginx certbot python3-certbot-nginx -y2. Configure Nginx for Windmill
Create a new Nginx server block configuration:
sudo nano /etc/nginx/sites-available/windmillPaste the following configuration, replacing windmill.yourcompany.com with your actual domain:
server {
listen 80;
server_name windmill.yourcompany.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $$scheme;
# WebSocket support required for Windmill logs
proxy_http_version 1.1;
proxy_set_header Upgrade $$http_upgrade;
proxy_set_header Connection "upgrade";
}
}Enable the site configuration and restart Nginx:
sudo ln -s /etc/nginx/sites-available/windmill /etc/nginx/sites-enabled/
sudo systemctl restart nginx3. Obtain an SSL Certificate
Execute Certbot to automatically fetch and configure an SSL certificate from Let's Encrypt:
sudo certbot --nginx -d windmill.yourcompany.comFollow the interactive prompts to complete the configuration. Certbot will automatically rewrite the Nginx files to enforce secure HTTPS connections.
Post-Deployment Architecture and Scale Considerations
Once you navigate to your domain and log in with the default administrator credentials ([email protected] / password), you will immediately notice the responsiveness of the interface. However, maintaining this velocity at scale requires adhering to production best practices.
Horizontal Worker Scaling
One of Windmill’s structural advantages over n8n is its native capability to scale workers independently of the web server. If your workflows bottleneck due to resource-heavy data processing scripts, you can scale your worker pool instantly by running:
sudo docker compose up -d --scale windmill-worker=3Database Maintenance
Because Windmill relies entirely on PostgreSQL for task state, job queues, and audits, your database will grow continuously. Implement automated automated backup strategies (such as pg_dump cron jobs synced to secure object storage) and periodically review log retention policies within Windmill settings to prevent storage exhaustion.
Conclusion
Windmill.dev represents a paradigm shift in workflow orchestration. By combining the ultra-low latency and safety of a Rust core with a developer-centric, code-first design language, it provides an optimized engineering experience that outpaces n8n in pure performance and vastly simplifies the operational footprint required by Temporal. Deploying Windmill on a self-hosted VPS gives your organization complete data sovereignty, predictable infrastructure expenditures, and an enterprise-grade automation engine ready to scale with your backend requirements.
