Back to Blog
n8n

How to Self-Host n8n on Ubuntu 22.04: A Practical Production Setup

November 10, 2025·6 min read·Amit El
How to Self-Host n8n on Ubuntu 22.04: A Practical Production Setup

Introduction

Self-hosting n8n on a Linux server gives you full control over where your workflows run, how data stays on your network, and how you scale. If you’re building automation for a small team or a SaaS product, a self-hosted instance can be cheaper in the long run and easier to audit than a managed service. Ubuntu 22.04 LTS is a stable, long-term choice for production workloads, with solid Docker support and a predictable update cadence. This guide walks you through a practical, production-ready setup: running n8n in Docker with PostgreSQL as the persistent store, protected behind an Nginx reverse proxy, and secured with Let's Encrypt SSL. It also covers data-backed backups, security basics, and maintenance tips so you can operate reliably. We’ll cover: - Preparing the host and prerequisites - Running n8n with PostgreSQL in Docker - Setting up a reverse proxy and TLS - Data persistence and backups - Basic security hardening - Maintenance, upgrades, and common issues If you’re evaluating hosting options, this article also notes when a managed option (like FlowEngine or n8n Cloud) might be preferable to self-hosting.

Prerequisites

Before you start, ensure you have a clean Ubuntu 22.04 machine with root or sudo access. You’ll also want a domain name pointing at the server and a static IP. A minimal server spec for a basic n8n instance with PostgreSQL is:

  • 2 CPU cores
  • 4 GB RAM (8 GB recommended for production)
  • 20 GB SSD for the OS and containers, plus PostgreSQL data storage
  • Unrestricted outbound network access (for updates and Docker images)

Networking notes: - Reserve port 80 and 443 for the reverse proxy/TLS. - Your n8n API will run behind the proxy on port 8080 inside the container.

Install Docker and Docker Compose

Docker is the runtime you’ll use for n8n and PostgreSQL. Docker Compose makes it easy to manage multiple containers as a single stack.

sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER

# Install Docker Compose (v2)
sudo apt-get install -y docker-compose

Log out and back in, or run newgrp docker to apply group changes. Verify with:

docker --version
docker compose version

Create a Docker Compose stack for n8n and PostgreSQL

Use a dedicated directory for the stack and create a docker-compose.yml that defines two services: n8n and a PostgreSQL database. Production workloads should use a separate volume for data persistence.

version: '3.8'
services:
  postgres:
    image: postgres:13
    restart: unless-stopped
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: your-secure-password
      POSTGRES_DB: n8n
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - '5432:5432'

  n8n:
    image: n8nio/n8n:latest
    restart: unless-stopped
    depends_on:
      - postgres
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=your-secure-password
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=change-me
      - N8N_HOST=0.0.0.0
      - N8N_PORT=8080
      - N8N_WORKFLOW_EXECUTION_MODE=queue
    ports:
      - '8080:8080'
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  pgdata:
  n8n_data:

Save this as docker-compose.yml in a new directory and start the stack:

docker compose up -d --pull

First run may take a minute as images download. After it comes up, n8n will be accessible at http://your-server-ip:8080, though we’ll route it through a reverse proxy and TLS in the next steps.

Open the basics: environment, authentication, and data

Security and reliability hinge on sensible defaults. In production, don’t run n8n with the default SQLite database; PostgreSQL provides better durability and concurrent access. It’s also a good time to enable basic authentication in front of the app, so you’re not exposing the UI directly to the internet.

# Example .env (optional for docker-compose if you want to separate config)
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=your-secure-password
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=change-me
N8N_HOST=0.0.0.0
N8N_PORT=8080

Note: If you keep the password in Docker Compose, protect the file with proper filesystem permissions and consider using Docker secrets in a more advanced setup.

Set up a reverse proxy with TLS

A reverse proxy handles TLS termination, enforces HTTP to HTTPS redirects, and exposes a stable public URL for your n8n instance. Nginx is a popular choice; Caddy is another option that can automate TLS with Let’s Encrypt. Here’s a minimal Nginx setup using a separate server block and a TLS certificate from Let’s Encrypt.

# Install Nginx
sudo apt-get install -y nginx

# Example Nginx server block (place in /etc/nginx/sites-available/n8n)
server {
  listen 80 default_server;
  server_name n8n.yourdomain.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  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;

  location / {
    proxy_pass http://localhost:8080;
    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;
  }
}

Obtain a TLS certificate with Certbot:

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

Reload Nginx after certificate issuance:

sudo systemctl reload nginx

SSL/TLS best practices and security

TLS is non-negotiable for a production UI. In addition to certs, consider: - Enforcing strong ciphers and TLS versions via Nginx config - Enabling HTTP Strict Transport Security (HSTS) for a period (e.g., 6 months) - Keeping your server packages up to date with security patches - Using a non-privileged user to run containers where possible

Data persistence and backups

PostgreSQL stores your n8n data. Ensure its data directory lives on a persistent volume that isn’t removed during container recreation. Backups are essential. A simple backup approach is to use pg_dump and store dumps on a separate backup disk or off-site.

# Example backup script (run on host)
TIMESTAMP=$(date +"%F-%H-%M-%S")
docker exec -t your_postgres_container pg_dump -U n8n n8n > /backups/n8n_$TIMESTAMP.sql

Automate backups with a cron job and consider off-site storage (e.g., S3-compatible storage) for resilience. If you’re running PostgreSQL in Docker, you can also use pgBackRest or similar tools for incremental backups.

Security hardening: basics you shouldn’t skip

  • Use N8N_BASIC_AUTH_ACTIVE and strong credentials for the UI.
  • Disable SSH password authentication and use SSH keys.
  • Keep Docker and the host OS patched with security updates.
  • Limit network exposure: only expose ports 80/443 and the internal ports needed by Docker.
  • Rotate credentials periodically and monitor access logs for unusual activity.

Maintenance, upgrades, and common issues

Plan for maintenance windows and test upgrades in a staging environment when possible. A typical upgrade path is to pull the latest images and re-create containers:

docker compose pull
docker compose down
docker compose up -d --remove-orphans

Common issues and quick checks:

  • Container restarts or OOM: allocate more memory, enable swap if appropriate, or reduce concurrent executions in n8n.
  • DNS or TLS issues: verify domain resolves to the server, reissue certs, ensure firewall allows 443.
  • PostgreSQL connection errors: ensure DB_HOST and credentials match; check docker-compose logs for details.

Performance and scaling tips

n8n’s performance depends on how many workflows run in parallel and how heavy each execution is. Practical tips:

  • Increase memory to 4–8 GB for typical mid-size teams; this reduces backpressure during bursts.
  • Enable queue-based execution (N8N_WORKFLOW_EXECUTION_MODE=queue) to smooth spikes if you’re using a shared CPU.
  • Place PostgreSQL on its own volume and consider a separate database server if your workflow load is heavy.
  • Run a small, dedicated worker pool if you’re doing long-running tasks or heavy IO.

Alternate hosting options and when to choose them

Self-hosting gives you control, but it also requires ongoing maintenance. If you want something hands-off, consider managed hosting options. Some common choices include:

  • n8n Cloud – official managed hosting from the n8n project.
  • FlowEngine – a managed hosting option that can run n8n instances with additional tooling.
  • Other VPS or PaaS providers like Railway, Render, or Heroku (for quick pilots, with caveats around cost and control).

Managed options can simplify updates and security patches, but you’ll trade off some control and potentially higher ongoing costs for teams with limited ops bandwidth. If you prefer a middle ground, you can run a self-hosted n8n with a lightweight automation layer on top and use FlowEngine or similar services as a management layer for backups, monitoring, and scaling.

For more on managed hosting choices, see the official documentation and vendor guides. If you’re evaluating options, a practical approach is to map your needs against features such as uptime, data residency, scaling elasticity, and total cost of ownership over 12–24 months.

Next steps and references

This guide shows a straightforward path to a production-ready n8n deployment on Ubuntu 22.04. You now have a PostgreSQL-backed container, a reverse proxy with TLS, and a basic security posture. From here, you can add Redis for cache and queuing, introduce rate limiting, or add backup automation that fits your policy. If you’d like a more managed approach, consider FlowEngine as a hosted option, or explore n8n Cloud for a fully managed experience. Whatever you choose, keep a procedure for upgrades and a tested backup plan.

References and further reading: - n8n documentation - Docker documentation - Docker Compose - Nginx documentation - Let's Encrypt - FlowEngine

n8nself-hostingubuntu-22.04dockerPostgreSQLnginxtlssecurity