How to Run n8n Workflow Automation on a VPS (Self-Hosted Zapier)

How to Run n8n Workflow Automation on a VPS (Self-Hosted Zapier)

Zapier charges $20–$70/month per user and limits you to a fixed number of task executions. n8n (pronounced “n-eight-n”) is the open-source workflow automation platform that connects 400+ apps and services — and when self-hosted on a VPS, it’s completely free with unlimited workflows, unlimited executions, and no per-task pricing.

This guide installs n8n on an Ubuntu VPS using Docker, exposes it via Nginx with SSL, and walks through building your first practical automations.

n8n vs Zapier vs Make: Why Self-Host?

n8n (self-hosted) Zapier Make (Integromat)
Monthly cost $0 (VPS cost only) $20–$70+/user $9–$29+/month
Task/execution limits Unlimited 750–100K tasks 1K–150K ops
Data privacy Your server only Zapier’s servers Make’s servers
Custom code nodes ✅ JavaScript/Python Limited Limited
Integrations 400+ 6,000+ 1,500+
Self-host option ✅ Free

The trade-off: self-hosting requires a VPS and initial setup time. The payoff: zero recurring SaaS costs, complete data privacy, and unlimited automation capacity.

💡 VPS.DO Tip: n8n needs at least 1 GB RAM. A 2 vCPU / 4 GB RAM VPS handles n8n plus other applications comfortably. View Plans →


Step 1: Install Docker and Docker Compose

sudo apt update && sudo apt upgrade -y
sudo apt install docker.io docker-compose nginx certbot python3-certbot-nginx -y
sudo systemctl enable docker
sudo usermod -aG docker $USER
newgrp docker

Step 2: Create n8n Directory and Environment File

mkdir -p /var/apps/n8n
cd /var/apps/n8n
nano .env
# Domain where n8n will be accessible
DOMAIN_NAME=n8n.yourdomain.com

# n8n webhook URL (same as domain)
WEBHOOK_URL=https://n8n.yourdomain.com/

# Database credentials (PostgreSQL for production)
POSTGRES_USER=n8n
POSTGRES_PASSWORD=SecurePostgresPass123!
POSTGRES_DB=n8n

# n8n encryption key (generate with: openssl rand -hex 32)
N8N_ENCRYPTION_KEY=your-32-char-hex-key-here

# Basic auth (optional but recommended)
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=YourAdminPassword!

# Timezone
GENERIC_TIMEZONE=America/New_York

# Enable user management
N8N_USER_MANAGEMENT_DISABLED=false

Step 3: Create Docker Compose File

nano docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:16
    container_name: n8n-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - n8n_postgres_data:/var/lib/postgresql/data
    networks:
      - n8n-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      # Database
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
      DB_POSTGRESDB_USER: ${POSTGRES_USER}
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}

      # n8n settings
      N8N_HOST: ${DOMAIN_NAME}
      N8N_PORT: 5678
      N8N_PROTOCOL: https
      WEBHOOK_URL: ${WEBHOOK_URL}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}

      # Auth
      N8N_BASIC_AUTH_ACTIVE: ${N8N_BASIC_AUTH_ACTIVE}
      N8N_BASIC_AUTH_USER: ${N8N_BASIC_AUTH_USER}
      N8N_BASIC_AUTH_PASSWORD: ${N8N_BASIC_AUTH_PASSWORD}

      # Executions
      EXECUTIONS_DATA_PRUNE: true
      EXECUTIONS_DATA_MAX_AGE: 168    # Keep 7 days of history

    volumes:
      - n8n_data:/home/node/.n8n
    networks:
      - n8n-network
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  n8n_postgres_data:
  n8n_data:

networks:
  n8n-network:
docker compose up -d
docker compose ps  # Verify both services are running

Step 4: Configure Nginx and SSL

sudo nano /etc/nginx/sites-available/n8n
server {
    listen 80;
    server_name n8n.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name n8n.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;
        proxy_cache_bypass $http_upgrade;

        # n8n needs longer timeouts for webhook processing
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d n8n.yourdomain.com

Open https://n8n.yourdomain.com in your browser. You’ll see the n8n interface. ✅


Step 5: Building Your First Workflows

Workflow 1: GitHub → Telegram notifications

Get a Telegram message every time someone opens a pull request on your repository:

  1. Trigger: GitHub → Webhook → On Pull Request opened
  2. Action: Telegram → Send Message
  3. Message: 🔔 New PR: {{$json.pull_request.title}} by {{$json.pull_request.user.login}}

Workflow 2: Daily report from database → Email

  1. Trigger: Schedule → Every day at 8 AM
  2. Action: PostgreSQL → Execute Query (daily stats)
  3. Action: Gmail → Send Email with query results

Workflow 3: New form submission → CRM + Email + Slack

  1. Trigger: Webhook (receives form POST data)
  2. Action: Airtable → Create Record
  3. Action: Gmail → Send welcome email
  4. Action: Slack → Post to #leads channel

Workflow 4: RSS feed monitor → Blog post draft

  1. Trigger: RSS Feed Read → Every hour
  2. Action: HTTP Request → OpenAI/Ollama API (summarize)
  3. Action: WordPress → Create Draft Post

Step 6: Using the Code Node

n8n’s Code node executes JavaScript or Python — making it far more powerful than no-code tools:

// Example: Transform and filter data in a Code node

const items = $input.all();

return items
  .filter(item => item.json.price > 100)  // Filter items
  .map(item => ({
    json: {
      ...item.json,
      // Add computed fields
      price_with_tax: item.json.price * 1.1,
      display_name: item.json.name.toUpperCase(),
      processed_at: new Date().toISOString()
    }
  }));

Step 7: Connecting to External Services

Most-used integrations

Category Services
Communication Telegram, Slack, Discord, Email, SMS
CRM/Sales HubSpot, Salesforce, Pipedrive, Airtable
Databases PostgreSQL, MySQL, MongoDB, Redis
Cloud storage Google Drive, Dropbox, S3, OneDrive
Dev tools GitHub, GitLab, Jira, Linear
AI/ML OpenAI, Anthropic, Google AI, Ollama
E-commerce Shopify, WooCommerce, Stripe
Marketing Mailchimp, Klaviyo, Typeform

Using HTTP Request for any API

For services without a native n8n node, the HTTP Request node connects to any REST API:

// HTTP Request node configuration:
Method: POST
URL: https://api.yourservice.com/endpoint
Authentication: Header Auth
Header Name: Authorization
Header Value: Bearer {{ $env.API_KEY }}
Body: {
  "data": "{{ $json.someField }}"
}

Step 8: Backups and Maintenance

nano ~/backup-n8n.sh
#!/bin/bash
DATE=$(date +%Y-%m-%d)
BACKUP_DIR="/var/backups/n8n"
mkdir -p $BACKUP_DIR

# Export all workflows via n8n CLI
docker exec n8n n8n export:workflow --all \
  --output=/home/node/.n8n/workflows-$DATE.json

# Backup PostgreSQL database
docker exec n8n-postgres pg_dump -U n8n n8n \
  | gzip > $BACKUP_DIR/n8n-db-$DATE.sql.gz

# Backup n8n data volume
docker run --rm \
  -v n8n_data:/data \
  -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/n8n-data-$DATE.tar.gz -C /data .

find $BACKUP_DIR -name "*.gz" -mtime +30 -delete
echo "n8n backup complete: $DATE"
chmod +x ~/backup-n8n.sh
crontab -e
# 0 2 * * * /bin/bash /root/backup-n8n.sh

Update n8n

cd /var/apps/n8n
docker compose pull
docker compose up -d
docker compose ps

Final Thoughts

Self-hosted n8n on a VPS replaces hundreds of dollars per month in Zapier or Make subscriptions with a one-time setup on a $20–50/month VPS. Unlimited workflows, unlimited executions, complete data privacy, and the flexibility of custom code nodes make it one of the highest-value tools you can self-host.

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!