AutomateNexus

Technical guide · n8n

The self-hosted n8n setup guide.

The exact step-by-step process we use to deploy production-ready n8n instances for clients: VPS, Docker Compose with PostgreSQL, SSL, automated backups, and a sane update routine. Full control of your automation infrastructure, in under 30 minutes.

500+

Deployments

<30 min

Setup time

98%

Success rate

$20/mo

Typical infra cost

Why self-host

4 reasons to run it yourself.

n8n Cloud starts at $24/mo —
fine until volume or compliance says no.

01

Zero per-execution fees

A $20/month VPS replaces the $200–$600 monthly bill that the same volume costs on per-task platforms. The workflow count stops mattering.

02

Data sovereignty

Customer records, credentials, and webhook payloads never leave infrastructure you control — the requirement that decides this for healthcare, finance, and government work.

03

No vendor ceiling

Fair-code license, custom nodes in TypeScript, JavaScript and Python code nodes. When the platform lacks a connector, you write one instead of waiting.

04

First-class AI tooling

LLM nodes for Anthropic, OpenAI, and Google, vector store connectors, and agent orchestration — self-hosted, with your own API keys.

Requirements

What you need before step 01.

Server
2 vCPU · 4 GB RAM · 40 GB SSD — Ubuntu 24.04 LTS (~$20/mo)
Domain
One subdomain, e.g. n8n.yourdomain.com, with DNS you control
Skills
Comfortable in a Linux shell; basic Docker familiarity helps
Time
About 30 minutes, end to end

The deployment · 7 steps

From blank server to production.

Copy-paste ready. Replace
yourdomain.com throughout.

01

Provision the VPS

Any provider works — Hetzner, DigitalOcean, AWS Lightsail. Start with 2 vCPU / 4 GB RAM / 40 GB SSD running Ubuntu 24.04 LTS; that handles tens of thousands of executions a month for roughly $20. Point a DNS A record (e.g. n8n.yourdomain.com) at the server, then harden the basics.

# as root, first login
adduser n8nadmin && usermod -aG sudo n8nadmin
ufw allow OpenSSH && ufw allow 80,443/tcp && ufw enable

# disable root + password SSH login
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

02

Install Docker

Docker plus the Compose plugin is the entire runtime. One script, official source.

curl -fsSL https://get.docker.com | sh
usermod -aG docker n8nadmin
docker --version && docker compose version

03

Compose n8n + PostgreSQL

SQLite is fine for testing; production gets PostgreSQL. Create /opt/n8n/docker-compose.yml with two services and named volumes so data survives container replacement.

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

  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
      N8N_HOST: n8n.yourdomain.com
      N8N_PROTOCOL: https
      WEBHOOK_URL: https://n8n.yourdomain.com/
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      GENERIC_TIMEZONE: America/Los_Angeles
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  pg_data:
  n8n_data:

04

Set secrets, then launch

Secrets live in an .env file next to the compose file — never in the YAML. The encryption key protects every stored credential; lose it and every saved credential is unrecoverable. Back it up somewhere that is not this server.

cd /opt/n8n
cat > .env << 'EOF'
POSTGRES_PASSWORD=$(openssl rand -hex 24)
N8N_ENCRYPTION_KEY=$(openssl rand -hex 24)
EOF
chmod 600 .env

docker compose up -d
docker compose logs -f n8n   # wait for "Editor is now accessible"

05

SSL with a reverse proxy

n8n listens on localhost only; Caddy terminates TLS in front of it and renews Let's Encrypt certificates automatically. Two lines of config — this is why we prefer it over nginx + certbot for single-app servers.

apt install -y caddy

# /etc/caddy/Caddyfile
n8n.yourdomain.com {
    reverse_proxy 127.0.0.1:5678
}

systemctl reload caddy
# https://n8n.yourdomain.com now serves the editor — create the owner account immediately

06

Automated backups

Three things to back up: the Postgres database, the n8n data volume, and the .env file. Nightly cron, 14-day retention, and — this part everyone skips — restore it once to prove it works.

# /opt/n8n/backup.sh
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%F)
BACKUP_DIR=/opt/n8n/backups
mkdir -p "$BACKUP_DIR"
docker compose -f /opt/n8n/docker-compose.yml exec -T postgres \
  pg_dump -U n8n n8n | gzip > "$BACKUP_DIR/n8n-db-$STAMP.sql.gz"
docker run --rm -v n8n_n8n_data:/data -v "$BACKUP_DIR":/backup alpine \
  tar czf "/backup/n8n-data-$STAMP.tar.gz" -C /data .
find "$BACKUP_DIR" -mtime +14 -delete

# install: chmod +x backup.sh, then
# crontab -e → 0 3 * * * /opt/n8n/backup.sh
# ship the backups off-box: rclone, S3, or Borg

07

Updating

n8n releases weekly. Update on your schedule, not latest-tag roulette: read the release notes, back up first, then pull and restart. Pin a version tag if you need change control.

cd /opt/n8n
./backup.sh                  # always before updating
docker compose pull
docker compose up -d         # recreates with the new image
docker image prune -f
/ 7-STEP DEPLOY/ FIG. 01

Field notes

The 4 mistakes we get called about.

Lost encryption key

N8N_ENCRYPTION_KEY not backed up off-server. Every stored credential becomes unrecoverable. Save it in your password manager today.

Webhooks return 404

WEBHOOK_URL missing or still http://. Set it to the public https URL and recreate the container.

SQLite in production

Works until the first big execution log. Migrate to PostgreSQL before go-live, not after the corruption.

Untested backups

A backup script that has never been restored is a hope, not a backup. Do one restore drill per quarter.

When to hire us instead

DIY is real. So is 2 a.m. pager duty.

This guide gets a competent admin to production. Hire us when the instance needs high availability, security hardening for compliance, custom nodes, or when the person who would maintain it already has a full-time job. We deploy on your infrastructure, document everything, and hand over the keys — you own it either way.

Deployed on your cloud or on-prem.

Hardening, HA, monitoring included.

Knowledge transfer, not lock-in.

/ DONE-FOR-YOU/ FIG. 02

Keep reading

Where we go from here

Want it running by Friday?

Standard deployment covers installation on your cloud provider, domain and SSL, database setup, security configuration, documentation, and a month of support. Enterprise adds HA, hardening, and custom nodes.

No subscription.

No lock-in.

No surprise invoices.

/ START HERE/ FIG. 14