Learn how to install n8n fast and reliably. This step-by-step guide covers the recommended Docker Compose setup (with and without PostgreSQL), a quick Docker run one-liner, and a local Node.js method. You’ll also get best practices for SSL, environment variables, and updates so your n8n instance stays secure and stable.
Quick answer
- Best for production: Docker Compose behind a reverse proxy with SSL.
- Best for testing: Docker run one-liner or Node.js (npm) install locally.
- Must-set env vars:
N8N_HOST,N8N_PORT,N8N_PROTOCOL,WEBHOOK_URL, and a strongN8N_ENCRYPTION_KEY.
Prerequisites
- A server or VM (Ubuntu 22.04+ recommended) or a local machine (macOS/Windows/Linux)
- Docker and Docker Compose (or Docker Desktop)
- A domain/subdomain for production (e.g.,
automation.example.com) - Optional but recommended: reverse proxy (Nginx, Caddy, or Traefik) with SSL
Method 1: Install n8n with Docker Compose (recommended)
This setup is durable, easy to update, and production-friendly. You can use the built-in SQLite database (simpler) or PostgreSQL (more scalable and robust).
Option A: Simple Docker Compose (SQLite)
Create a project folder and a minimal docker-compose.yml:
mkdir -p ~/n8n && cd ~/n8n
cat > docker-compose.yml <<'YAML'
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_HOST=automation.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://automation.example.com/
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=UTC
volumes:
- ./n8n_data:/home/node/.n8n
YAML
Set a strong encryption key and start:
export N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
docker compose up -d
Point your reverse proxy at http://SERVER_IP:5678 (see SSL section below). Visit your domain to complete the first-user setup.
Option B: Docker Compose with PostgreSQL (production)
For teams or heavier workloads, use PostgreSQL. Create docker-compose.yml:
mkdir -p ~/n8n && cd ~/n8n
cat > docker-compose.yml <<'YAML'
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
depends_on:
- postgres
ports:
- "5678:5678"
environment:
- N8N_HOST=automation.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://automation.example.com/
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=UTC
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- ./n8n_data:/home/node/.n8n
postgres:
image: postgres:15
container_name: n8n_postgres
restart: unless-stopped
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=n8n
volumes:
- ./pg_data:/var/lib/postgresql/data
YAML
Set secrets and start:
export N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
export POSTGRES_PASSWORD=$(openssl rand -hex 24)
docker compose up -d
Add SSL with Nginx (example)
Point DNS for automation.example.com to your server. Then install Nginx and Certbot, and proxy to n8n:
sudo apt update && sudo apt install -y nginx certbot python3-certbot-nginx
sudo tee /etc/nginx/sites-available/n8n > /dev/null <<'NGINX'
server {
server_name automation.example.com;
location / {
proxy_pass http://127.0.0.1:5678;
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;
}
}
NGINX
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d automation.example.com --redirect
Update your Docker env to reflect HTTPS:
N8N_HOST=automation.example.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://automation.example.com/
Restart n8n after changes:
docker compose down && docker compose up -d
Method 2: Quick test with Docker run
Good for local testing. Not ideal for production (no volumes, no SSL by default):
docker run -it --rm \
-p 5678:5678 \
-e N8N_HOST=localhost \
-e N8N_PORT=5678 \
-e N8N_PROTOCOL=http \
-e WEBHOOK_URL=http://localhost:5678/ \
-e N8N_ENCRYPTION_KEY=$(openssl rand -hex 32) \
n8nio/n8n:latest
Method 3: Install n8n with Node.js (npm)
Use for local exploration. For production, prefer Docker. Requires Node.js 18+ and npm:
# install Node.js 18+ (example using nvm)
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.nvm/nvm.sh
nvm install --lts
# install and run n8n
npm install -g n8n
n8n start
Open http://localhost:5678 in your browser.
Post-install best practices
- Security: keep
N8N_ENCRYPTION_KEYsecret; enable HTTPS; restrict the editor to trusted networks if needed. - Backups: back up
./n8n_data(and PostgreSQL if used). - Updates: periodically
docker compose pullthenup -dto update. - Environment: set
GENERIC_TIMEZONEcorrectly; configure email (SMTP) for alerts if required. - Scaling: move to PostgreSQL and consider externalizing Redis/Queue if your workload grows.
Troubleshooting
- Container won’t start: check logs with
docker compose logs -f. - 404 on webhooks: ensure
WEBHOOK_URLmatches your public URL and protocol. - Mixed content/redirect loops: verify Nginx proxy headers and that
N8N_PROTOCOL=https. - Permissions on volumes: ensure the Docker user can write to
./n8n_data.
FAQs
Is Docker mandatory for n8n?
No, but it’s the easiest and most reliable way to run n8n in production. You can also install via Node.js for local use.
Which database should I use?
SQLite is fine for single-user or light workloads. Use PostgreSQL for teams, reliability, and easier scaling.
How do I update n8n?
With Docker: docker compose pull followed by docker compose up -d. Always back up data first.
Can I put n8n behind Cloudflare or a tunnel?
Yes. Ensure your public URL (e.g., Cloudflare proxy or tunnel hostname) is set in WEBHOOK_URL and N8N_PROTOCOL is correct.
That’s it! You now have a secure, updatable n8n install. If you want, I can customize a production-ready docker-compose.yml for your domain and reverse proxy of choice.