Self-hosting open source tools on budget VPS

Self-hosting open source tools on budget VPS

What You’ll Need

  • n8n Cloud or self-hosted n8n instance
  • Hetzner VPS or Contabo VPS for hosting ($3-8/month)
  • DigitalOcean as an alternative ($4/month Droplet)
  • Namecheap for domain registration (if needed)
  • SSH client (built into macOS/Linux, PuTTY for Windows)
  • Basic Linux command-line knowledge
  • Docker installed on your VPS (we’ll cover this)

Table of Contents

  1. Why Self-Host Open Source Tools
  2. Choosing the Right Budget VPS
  3. Setting Up Your Server Foundation
  4. Installing and Configuring n8n
  5. Running PostgreSQL for Data Storage
  6. Securing Your Self-Hosted Stack
  7. Monitoring and Maintenance
  8. Getting Started

Why Self-Host Open Source Tools

I’ve spent the last three years building automation workflows, and the cost difference between SaaS and self-hosted solutions is staggering. When you’re running dozens of workflows daily, platform fees add up fast. Self-hosting open source tools like n8n gives you complete control, unlimited automation runs, and data stored on your infrastructure.

The trade-off? You manage the server. But on a $5/month VPS, that’s still a massive win compared to $29/month per seat on managed platforms.

For context, if you’re deciding between workflow automation solutions, I’ve compared the actual costs of Temporal vs n8n vs Zapier API Automation Costs in another guide—self-hosting n8n consistently wins for small-to-medium teams.


Choosing the Right Budget VPS

I’ve tested hosting on Hetzner VPS , Contabo VPS , and DigitalOcean . Here’s what actually matters:

Hetzner CPX11 ($5.29/month): 2 vCPU, 4GB RAM, 40GB SSD

  • Best value. Runs n8n + PostgreSQL smoothly.
  • Datacenter in Europe; excellent uptime.
  • Slightly slower dashboard than competitors.

Contabo VPS S ($3.99/month): 4 vCPU, 8GB RAM, 200GB SSD

  • Marketed aggressively, but oversold during peak hours.
  • Fine for hobby projects; I’d upgrade for production.

DigitalOcean Droplet ($4/month): 512MB RAM, 1 vCPU, 10GB SSD

  • Too small for n8n + database. Upgrade to $6/month tier ($1GB RAM).
  • Premium support and one-click installs reduce headaches.

My pick: Hetzner VPS for production, DigitalOcean for learning. Both have excellent uptime (99.9%+).

For your domain, grab it from Namecheap —$0.88/year for .xyz domains, and they’re good at DNS management.


Setting Up Your Server Foundation

I’ll walk you through deploying on a fresh Ubuntu 22.04 LTS instance. This setup takes 20 minutes if you follow exactly.

Step 1: SSH into your server

ssh root@your_vps_ip_address

Replace your_vps_ip_address with the actual IP. Your hosting provider emails this at signup.

Step 2: Update system packages

apt update
apt upgrade -y

This patches security vulnerabilities—critical for production.

Step 3: Install Docker and Docker Compose

apt install -y curl gnupg2 lsb-release ubuntu-keyring
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | 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 $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Verify installation:

docker --version
docker compose version

Step 4: Create a non-root user (security best practice)

useradd -m -s /bin/bash automation
usermod -aG docker automation
su - automation

Docker commands now work without sudo. This prevents accidental root-level damage.


Installing and Configuring n8n

n8n is my workflow engine of choice—1400+ pre-built integrations, visual editor, and bulletproof reliability.

💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.

Step 1: Create project directory

cd ~
mkdir n8n-deployment
cd n8n-deployment

Step 2: Create docker-compose.yml

I’m using PostgreSQL for persistence (SQLite corrupts on larger deployments).

version: '3.8'

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

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: always
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: n8n
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: secure_password_change_this_12345
      N8N_PROTOCOL: https
      N8N_HOST: your_domain.com
      N8N_PORT: 443
      N8N_SECURE_COOKIE: "true"
      N8N_EDITOR_BASE_URL: https://your_domain.com/
      WEBHOOK_TUNNEL_URL: https://your_domain.com/
      NODE_ENV: production
      NODE_OPTIONS: --max-old-space-size=1024
    volumes:
      - n8n_data:/home/node/.n8n
    ports:
      - "5678:5678"
    networks:
      - n8n-network

  nginx:
    image: nginx:alpine
    container_name: n8n-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - n8n
    networks:
      - n8n-network

volumes:
  postgres_data:
  n8n_data:

networks:
  n8n-network:
    driver: bridge

Replace secure_password_change_this_12345 with a 32-character random string:

openssl rand -base64 32

Replace your_domain.com with your actual domain.

Step 3: Create nginx.conf

cat > nginx.conf << 'EOF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;
    sendfile on;
    keepalive_timeout 65;
    gzip on;

    upstream n8n {
        server n8n:5678;
    }

    server {
        listen 80;
        server_name your_domain.com;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name your_domain.com;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

        client_max_body_size 50M;

        location / {
            proxy_pass http://n8n;
            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_read_timeout 3600s;
            proxy_connect_timeout 3600s;
            proxy_send_timeout 3600s;
        }
    }
}
EOF

Running PostgreSQL for Data Storage

PostgreSQL handles persistence better than SQLite, especially when scaling. The docker-compose setup above includes it, but here’s the manual approach if you prefer:

Step 1: Start PostgreSQL

docker run -d \
  --name n8n-postgres \
  --restart always \
  -e POSTGRES_DB=n8n \
  -e POSTGRES_USER=n8n \
  -e POSTGRES_PASSWORD=secure_password_change_this_12345 \
  -v postgres_data:/var/lib/postgresql/data \
  postgres:15-alpine

Step 2: Verify it’s running

docker ps
docker logs n8n-postgres

You should see “database system is ready to accept connections.”


Securing Your Self-Hosted Stack

This is non-negotiable. Open-source tools on public

Want to automate this yourself?

Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.

system online