Deploy Activepieces on a VPS
Open-source workflow automation platform — a self-hosted alternative to Zapier with a visual drag-and-drop flow builder.
Prerequisites
- A RamNode VPS running Ubuntu 22.04 or 24.04 (1 GB RAM minimum, 2 GB recommended)
- A domain or subdomain pointed at your VPS IP
- Docker and Docker Compose installed
- Root or sudo access
Recommended: RamNode's 2 GB KVM plan comfortably handles Activepieces, PostgreSQL, and Redis with room for concurrent automations.
Point Your Domain
Create a DNS A record pointing your subdomain to your VPS IP:
automations.yourdomain.com A YOUR_VPS_IPdig +short automations.yourdomain.comInstall Docker and Docker Compose
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugindocker --version
docker compose version
sudo usermod -aG docker $USER
newgrp dockerCreate the Project Directory
mkdir -p /opt/activepieces
cd /opt/activepiecesGenerate Secrets
Activepieces requires an encryption key for stored credentials and a JWT secret for authentication tokens:
# Encryption key (16 bytes / 32 hex chars)
openssl rand -hex 16
# JWT secret (32 bytes / 64 hex chars)
openssl rand -hex 32
# PostgreSQL password
openssl rand -hex 16Save all three values — you will need them in the next step.
Create the Environment File
nano /opt/activepieces/.env# Domain
AP_FRONTEND_URL=https://automations.yourdomain.com
# PostgreSQL
AP_DB_TYPE=POSTGRES
AP_POSTGRES_DATABASE=activepieces
AP_POSTGRES_USERNAME=ap_user
AP_POSTGRES_PASSWORD=CHANGE_ME_PASTE_GENERATED_PASSWORD
AP_POSTGRES_HOST=postgres
AP_POSTGRES_PORT=5432
# Redis
AP_REDIS_TYPE=REDIS
AP_REDIS_HOST=redis
AP_REDIS_PORT=6379
# Security
AP_ENCRYPTION_KEY=CHANGE_ME_PASTE_16_BYTE_HEX
AP_JWT_SECRET=CHANGE_ME_PASTE_32_BYTE_HEX
# Sign-up mode: EMAIL (open), INVITATION (invite-only)
AP_SIGN_UP_ENABLED=truechmod 600 /opt/activepieces/.envWrite the Docker Compose File
services:
activepieces:
image: activepieces/activepieces:latest
container_name: activepieces
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
env_file:
- .env
volumes:
- ap_cache:/usr/src/app/cache
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- ap_network
postgres:
image: postgres:16
container_name: ap_postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${AP_POSTGRES_DATABASE}
POSTGRES_USER: ${AP_POSTGRES_USERNAME}
POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
volumes:
- ap_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${AP_POSTGRES_USERNAME} -d ${AP_POSTGRES_DATABASE}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ap_network
redis:
image: redis:7-alpine
container_name: ap_redis
restart: unless-stopped
volumes:
- ap_redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ap_network
volumes:
ap_postgres_data:
ap_redis_data:
ap_cache:
networks:
ap_network:
driver: bridgeSecurity note: Activepieces binds only to 127.0.0.1:8080, preventing direct public access. All traffic goes through Nginx.
Configure Nginx as a Reverse Proxy
sudo apt install -y nginx certbot python3-certbot-nginxserver {
listen 80;
server_name automations.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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 live flow editor)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Increase timeouts for long-running automation runs
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
}sudo ln -s /etc/nginx/sites-available/activepieces /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxIssue an SSL Certificate
sudo certbot --nginx -d automations.yourdomain.comsudo systemctl status certbot.timerStart Activepieces
cd /opt/activepieces
docker compose up -d
docker compose logs -f activepiecesOn first launch, Activepieces runs database migrations (30–60 seconds). You'll see Activepieces is running when it's ready.
Create Your Admin Account
Open https://automations.yourdomain.com in your browser. The first account you create becomes the platform administrator.
Firewall Configuration
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw statusUpgrading Activepieces
Back up PostgreSQL first
docker exec ap_postgres pg_dump -U ap_user activepieces > \
/opt/activepieces/backup-$(date +%Y%m%d).sqlPull and restart
cd /opt/activepieces
docker compose pull
docker compose up -dActivepieces runs database migrations automatically on startup. Watch the logs after upgrading to confirm migrations complete without errors.
Useful Management Commands
| Task | Command |
|---|---|
| View container status | docker compose ps |
| Tail logs | docker compose logs -f activepieces |
| Restart all services | docker compose restart |
| Stop all services | docker compose down |
| Stop and remove volumes | docker compose down -v |
| Connect to PostgreSQL | docker exec -it ap_postgres psql -U ap_user -d activepieces |
Troubleshooting
502 Bad Gateway on first visit
Activepieces is still running migrations. Wait 60 seconds and refresh. Check progress with docker compose logs -f activepieces.
Container exits immediately
Check for missing or incorrect environment variables. A missing AP_ENCRYPTION_KEY or malformed AP_POSTGRES_PASSWORD will cause an immediate crash.
Webhooks not triggering
Verify AP_FRONTEND_URL matches the public URL exactly, including https://. A mismatch will cause incoming webhooks to fail.
Flows time out on long tasks
The Nginx proxy_read_timeout 300s setting handles most cases. If flows take longer than 5 minutes, increase this value and reload Nginx.
