Table of Contents
What you will read?
- 1 Update Debian 12.11 and install essentials
- 2 Create a dedicated n8n user
- 3 Install Docker Engine
- 4 Prepare project directories
- 5 Set environment variables (.env)
- 6 Create docker-compose.yml
- 7 Start containers and verify
- 8 Configure UFW firewall
- 9 Optional: Nginx reverse proxy with HTTPS
- 10 Create admin and secure access
- 11 Backup and upgrade safely
Deploy n8n on Debian 12.11 fast and secure with Docker, Postgres, and optional HTTPS. This step-by-step setup focuses on persistence, clean upgrades, and minimal downtime. Expect a production-ready layout that fits small teams and scales. Use a domain for SSL and keep ports locked down for safety.
Update Debian 12.11 and install essentials
Refresh repositories, patch the system, and install basic tools required for Docker and networking.
sudo apt update
sudo apt -y upgrade
sudo apt -y install ca-certificates curl gnupg lsb-release ufw
Create a dedicated n8n user
Run n8n under a non-root account for better isolation and simpler file permissions.
sudo adduser --disabled-password --gecos "" n8n
sudo usermod -aG sudo n8n
sudo su - n8n
Install Docker Engine
Use the official Docker repository for the latest stable Docker and Compose plugin.
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt update
sudo apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo sudo usermod -aG docker $USER
newgrp docker
docker --version
docker compose version
Prepare project directories
Create a clean folder structure for persistent data and configuration.
mkdir -p ~/n8n/.n8n
mkdir -p ~/n8n/postgres
cd ~/n8n
Set environment variables (.env)
Define database credentials, host, protocol, timezone, and an encryption key for sensitive data.
cat > .env << 'EOF'
POSTGRES_USER=n8n
POSTGRES_PASSWORD=ChangeMe_SuperStrong_123!
POSTGRES_DB=n8n
# Replace with your domain or server IP (use a domain if enabling HTTPS)
N8N_HOST=n8n.example.com
N8N_PORT=5678
N8N_PROTOCOL=http
WEBHOOK_URL=http://n8n.example.com/
TZ=UTC
# Generate a 32-byte hex key:
# openssl rand -hex 32
N8N_ENCRYPTION_KEY=REPLACE_WITH_HEX_KEY
EOF
Create docker-compose.yml
Run n8n with Postgres for reliability, with volumes for persistence and automatic restart.
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
postgres:
image: postgres:16
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- ./postgres:/var/lib/postgresql/data
restart: unless-stopped
n8n:
image: n8nio/n8n:latest
ports:
- "5678:5678"
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- N8N_HOST=${N8N_HOST}
- N8N_PORT=${N8N_PORT}
- N8N_PROTOCOL=${N8N_PROTOCOL}
- WEBHOOK_URL=${WEBHOOK_URL}
- GENERIC_TIMEZONE=${TZ}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
volumes:
- ./.n8n:/home/node/.n8n
depends_on:
- postgres
restart: unless-stopped
EOF
Start containers and verify
Launch the stack, inspect logs, and confirm the UI is reachable on port 5678.
docker compose up -d
docker compose ps
docker compose logs -f n8n
# Example output (trimmed)
NAME COMMAND STATE PORTS
n8n-n8n-1 "tini -- /docker-ent…" Up 0.0.0.0:5678->5678/tcp
n8n-postgres-1 "docker-entrypoint.s…" Up 5432/tcp
Configure UFW firewall
Allow SSH and n8n now; add HTTP/HTTPS if using a reverse proxy later.
sudo ufw allow OpenSSH
sudo ufw allow 5678/tcp
# If planning HTTPS with Nginx:
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status
Optional: Nginx reverse proxy with HTTPS
Place n8n behind Nginx and get a free Let’s Encrypt certificate. Update your DNS A record to the server IP first.
sudo apt -y install nginx certbot python3-certbot-nginx
sudo tee /etc/nginx/sites-available/n8n >/dev/null <<'EOF'
server {
server_name n8n.example.com;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
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 3600;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/n8n
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d n8n.example.com --redirect --email [email protected] --agree-tos -n
Switch n8n to HTTPS and restart the container to apply external URLs.
sed -i 's/^N8N_PROTOCOL=.*/N8N_PROTOCOL=https/' .env
sed -i 's#^WEBHOOK_URL=.*#WEBHOOK_URL=https://n8n.example.com/#' .env
docker compose up -d
Create admin and secure access
Open the n8n URL in a browser and finish the onboarding. Use a strong password. Restrict public signups if exposing to the internet.
# Optional environment hardening in .env (restart after changes):
# N8N_USER_MANAGEMENT_DISABLED=false
# N8N_DISABLE_PRODUCTION_MAIN_MENU=true
Backup and upgrade safely
Archive volumes regularly, then pull images and recreate containers to update.
cd ~/n8n
docker compose down
tar -czf n8n-backup-$(date +%F).tar.gz .n8n postgres docker-compose.yml .env
docker compose pull
docker compose up -d
docker compose exec n8n n8n --version
n8n now runs on Debian 12.11 with Docker, Postgres, persistence, and optional SSL. Keep the system patched, back up volumes, and update containers regularly.
