Deploying Activepieces on Hetzner Using Docker Compose
What You’ll Need
- A cloud instance from Hetzner VPS or Contabo VPS running Ubuntu 22.04 LTS
- A domain name registered with Namecheap
- An account with DigitalOcean if you prefer an alternative server provider
- Basic familiarity with open source automation engines compared against n8n Cloud or SaaS alternatives like Make.com
Table of Contents
- Provisioning Your Hetzner Server and Firewall Setup
- Activepieces Architecture and Docker Compose Configuration
- Configuring Caddy Reverse Proxy and SSL Certificates
- Day-2 Operations: Backup, Updates, and Monitoring
- Getting Started
Provisioning Your Hetzner Server and Firewall Setup
Self-hosting an automation engine gives you absolute control over your execution environment, data privacy, and monthly compute costs. Activepieces is an open-source, TypeScript-based workflow automation platform designed to be lightweight, modular, and fast. Deploying it on a high-performance cloud server provides a rock-solid infrastructure for processing webhooks, API requests, and scheduled background jobs.
To begin, log into your account on Hetzner VPS and spin up a new Cloud Server instance. For production workloads with multiple active flows, I recommend selecting at least a CX22 or CX32 server instance running Ubuntu 22.04 LTS. Assign a static IPv4 address to your server so your domain records remain stable.
Once your server boots, SSH into the machine as the root user:
ssh root@your_server_ip
First, update your package cache and upgrade all existing system dependencies to their latest stable releases:
apt update && apt upgrade -y
Next, create a dedicated non-root deploy user with sudo privileges to manage your container environment safely:
useradd -m -s /bin/bash deploy
usermod -aG sudo deploy
passwd deploy
Switch to the newly created deploy user and set up Docker’s official repository:
su - deploy
sudo apt-get install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker deploy
Log out and back in as deploy to ensure your shell inherits the new Docker group permissions. Test that Docker runs without root privileges by executing:
docker run hello-world
Network security must be configured before exposing any application services to the public internet. You should follow best practices for Configuring UFW Firewall Rules On Linux Servers to restrict unauthorized access to your instance. Run the following commands to block all inbound traffic except OpenSSH, HTTP, and HTTPS:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.
Activepieces Architecture and Docker Compose Configuration
Activepieces relies on three core services to execute automation tasks reliably:
- PostgreSQL database for storing user accounts, flow definitions, execution history, and connection credentials.
- Redis instance for managing job queues, worker coordination, and pub/sub event distribution.
- Activepieces container hosting the engine, web dashboard, and sandboxed code execution workers.
Create a dedicated directory on your server to house your stack configurations:
mkdir -p ~/activepieces
cd ~/activepieces
We need to generate two distinct cryptographically secure secrets for session encryption and database protection. Generate these secrets using OpenSSL:
openssl rand -hex 32
openssl rand -hex 32
Create a .env file inside ~/activepieces using your terminal editor. Populate every configuration variable fully without missing keys:
AP_ENGINE_EXECUTOR=SANDBOXED
AP_CONTAINER_SANDBOX_TIMEOUT_IN_SECONDS=600
AP_ENVIRONMENT=prod
AP_ENCRYPTION_KEY=e4f82a938c1b472e90f1d2c3b4a5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3
AP_JWT_SECRET=9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b
AP_FRONTEND_URL=https://automation.yourdomain.com
AP_POSTGRES_DATABASE=activepieces
AP_POSTGRES_USER=activepieces_user
AP_POSTGRES_PASSWORD=super_secure_postgres_password_9872
AP_POSTGRES_HOST=postgres
AP_POSTGRES_PORT=5432
AP_REDIS_HOST=redis
AP_REDIS_PORT=6379
AP_REDIS_PASSWORD=super_secure_redis_password_6541
AP_TELEMETRY_ENABLED=false
Now create the docker-compose.yml file in the same directory. This file defines the full dependency tree, volume mounts, network boundaries, and environment configurations:
version: '3.8'
networks:
activepieces-net:
driver: bridge
volumes:
postgres_data:
driver: local
redis_data:
driver: local
activepieces_data:
driver: local
services:
postgres:
image: postgres:15-alpine
container_name: activepieces-postgres
restart: always
env_file:
- .env
environment:
POSTGRES_DB: ${AP_POSTGRES_DATABASE}
POSTGRES_USER: ${AP_POSTGRES_USER}
POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- activepieces-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${AP_POSTGRES_USER} -d ${AP_POSTGRES_DATABASE}"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: activepieces-redis
restart: always
command: redis-server --requirepass ${AP_REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- activepieces-net
healthcheck:
test: ["CMD", "redis-cli", "-a", "${AP_REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
activepieces:
image: activepieces/activepieces:latest
container_name: activepieces-app
restart: always
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
env_file:
- .env
environment:
AP_POSTGRES_HOST: postgres
AP_POSTGRES_PORT: 5432
AP_POSTGRES_DATABASE: ${AP_POSTGRES_DATABASE}
AP_POSTGRES_USER: ${AP_POSTGRES_USER}
AP_POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
AP_REDIS_HOST: redis
AP_REDIS_PORT: 6379
AP_REDIS_PASSWORD: ${AP_REDIS_PASSWORD}
AP_ENCRYPTION_KEY: ${AP_ENCRYPTION_KEY}
AP_JWT_SECRET: ${AP_JWT_SECRET}
AP_FRONTEND_URL: ${AP_FRONTEND_URL}
AP_ENGINE_EXECUTOR: ${AP_ENGINE_EXECUTOR}
AP_CONTAINER_SANDBOX_TIMEOUT_IN_SECONDS: ${AP_CONTAINER_SANDBOX_TIMEOUT_IN_SECONDS}
AP_ENVIRONMENT: ${AP_ENVIRONMENT}
AP_TELEMETRY_ENABLED: ${AP_TELEMETRY_ENABLED}
ports:
- "127.0.0.1:8080:80"
volumes:
- activepieces_data:/usr/src/app/dist
- /var/run/docker.sock:/var/run/docker.sock
networks:
- activepieces-net
This stack routes the application traffic through port 8080 restricted to localhost (127.0.0.1). This isolates Activepieces from direct public internet exposure until our reverse proxy handles incoming requests.
Configuring Caddy Reverse Proxy and SSL Certificates
To expose Activepieces securely over HTTPS, we use Caddy as our edge reverse proxy. Caddy automatically provisions and renews TLS certificates via Let’s Encrypt without external cron jobs or Certbot configurations.
Head over to Namecheap and update your domain settings. Add an A record pointing automation.yourdomain.com directly to the public IP address of your server.
Install Caddy natively on Ubuntu:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
Now overwrite the default Caddyfile located at /etc/caddy/Caddyfile with a clean configuration tailored for Activepieces:
automation.yourdomain.com {
encode gzip zstd
reverse_proxy 127.0.0.1:8080 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
log {
output file /var/log/caddy/activepieces_access.log {
roll_size 10mb
roll_keep 10
}
}
}
Validate your Caddyfile for syntax issues and reload the systemd service:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
Start the Docker Compose deployment:
cd ~/activepieces
docker compose up -d
Verify that all three containers are healthy and running:
docker compose ps
You can now open https://automation.yourdomain.com in your web browser. You will be greeted by the Activepieces onboarding screen where you can create your primary administrative owner account.
If you are running multiple microservices on the same server alongside Activepieces, such as a backend database engine detailed in Deploying Self-Hosted PocketBase on Cloud Servers, Caddy will manage separate hostnames effortlessly within that single /etc/caddy/Caddyfile.
For log collection across your application suite, consider Configuring Centralized Log Aggregation with Grafana Loki to stream Caddy logs, Postgres output, and Activepieces runtime logs into a single unified monitoring dashboard.
Day-2 Operations: Backup, Updates, and Monitoring
Deploying the stack is only step one. Managing state, performing automated backups, and upgrading Activepieces reliably ensure your workflow automation engine stays online without loss of data.
Database and Configuration Backups
Create an automated backup script located at /home/deploy/activepieces/backup.sh:
#!/bin/bash
set -e
BACKUP_DIR="/home/deploy/backups/activepieces"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
CONTAINER_NAME="activepieces-postgres"
DB_USER="activepieces_user"
DB_NAME="activepieces"
mkdir -p "${BACKUP_DIR}"
echo "[${TIMESTAMP}] Starting PostgreSQL backup..."
docker exec -t ${CONTAINER_NAME} pg_dump -U ${DB_USER} -d ${DB_NAME} -F c > "${BACKUP_DIR}/db_backup_${TIMESTAMP}.dump"
echo "[${TIMESTAMP}] Backing up environment files..."
cp /home/deploy/activepieces/.env "${BACKUP_DIR}/env_backup_${TIMESTAMP}"
echo "[${TIMESTAMP}] Pruning backups older than 14 days..."
find "${BACKUP_DIR}" -type f -mtime +14 -delete
echo "[${TIMESTAMP}] Backup completed successfully."
Make the script executable:
chmod +x /home/deploy/activepieces/backup.sh
To automate daily execution at 2:00 AM, add a task to your user crontab:
crontab -e
Append the following line to the crontab file:
0 2 * * * /home/deploy/activepieces/backup.sh >> /home/deploy/backups/backup.log 2>&1
Performing Zero-Downtime Container Upgrades
When a new release of Activepieces is published, update your running instance by pulling the latest image tags, recreating the containers, and pruning old unused layers:
cd ~/activepieces
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
Because database migrations are handled internally by the Activepieces backend on startup, the application automatically upgrades its internal state schemas before opening ports to serve web requests.
Getting Started
Deploying Activepieces on Hetzner VPS or Contabo VPS gives you an exceptionally fast, cost-effective automation stack without execution limits or payload throttling. By provisioning your server securely, tying DNS records through Namecheap, running services via Docker Compose, and terminating SSL with Caddy, you build a production-grade infrastructure tailored for demanding modern integrations.
Outsource Your Automation
Don’t have time? I build production n8n workflows, WhatsApp bots, and fully automated YouTube Shorts pipelines. Hire me on Fiverr, mention SYS3-HUGO for priority. Or DM at chasebot.online.
Want to automate this yourself?
Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.
Want this engine running on your own VPS?
This blog publishes itself — daily, unattended, on free API tiers. The full engine, Hugo theme, and setup guide are available as System 3.
Get System 3