Limited time offer: Get .COM at ₦10000 Use NGNEWCOM
India English
Kenya English
United Kingdom English
South Africa English
Nigeria English
United States English
United States Español
Indonesia English
Bangladesh English
Egypt العربية
Tanzania English
Ethiopia English
Uganda English
Congo - Kinshasa English
Ghana English
Côte d’Ivoire English
Zambia English
Cameroon English
Rwanda English
Germany Deutsch
France Français
Spain Català
Spain Español
Italy Italiano
Russia Русский
Japan English
Brazil Português
Brazil Português
Mexico Español
Philippines English
Pakistan English
Turkey Türkçe
Vietnam English
Thailand English
South Korea English
Australia English
China 中文
Canada English
Canada Français
Somalia English
Netherlands Nederlands

How to Run n8n on a VPS: A Step-by-Step Guide

Buy domains, business emails, hosting, VPS and more: Get Started

Cheapest Domains in Nigeria

Get your .com.ng domain now for just ₦5,500

.COM.NG for ₦5,500 | .COM for ₦10,000

If you are using n8n for serious automation workloads, self-hosting gives you more control over your environment, data, and costs. Instead of relying on a managed service, you run the stack on your own VPS and take responsibility for updates, security, storage, and maintenance.

This guide walks through a production-ready setup using Docker, PostgreSQL, Nginx as a reverse proxy, Let’s Encrypt TLS, firewall rules, and automated backups. It is written for users who are comfortable working in a terminal but may be new to server administration.

What you’ll need

  • A VPS with at least 2GB RAM. 1GB can run n8n alone for light use, but Postgres alongside it wants headroom; under-provisioning here is the most common cause of containers that restart in a loop.
  • Ubuntu 22.04 or 24.04 LTS. The commands below assume one of these; Debian 11/12 is nearly identical.
  • A domain name you can point at the server (e.g., n8n.yourdomain.com). n8n’s webhook features and OAuth-based integrations require a real HTTPS domain; an IP address alone won’t work for those.
  • SSH access to the server, with root or sudo privileges.

Step 1: Initial server setup

Connect to the server:

ssh root@your-server-ip

Update the system, then create a non-root user with sudo access (skip the adduser step if one already exists):

apt update && apt upgrade -y
adduser deploy
usermod -aG sudo deploy

Log out and back in as deploy for the remainder of this guide. Running Docker and application services as root is an unnecessary risk for no benefit.

Step 2: Point your domain at the server

In your DNS provider’s dashboard, add an A record:

FieldValue
Hostn8n (or whichever subdomain you prefer)
Valueyour server’s public IPv4 address
TTLProvider default is fine

DNS propagation ranges from a few minutes to a few hours depending on your registrar and TTL. You can continue through the Docker and n8n setup while waiting; you’ll only need DNS resolved by Step 11, when Certbot issues the certificate.

how to run n8n on a vps

Step 3: Install Docker and Docker Compose

Docker is the recommended install path. It isolates n8n and Postgres from the host OS and reduces updates to docker compose pull && docker compose up -d.

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Log out and back in for the group membership to take effect, then confirm both are working:

docker --version
docker compose version

Docker Compose ships as a plugin (docker compose, no hyphen) with current Docker installs, no separate binary to fetch.

Step 4: Set up the project directory

Keep the compose file, environment file, and any local file mounts together so backups and upgrades stay simple:

mkdir -p ~/n8n-compose/local-files
cd ~/n8n-compose  

Step 5: Generate your encryption key

n8n uses one key to encrypt stored credentials (API keys, tokens, passwords). Generate it before the first launch:

openssl rand -hex 32

Store the output in a password manager or secrets vault.

This key is critical: losing it, or starting n8n without it, makes existing credentials unreadable. There is no recovery; services must be connected again. Set it once and always keep it configured.

Step 6: Create the .env file

nano ~/n8n-compose/.env
# Domain
N8N_HOST=n8n.yourdomain.com
N8N_PORT=5678
N8N_PROTOCOL=https
NODE_ENV=production
WEBHOOK_URL=https://n8n.yourdomain.com/
N8N_PROXY_HOPS=1

# Timezone
GENERIC_TIMEZONE=Etc/UTC

# Encryption key
N8N_ENCRYPTION_KEY=paste-your-generated-key-here

# Postgres
POSTGRES_USER=n8n
POSTGRES_PASSWORD=use-a-long-random-password-here
POSTGRES_DB=n8n

Three settings commonly cause issues:

N8N_PROXY_HOPS=1 tells n8n it is behind one reverse proxy (Nginx). Without it, n8n may detect the wrong IP or protocol, affecting webhooks and security checks.

WEBHOOK_URL must exactly match your public HTTPS URL. If it is wrong, webhook URLs may look correct in n8n but fail when external services call them.

GENERIC_TIMEZONE controls scheduled workflows. The wrong timezone causes Cron jobs to run at unexpected times.

Replace the domain, encryption key, and database password values before continuing.

Step 7: Write the Docker Compose file

nano ~/n8n-compose/docker-compose.yml
services:
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]

  n8n:
    image: n8nio/n8n:1
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - N8N_HOST=${N8N_HOST}
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_USER=${POSTGRES_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  postgres_data:
  n8n_data:

Key choices:

  • 127.0.0.1:5678:5678 keeps n8n private; Nginx handles public access.
  • n8n_data stores encryption keys and settings. Deleting it can make credentials unreadable.
  • n8nio/n8n:1 avoids unexpected major version upgrades.
  • service_healthy starts n8n only after Postgres is ready.
how to run n8n on a vps

Step 8: Start n8n

docker compose up -d
docker compose ps
docker compose logs -f n8n

Both containers should show as healthy/running. The n8n logs should show it initializing the database and listening for connections. Ctrl+C stops following the logs without stopping the container.

Before touching the public domain, confirm it’s reachable locally:

curl -I http://127.0.0.1:5678

An HTTP/1.1 200 OK (or a redirect) means n8n is up and the rest is networking and TLS.

Step 9: Configure the firewall

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Port 5678 stays closed to the outside world; it’s already bound to localhost in Step 7, and the firewall is a second layer against misconfiguration. All public traffic reaches n8n through Nginx on 443.

Step 10: Install and configure Nginx reverse proxy

Install Nginx:

sudo apt install nginx -y

Create the n8n server block:

sudo nano /etc/nginx/sites-available/n8n
server {
    listen 80;
    server_name n8n.yourdomain.com;

    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_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

The WebSocket headers and longer timeouts prevent interruptions during live updates and long-running workflows.

Enable the site and reload Nginx:

sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
how to run n8n on a vps

Step 11: Add SSL with Certbot

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d n8n.yourdomain.com

Certbot prompts for an email (used for renewal and expiry notices) and asks you to accept the Let’s Encrypt terms. It then edits the Nginx server block directly, adding the listen 443 ssl directive, pointing at the issued certificate, and configuring an automatic HTTP-to-HTTPS redirect.

Confirm the renewal timer works before you need it:

sudo certbot renew --dry-run

Let’s Encrypt certificates expire every 90 days; the Certbot package installs a systemd timer (or cron job, on older setups) that renews automatically well before that, so this step is a one-time check rather than an ongoing chore.

Step 12: First login

Visit https://n8n.yourdomain.com. On first load, n8n prompts for an owner account: email, name, and password. This account has full administrative access to the instance; use a strong, unique password, ideally stored in the same password manager as the encryption key.

Once logged in, you’ll land on the workflow canvas, with the credentials store and executions list in the left sidebar. The instance is live and ready for workflows.

Step 13: Set up backups

Back up two things: the Postgres database (workflows, credentials, executions) and the n8n_data volume (encryption key and settings). Losing either means rebuilding the instance.

Create ~/n8n-compose/backup.sh:

#!/bin/bash
set -e

BACKUP_DIR=~/n8n-backups
TIMESTAMP=$(date +%F_%H-%M-%S)

mkdir -p "$BACKUP_DIR"
cd ~/n8n-compose

# Backup database
docker compose exec -T postgres pg_dump -U n8n n8n > "$BACKUP_DIR/n8n_db_$TIMESTAMP.sql"

# Backup workflows and credentials
docker compose exec -T n8n n8n export:workflow --backup --output=/home/node/.n8n/workflows_$TIMESTAMP
docker compose exec -T n8n n8n export:credentials --backup --output=/home/node/.n8n/credentials_$TIMESTAMP

# Remove backups older than 14 days
find "$BACKUP_DIR" -type f -mtime +14 -delete

Make it executable and schedule it daily:

chmod +x ~/n8n-compose/backup.sh
crontab -e

Add:

0 2 * * * /home/deploy/n8n-compose/backup.sh

Store backups outside the server as well. A backup on the same disk will not help if that disk fails.

Step 14: Updating n8n

cd ~/n8n-compose
docker compose pull
docker compose down
docker compose up -d

Because the image is pinned to n8nio//n8n2.0, pull fetches the latest release within that major version rather than jumping to a potentially breaking one. 

Troubleshooting

ProblemLikely CauseSolution
Webhooks aren’t firingWEBHOOK_URL doesn’t exactly match your public HTTPS domain, or containers weren’t restarted after changing .env.Verify WEBHOOK_URL (including the trailing slash), save the changes, and restart the containers.
“Could not decrypt” credential errorsThe encryption key changed or n8n started without N8N_ENCRYPTION_KEY.Restore the original encryption key in .env and restart. If the original key is lost, all credentials must be recreated.
Container keeps restartingThe VPS is running out of memory, especially on a 1GB instance.Check resource usage with docker stats, then upgrade the VPS RAM or reduce concurrent workflow executions.
Database connection errorsDB_POSTGRESDB_HOST or POSTGRES_PASSWORD doesn’t match the PostgreSQL configuration.Ensure DB_POSTGRESDB_HOST=postgres matches the Compose service name and that the password matches the one used when PostgreSQL was first initialized.
SSL certificate fails to issueDNS hasn’t propagated or port 80 isn’t publicly accessible.Confirm DNS with dig n8n.yourdomain.com, ensure port 80 is open, then rerun Certbot.

Your n8n Instance Is Ready

Your self-hosted n8n setup is now running with HTTPS, PostgreSQL storage, controlled updates, and scheduled backups. The infrastructure is in place, so you can focus on creating workflows and automations instead of managing the underlying stack.

Need a reliable hosting environment for your n8n deployment? Check managed n8n hosting options with Truehost n8n Hosting.

How to Run n8n on a VPS FAQs

How much RAM do I need to run n8n on a VPS?

2GB RAM is a good starting point for running n8n with PostgreSQL. While 1GB can handle light workloads, it often runs out of memory. For production use or larger workflows, 4GB or more is recommended.

Should I use Docker or npm to install n8n?

Docker is the recommended option for most self-hosted setups. It’s easier to update, back up, and manage. An npm installation works too, but you’ll need to manage Node.js, dependencies, and the n8n service yourself.

Is PostgreSQL better than SQLite for self-hosted n8n?

Yes, for production. SQLite is fine for testing or small personal projects, but PostgreSQL handles multiple workflows more reliably and is the database recommended by n8n for production deployments.

Why are my n8n webhooks not working?

The most common cause is an incorrect WEBHOOK_URL. Make sure it exactly matches your public HTTPS domain. Also check that N8N_PROXY_HOPS is set correctly if you’re using Nginx or another reverse proxy.

How do I update n8n without losing my workflows?

Run docker compose pull, then restart your containers. Your workflows and credentials remain safe because they’re stored in the database and persistent volumes, not inside the n8n container. Always create a backup before updating.

Is self-hosting n8n on a VPS worth it?

If you run many workflows or want full control over your data, yes. Self-hosting removes usage limits and recurring execution costs, but you’ll be responsible for updates, backups, and server maintenance.

How do I scale n8n when one VPS is no longer enough?

Start by upgrading your VPS with more CPU and RAM. If that’s no longer enough, use n8n’s queue mode with Redis to spread workflow executions across multiple worker instances.

Irine Wayua
Author

Irine Wayua

SEO WRITER Nairobi, Kenya

Dedicated SEO writer and content development professional with a strong focus on producing high-quality, data-driven, and search-optimized material. Committed to delivering clarity, accuracy, and measurable value through well-structured digital content.

View All Posts