n8n

How to Install n8n on VPS

Automation used to be a luxury reserved for big enterprises with even bigger engineering budgets. Not anymore. n8n flips that script entirely. It’s a self-hostable, open-source workflow automation tool that lets you connect virtually any app, API, or database with a visual node-based editor — no proprietary lock-in, no per-task pricing surprises, and no ceiling on what you can build.

Running n8n on your own VPS puts you in the driver’s seat. Your credentials never leave your server. You control the upgrade schedule. And you can trigger workflows from internal services that a cloud-hosted SaaS couldn’t even reach. Think of it as Zapier’s ambitious cousin that actually lives on your infrastructure.

This guide walks you through a production-ready n8n installation on Ubuntu 22.04 or 24.04 LTS using Docker, Nginx as a reverse proxy, and a free Let’s Encrypt SSL certificate. By the end, you’ll have a fully secured, publicly accessible n8n instance running behind a proper domain.

What Is n8n?

n8n (pronounced “n-eight-n,” short for “nodemation”) is a workflow automation platform built around a visual, node-based canvas. Each node in a workflow represents an action — fetch data from an API, transform a JSON object, send a Slack message, write a row to a database. You chain those nodes together and n8n handles the execution.

What separates it from tools like Zapier or Make is the self-hosting model. The community edition is free and fully open-source under the Sustainable Use License. You run it wherever you want — a $6/month VPS works just fine — and your data never touches a third-party server. For teams handling sensitive customer data or internal tooling, that distinction matters enormously.

n8n ships with 400+ built-in integrations covering everything from Google Sheets and HubSpot to custom HTTP requests and webhooks. It also supports code nodes (JavaScript and Python) for logic that outgrows the visual editor. Basically: if you can describe an automation in plain English, n8n can probably execute it.

Prerequisites

Before you run your first command, make sure you’ve got the following in place.

RequirementMinimumRecommended
CPU1 vCPU2 vCPUs
RAM1 GB2 GB
Storage20 GB SSD40 GB SSD
OSUbuntu 22.04 LTSUbuntu 24.04 LTS
Domain nameRequired (for SSL)Required (for SSL)
Open ports22, 80, 44322, 80, 443
  • A non-root sudo user on your VPS
  • A domain (or subdomain) with an A record pointing to your server’s IP
  • Basic familiarity with the Linux command line

The minimum specs will handle light personal automation just fine. If you’re running dozens of concurrent workflows or processing large payloads, bump up to the recommended tier.

How to Install n8n on a VPS

Step 1: Update Your System

Start with a clean slate. Update the package index and upgrade any outdated packages before touching anything else.

sudo apt update && sudo apt upgrade -y

Reboot if the kernel updated — a quick sudo reboot followed by reconnecting via SSH is all it takes.

Step 2: Install Docker Engine

n8n ships as a Docker image so that’s your runtime. Ubuntu’s default repositories include Docker but often lag behind upstream releases. Install directly from Docker’s official repository instead.

First, install the dependencies and add Docker’s GPG key:

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

Add the Docker repository:

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

Now install Docker Engine and the Compose plugin:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Add your user to the docker group so you don’t need sudo for every Docker command:

sudo usermod -aG docker $USER
newgrp docker

Verify Docker is running:

docker --version
docker compose version

Step 3: Create the n8n Directory and Environment File

Organization matters here. Keep all of n8n’s configuration under a single directory so upgrades and backups are straightforward.

mkdir -p ~/n8n && cd ~/n8n

Create an environment file to store your configuration values. Using an .env file keeps secrets out of your Compose file and makes future edits painless.

nano .env

Paste in the following, replacing the placeholder values with your own:

# Domain your n8n instance will be accessible at
DOMAIN_NAME=n8n.yourdomain.com

# Timezone — find yours at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
GENERIC_TIMEZONE=America/New_York

# Encryption key for stored credentials (generate a strong random string)
N8N_ENCRYPTION_KEY=replace_with_a_long_random_string_here

# n8n webhook URL (must match your domain)
WEBHOOK_URL=https://n8n.yourdomain.com/

Generate a secure encryption key with this one-liner:

openssl rand -hex 32

Copy the output and paste it as the value of N8N_ENCRYPTION_KEY. This key encrypts every credential you store in n8n — losing it means losing access to those credentials, so back it up somewhere safe.

Step 4: Write the Docker Compose File

Create the Compose file in the same directory:

nano docker-compose.yml

Paste in the following configuration:

services:
  n8n:
    image: n8nio/n8n:1
    container_name: n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - WEBHOOK_URL=${WEBHOOK_URL}
      - N8N_HOST=${DOMAIN_NAME}
      - N8N_PROTOCOL=https
      - N8N_PORT=5678
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

A few things worth noting here. The port binding 127.0.0.1:5678:5678 intentionally restricts n8n to localhost only — Nginx will handle all public traffic. The named volume n8n_data persists your workflows, credentials, and execution history across container restarts. Pinning to the 1 major version tag rather than latest means you won’t accidentally pull a breaking major release during an unplanned restart. Verify the current stable major version at Docker Hub before deploying.

Step 5: Configure UFW Firewall

Lock down your server to allow only the traffic you actually need.

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

Confirm the rules look right:

sudo ufw status verbose

Port 5678 deliberately stays closed to the outside world. Everything routes through Nginx on 443.

Step 6: Install Nginx

Nginx acts as the reverse proxy sitting in front of n8n. It terminates SSL, handles WebSocket upgrades, and gives you a clean HTTPS endpoint.

sudo apt install -y nginx

Create a new Nginx server block for your n8n domain:

sudo nano /etc/nginx/sites-available/n8n

Paste in the following — replacing n8n.yourdomain.com with your actual domain:

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 900;
    }
}

The Upgrade and Connection headers are critical. n8n’s editor uses WebSockets for real-time updates and the workflow canvas won’t function properly without them.

Enable the site and test the Nginx config:

sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 7: Issue an SSL Certificate with Certbot

Your domain’s A record needs to resolve to your server’s IP before this step works. Give DNS propagation a few minutes if you just made the change.

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

Certbot will prompt you for an email address for renewal notices then automatically rewrite your Nginx config to serve HTTPS and redirect HTTP traffic. After it completes, verify the renewal timer is active:

sudo systemctl status certbot.timer

Let’s Encrypt certificates expire every 90 days but Certbot renews them automatically so you shouldn’t ever need to think about this again.

Step 8: Start n8n

With Nginx and SSL in place, bring n8n up:

cd ~/n8n
docker compose up -d

Watch the startup logs to confirm everything initializes cleanly:

docker compose logs -f n8n

You’re looking for a line that reads something like n8n ready on 0.0.0.0, port 5678. Once you see it press Ctrl+C to exit the log stream — n8n keeps running in the background.

Open your browser and navigate to https://n8n.yourdomain.com. n8n will greet you with an account setup screen on first launch. Create your owner account and you’re in.

Step 9: Enable n8n to Start on Boot

Docker itself starts on boot automatically but you need to confirm your container does too. The restart: unless-stopped policy in the Compose file handles this — if the host reboots, Docker will restart the n8n container automatically.

Verify Docker’s systemd service is enabled:

sudo systemctl is-enabled docker

The output should read enabled. If it doesn’t, run sudo systemctl enable docker.

How to Update n8n

Keeping n8n current is straightforward with Docker. The process pulls the latest image within your pinned major version, recreates the container, and leaves your volume data untouched.

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

That’s the entire update procedure. Docker Compose pulls the newer image tag, stops the old container, and launches a fresh one — your workflows and credentials survive because they live in the persistent n8n_data volume.

Before updating to a new major version (for example, from 1 to 2), check the n8n release notes for breaking changes. Update the image tag in your Compose file when you’re ready to make that jump.

To clean up old images after updating:

docker image prune -f

Troubleshooting

n8n Container Fails to Start

Pull up the container logs first — they almost always tell you exactly what went wrong:

docker compose logs n8n

Common culprits include a malformed .env file, a missing or empty N8N_ENCRYPTION_KEY, or a port conflict if something else is already listening on 5678. Check whether the port is occupied:

sudo ss -tlnp | grep 5678

If another process owns that port, stop it or change n8n’s host port mapping in the Compose file.

502 Bad Gateway in the Browser

This error means Nginx can’t reach the n8n backend. Run through this checklist:

  • Confirm n8n is actually running: docker compose ps
  • Verify the port binding is correct: docker compose port n8n 5678 should return 127.0.0.1:5678
  • Check the Nginx proxy_pass URL matches exactly: http://127.0.0.1:5678
  • Look at Nginx’s error log: sudo tail -50 /var/log/nginx/error.log

Webhook Triggers Aren’t Firing

n8n webhooks rely on the WEBHOOK_URL environment variable to construct the correct callback URL. If that value is wrong or missing, webhook nodes will generate URLs that point nowhere useful.

Double-check your .env file:

cat ~/n8n/.env

WEBHOOK_URL must end with a trailing slash and use https://. After fixing the value, restart the container:

docker compose down && docker compose up -d

Workflow Editor Not Loading or Canvas is Blank

A blank or unresponsive workflow canvas almost always points to a WebSocket problem. The editor communicates with the backend in real time over a WebSocket connection and if those requests are being dropped or rejected, the canvas simply won’t render.

Verify your Nginx config includes both WebSocket headers:

sudo grep -A2 "proxy_set_header Upgrade" /etc/nginx/sites-available/n8n

You should see both proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade";. If either is missing, add it and reload Nginx:

sudo nginx -t && sudo systemctl reload nginx

SSL Certificate Errors or HTTPS Not Working

If your browser reports a certificate error or you’re landing on the HTTP version of the site instead of HTTPS, start by checking whether Certbot completed successfully:

sudo certbot certificates

If no certificate appears for your domain, run the Certbot command again. The most frequent cause of failure is DNS propagation lag — the domain’s A record hasn’t resolved to your server IP yet at the time Certbot performs its ACME challenge. Confirm DNS resolution before retrying:

dig +short n8n.yourdomain.com

The output should show your server’s public IP. Once it does, Certbot should succeed without issue.

What to Build Next

With n8n up and running, you’ve got a surprisingly powerful automation platform sitting on your own infrastructure. A few directions worth exploring right away:

  • Connect your first integration. n8n includes native nodes for Gmail, Slack, Notion, GitHub, and hundreds more. Head to the Credentials section, add your API keys, and wire up a simple notification workflow to get comfortable with the canvas.
  • Set up automated backups. The n8n_data volume holds everything — workflows, credentials, execution logs. Schedule a cron job or a simple bash script to snapshot that volume daily and ship it to object storage.
  • Explore AI agent nodes. Recent versions of n8n ship with LangChain-powered AI agent nodes. You can build workflows that call an LLM, parse the response, and take action based on the output — all without writing a line of Python.
  • Add a PostgreSQL backend. The default SQLite storage works fine for personal use but if you’re running many concurrent workflows or storing large execution histories, migrating to PostgreSQL gives you better performance and proper transactional guarantees.

You’ve gone from a blank VPS to a fully functional, SSL-secured n8n instance ready to automate whatever you throw at it. The hard part is done. Now comes the fun part — figuring out all the tedious tasks you can hand off to your new automation server.