Deploy n8n with Docker Compose: Complete Setup Guide

2026.05.07
Technology
897 Words
Deploy n8n with Docker Compose: Complete Setup Guide

n8n Deployment: Docker Compose Setup

Part 1 of 3. Part 2: Kubernetes Deployment | Part 3: Configuration Deep Dive

I once watched a startup lose three days of sales leads because their Zapier integration hit a rate limit during a product launch. The webhook queue backed up, credentials expired silently, and nobody noticed until the CRM team asked why Monday’s leads never arrived. That single incident cost them more in lost revenue than a self-hosted automation platform would have cost to run for an entire year.

That is why I run n8n, an open-source workflow automation tool, on my own infrastructure. n8n gives you the visual, node-based workflow builder that tools like Zapier and Make offer, but with one critical difference: you control the data, the credentials, and the execution environment. In 2025, with AI Agent nodes, LLM integrations, and self-hosted LLM support, n8n has evolved from a simple automation tool into a legitimate platform for AI-powered orchestration.

In this guide, I will walk you through deploying n8n in two configurations: Docker Compose for single-node setups and Kubernetes for production workloads. I will cover webhook security, credential encryption, queue mode with Redis, a PostgreSQL backend, and how to wire up AI Agent nodes with your own LLMs.

What You Will Build

By the end of this guide, you will have:

  • A running n8n instance with a PostgreSQL database backend
  • Redis-backed queue mode for handling concurrent executions
  • Encrypted credential storage and secure webhook endpoints
  • An AI Agent workflow connected to a self-hosted LLM
  • Kubernetes manifests you can drop into a GitOps pipeline

Prerequisites

Before you start, make sure you have the following in place.

RequirementMinimumRecommendedVerify Command
OSUbuntu 22.04Ubuntu 24.04 LTSlsb_release -a
CPU2 cores4+ coresnproc
RAM4 GB8 GBfree -h
Docker24.027.0+docker --version
Docker Compose2.202.27+docker compose version
Kubernetes1.281.30+ (optional)kubectl version
GPUNoneNVIDIA A10G (for local LLMs)nvidia-smi

Version note: These instructions apply to n8n 1.50+. If you are running an older version, some environment variable names may differ.

Architecture Overview

n8n can run in two execution modes: regular (everything in one process) and queue (webhooks and workers separated). For anything beyond personal experimentation, I strongly recommend queue mode.

In queue mode, the architecture looks like this:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client │────▢│ n8n Web │────▢│ PostgreSQL β”‚
β”‚ (Browser) β”‚ β”‚ (Main) β”‚ β”‚ (Database) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β–Ό β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Worker 1β”‚ β”‚ Worker 2β”‚ β”‚ Worker Nβ”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Redis β”‚
β”‚ (Queue) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The main process handles the web UI, webhook ingress, and API requests. Workers pick up execution jobs from Redis. PostgreSQL persists workflows, executions, and credentials. This separation means you can scale workers independently of the web tier, and a crashing workflow will not take down the UI.

Docker Compose Deployment

Docker Compose is the fastest path to a working n8n instance. I use this setup for homelab environments, staging, and smaller production workloads under moderate concurrency.

Step 1: Create the Project Directory

Terminal window
mkdir -p ~/n8n-deployment/{postgres,redis}
cd ~/n8n-deployment

Step 2: Write the Docker Compose File

Create docker-compose.yml with the following configuration. I have annotated each section so you know what it does.

docker-compose.yml
# Production-ready n8n with PostgreSQL, Redis, and encryption
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- ./postgres/data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n"]
interval: 10s
timeout: 5s
retries: 5
networks:
- n8n-network
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- ./redis/data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- n8n-network
n8n:
image: n8nio/n8n:1.50
restart: unless-stopped
environment:
# Database
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
# Queue mode
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: redis
QUEUE_BULL_REDIS_PORT: 6379
# Security
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
WEBHOOK_URL: ${WEBHOOK_URL}
# General
GENERIC_TIMEZONE: UTC
TZ: UTC
N8N_BASIC_AUTH_ACTIVE: "true"
N8N_BASIC_AUTH_USER: ${N8N_BASIC_AUTH_USER}
N8N_BASIC_AUTH_PASSWORD: ${N8N_BASIC_AUTH_PASSWORD}
ports:
- "5678:5678"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./n8n-data:/home/node/.n8n
networks:
- n8n-network
# Optional: Add workers for concurrent execution
n8n-worker:
image: n8nio/n8n:1.50
restart: unless-stopped
command: worker
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
QUEUE_BULL_REDIS_HOST: redis
QUEUE_BULL_REDIS_PORT: 6379
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
GENERIC_TIMEZONE: UTC
depends_on:
- redis
- postgres
deploy:
replicas: 2
networks:
- n8n-network
networks:
n8n-network:
driver: bridge

Step 3: Create the Environment File

Create .env in the same directory. Never commit this file to Git.

Terminal window
# .env: keep this secret
POSTGRES_PASSWORD=$(openssl rand -base64 32)
N8N_ENCRYPTION_KEY=$(openssl rand -base64 32)
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=$(openssl rand -base64 24)
WEBHOOK_URL=https://n8n.yourdomain.com/

Generate secure values:

Terminal window
touch .env
chmod 600 .env
cat <<EOF > .env
POSTGRES_PASSWORD=$(openssl rand -base64 32)
N8N_ENCRYPTION_KEY=$(openssl rand -base64 32)
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=$(openssl rand -base64 24)
WEBHOOK_URL=https://n8n.yourdomain.com/
EOF

Step 4: Start the Stack

Terminal window
docker compose up -d

Wait about 30 seconds for the database migrations to run, then verify:

Terminal window
docker compose ps
# All services should show "healthy" or "running"
docker compose logs n8n | grep "Editor is now accessible"
# Expected output: "Editor is now accessible via: http://localhost:5678/"

Navigate to http://localhost:5678 and complete the initial setup wizard.

Common Issues

  • Port 5678 already in use: Change the host port mapping to 8080:5678 in docker-compose.yml.
  • Permission denied on volumes: n8n runs as user node (UID 1000). Ensure the host directories are writable: sudo chown -R 1000:1000 ./n8n-data.

FAQ

What is n8n and how does it differ from Zapier?

n8n is an open-source workflow automation platform. Unlike Zapier, you self-host it, which means you own your data, your credentials never leave your infrastructure, and you are not bound by usage tiers or rate limits. n8n uses a visual node-based editor that I find more flexible for building complex multi-step automation pipelines.

Do I need queue mode for a small deployment?

For a handful of workflows running occasionally, regular mode works fine. I switch to queue mode as soon as I have more than 5 active workflows or any workflow that uses webhooks in production. Queue mode prevents webhook timeouts by decoupling request acceptance from execution.

Can I run n8n with SQLite instead of PostgreSQL?

Yes, n8n ships with SQLite by default. Do not use it in production. SQLite does not handle concurrent writes. I learned this the hard way when a busy webhook corrupted the database during a traffic spike. PostgreSQL handles concurrent connections properly and makes backups trivial with pg_dump.

How do I secure the n8n editor UI?

Enable basic authentication by setting N8N_BASIC_AUTH_ACTIVE=true with a strong password. I also put n8n behind a reverse proxy with TLS and restrict access by IP range where possible. Never expose the editor to the public internet without authentication.

What happens if the PostgreSQL database goes down?

n8n stops processing workflows until the database recovers. Workers will queue jobs in Redis memory, but once Redis hits its maxmemory limit, it starts evicting old jobs. This is why I run PostgreSQL with a replica and automated backups.

Can I connect n8n to Ollama or vLLM for local AI?

Yes. Both Ollama and vLLM expose OpenAI-compatible APIs. Point the HTTP Request node or the AI Agent node’s chat model at your local LLM service URL. I cover this setup in detail in Part 2.


Parts in this series: Part 2: Kubernetes Deployment β†’ | Part 3: Configuration Deep Dive β†’

# N8N # ai-automation # workflow # docker # Kubernetes # redis # postgresql # deployment # self-hosted