第 18 章

自托管生产部署

第 18 章:自托管生产部署

从开发环境到生产环境,是一次质的跨越。开发时你可以忽略备份、忽略 HTTPS、忽略多用户权限;但生产环境容不得这些疏漏——一次意外重启可能导致所有工作流丢失,一个裸 HTTP 请求可能泄露所有 API 凭证。本章提供一套经过验证的 n8n 生产部署方案:使用 Docker Compose 编排 n8n + PostgreSQL + Redis,配合 Nginx 做反向代理和 SSL 终止,并详细讲解密钥管理、备份策略和零停机升级流程。

18.1 生产环境架构概览

推荐的生产架构由四个组件构成:

为什么要换掉 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 秒)。

  1. 备份:升级前务必执行一次完整备份(参见上节脚本)
  2. 查看 Changelog:访问 n8n GitHub Releases 页面,确认是否有 Breaking Changes
  3. 拉取新镜像docker compose pull n8n
  4. 重启服务docker compose up -d n8n(compose 会自动用新镜像替换旧容器)
  5. 观察日志docker compose logs -f n8n,确认数据库迁移完成,无报错
  6. 验证:登录 UI,运行一个测试工作流,确认执行正常

锁定版本: 不建议在生产环境使用 latest 标签。改用具体版本号如 n8nio/n8n:1.45.0,升级时手动更新版本号,确保每次升级都是有意为之、经过测试的。

18.7 用户与权限管理

n8n 从 v0.219 开始支持多用户(Member 角色)。生产环境中,强烈建议开启以下设置:

# 关键安全环境变量

# 强制关闭 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
本章评分
4.7  / 5  (11 评分)

💬 留言讨论