自托管生产部署
第 18 章:自托管生产部署
从开发环境到生产环境,是一次质的跨越。开发时你可以忽略备份、忽略 HTTPS、忽略多用户权限;但生产环境容不得这些疏漏——一次意外重启可能导致所有工作流丢失,一个裸 HTTP 请求可能泄露所有 API 凭证。本章提供一套经过验证的 n8n 生产部署方案:使用 Docker Compose 编排 n8n + PostgreSQL + Redis,配合 Nginx 做反向代理和 SSL 终止,并详细讲解密钥管理、备份策略和零停机升级流程。
18.1 生产环境架构概览
推荐的生产架构由四个组件构成:
- n8n:主服务,负责工作流执行和 Web UI
- PostgreSQL 16:替代默认的 SQLite,存储工作流定义、执行记录、用户数据
- Redis 7:在 Queue 模式下作为消息队列(本章先配置好,第20章启用 Queue 模式)
- Nginx:反向代理,处理 SSL 终止、域名绑定、WebSocket 代理
为什么要换掉 SQLite? SQLite 是单文件数据库,并发写入能力极弱。当多个工作流同时执行时,SQLite 的锁竞争会导致执行失败率显著上升。PostgreSQL 支持真正的并发,且有成熟的备份工具链,是生产环境的唯一正确选择。
18.2 Docker Compose 完整配置
# docker-compose.yml(生产版)
version: '3.8'
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- n8n_net
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- n8n_net
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
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_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://${N8N_HOST}/
- EXECUTIONS_MODE=regular
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
- QUEUE_BULL_REDIS_PASSWORD=${REDIS_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
ports:
- "127.0.0.1:5678:5678"
networks:
- n8n_net
volumes:
postgres_data:
redis_data:
n8n_data:
networks:
n8n_net:
driver: bridge
注意端口绑定: n8n 端口绑定为
127.0.0.1:5678:5678而非0.0.0.0:5678:5678。这确保 n8n 只接受来自本机(Nginx)的请求,外网无法直接访问 5678 端口,是基本的安全要求。
18.3 环境变量安全管理
所有敏感配置(密码、密钥)通过 .env 文件注入,绝对不要硬编码在 compose 文件中。.env 文件应加入 .gitignore。
# /opt/n8n/.env
# 此文件不要提交到 Git!
POSTGRES_DB=n8n_prod
POSTGRES_USER=n8n_user
POSTGRES_PASSWORD=# 使用 openssl rand -base64 32 生成强密码
REDIS_PASSWORD=# 使用 openssl rand -base64 24 生成
# n8n 加密密钥,用于加密所有凭证
# 生成命令: openssl rand -hex 32
# 警告: 一旦设置不能更改,否则所有保存的凭证将失效
N8N_ENCRYPTION_KEY=your-32-char-hex-string-here
N8N_HOST=n8n.yourdomain.com
18.4 Nginx 反向代理配置(含 SSL)
使用 Nginx 作为 n8n 的前端代理,处理 HTTPS 和 WebSocket 连接(n8n 的实时执行日志依赖 WebSocket)。
# /etc/nginx/sites-available/n8n.conf
server {
listen 80;
server_name n8n.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
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;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 64M;
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;
# WebSocket support (required for n8n execution logs)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
}
}
申请 Let's Encrypt 证书
# 安装 Certbot
apt install certbot python3-certbot-nginx -y
# 申请证书(自动修改 Nginx 配置)
certbot --nginx -d n8n.yourdomain.com
# 验证自动续期
certbot renew --dry-run
18.5 数据备份策略
n8n 的核心数据有两类:PostgreSQL 数据库(工作流定义、执行记录)和 n8n_data 数据卷(凭证加密文件、二进制数据)。两类都需要定期备份。
#!/bin/bash
# /opt/n8n/backup.sh
# 添加到 crontab: 0 3 * * * /opt/n8n/backup.sh
set -e
BACKUP_DIR=/opt/n8n/backups
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
mkdir -p $BACKUP_DIR
# 备份 PostgreSQL
docker exec n8n-postgres-1 pg_dump \
-U ${POSTGRES_USER} ${POSTGRES_DB} \
| gzip > $BACKUP_DIR/pg_backup_$TIMESTAMP.sql.gz
# 备份 n8n 数据卷(凭证和配置)
docker run --rm \
-v n8n_n8n_data:/data \
-v $BACKUP_DIR:/backup \
alpine tar czf /backup/n8n_data_$TIMESTAMP.tar.gz -C /data .
# 删除超过 30 天的旧备份
find $BACKUP_DIR -name "*.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: $TIMESTAMP"
18.6 版本升级:零停机升级步骤
n8n 的升级流程需要特别注意:数据库迁移是自动执行的,但升级过程中会有短暂的服务中断(通常 10-30 秒)。
- 备份:升级前务必执行一次完整备份(参见上节脚本)
- 查看 Changelog:访问 n8n GitHub Releases 页面,确认是否有 Breaking Changes
- 拉取新镜像:
docker compose pull n8n - 重启服务:
docker compose up -d n8n(compose 会自动用新镜像替换旧容器) - 观察日志:
docker compose logs -f n8n,确认数据库迁移完成,无报错 - 验证:登录 UI,运行一个测试工作流,确认执行正常
锁定版本: 不建议在生产环境使用
latest标签。改用具体版本号如n8nio/n8n:1.45.0,升级时手动更新版本号,确保每次升级都是有意为之、经过测试的。
18.7 用户与权限管理
n8n 从 v0.219 开始支持多用户(Member 角色)。生产环境中,强烈建议开启以下设置:
- 禁用自主注册:设置
N8N_USER_MANAGEMENT_DISABLED=false(默认)并通过管理员邀请的方式添加成员 - 角色分级:Owner(可管理所有设置)、Admin(可管理用户)、Member(只能操作自己的工作流)
- LDAP/SAML 集成:企业版功能,支持对接 Azure AD、Okta 等 SSO 系统,实现统一身份认证
# 关键安全环境变量
# 强制关闭 n8n 首次运行的"跳过认证"模式
N8N_SKIP_WEBHOOK_DEREGISTRATION_SHUTDOWN=false
# 限制工作流只能被拥有者访问(默认关闭)
N8N_WORKFLOW_OWNER_BLOCK=true
# 禁止用户从外部 URL 导入工作流(防止供应链攻击)
N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES=true
# 设置执行数据保留天数(避免磁盘无限增长)
EXECUTIONS_DATA_MAX_AGE=30
EXECUTIONS_DATA_PRUNE=true