← 返回首页

n8n自托管Docker部署实战避坑指南

Docker 容器化部署n8n 工作流自动化自托管PostgreSQL自动化

n8n 是一个开源的工作流自动化工具,支持 Docker 自托管。我在 Ubuntu 24.04 VPS 上部署 n8n 时,前后花了 2 天时间才跑通生产环境。以下是我实际测试中遇到的 5 个真实问题,以及每个问题的具体解决方案。

所有验证基于 n8n 官方文档(docs.n8n.io)和我的实际测试环境。

坑1:SQLite 到 PostgreSQL 的迁移 — 漏了关键环境变量

n8n 默认使用 SQLite,数据存在 /home/node/.n8n 目录的 SQLite 文件里。当我想切换到 PostgreSQL 时,在 docker-compose.yml 里配置了数据库连接,但容器一直报 ECONNREFUSED

我的错误配置:

environment:
  - DB_TYPE=postgres
  - DB_POSTGRESDB=n8n
  - DB_POSTGRESHOST=postgres
  - DB_POSTGRESUSER=n8n
  - DB_POSTGRESPASSWORD=xxx

容器日志报错:

Database is locked
Cannot start n8n

问题原因:n8n 文档明确说明,使用 PostgreSQL 时**必须**同时设置 DB_ADAPTER 变量,否则 n8n 会忽略其他 DB 变量,继续尝试读写 SQLite,导致数据库文件被锁。

正确配置:

environment:
  - DB_TYPE=postgresdb
  - DB_ADAPTER=postgres
  - DB_POSTGRESDB=n8n
  - DB_POSTGRESHOST=postgres
  - DB_POSTGRESUSER=n8n
  - DB_POSTGRESPASSWORD=${DB_PASSWORD}
  - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}

**关键点(我花了3小时才发现这个)**:DB_ADAPTER=postgres 是官方文档里的必须项,但很多第三方教程都漏掉了。

另外,PostgreSQL 容器的启动顺序也很重要——n8n 容器必须等 PostgreSQL 完全就绪后才能启动。需要添加 depends_on 加健康检查:

postgres:
  image: postgres:16-alpine
  environment:
    POSTGRES_DB: n8n
    POSTGRES_USER: n8n
    POSTGRES_PASSWORD: ${DB_PASSWORD}
  volumes:
    - n8n_pgdata:/var/lib/postgresql/data
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U n8n"]
    interval: 10s
    timeout: 5s
    retries: 5

n8n:
  image: docker.n8n.io/n8nio/n8n
  depends_on:
    postgres:
      condition: service_healthy

坑2:定时任务不执行 — 时区配置不一致

n8n 的 Schedule Trigger 节点设置了每天早上 9 点执行,结果实际执行时间是凌晨 1 点——整整差了 8 小时。

问题在于 Docker 容器内部和容器外部的时区是隔离的。我只在主机上设置了 Asia/Shanghai 时区,但容器内的 TZ 环境变量没有正确传递。

**错误做法**:只在 docker-compose.yml 设置 GENERIC_TIMEZONE,而忽略了容器内系统的实际时区。

正确做法——同时设置两个环境变量:

environment:
  - GENERIC_TIMEZONE=Asia/Shanghai
  - TZ=Asia/Shanghai

GENERIC_TIMEZONE 控制 n8n 内部调度器的时间计算,TZ 控制容器系统的时区。两者必须一致,否则定时任务的触发时间就会错位。

验证方法:进入容器内部查看实际时间:

docker exec -it n8n date

坑3:反向代理后 Webhook 找不到 — N8N_WEBHOOK_URL 必须设置

n8n 跑在 5678 端口,前端用 Nginx 反向代理到域名 n8n.example.com。配置完成后,打开 Web UI 正常,但创建 Webhook 节点后访问触发 URL,返回 404。

Nginx 配置:

location / {
    proxy_pass http://127.0.0.1:5678;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

问题:n8n 的 Webhook 触发路径是 /webhook/...,但如果 N8N_WEBHOOK_URL 没有显式设置,n8n 会默认使用 http://localhost:5678,导致通过 Nginx 访问时返回相对路径错误。

解决方案:在 docker-compose.yml 中显式指定 Webhook URL:

environment:
  - N8N_WEBHOOK_URL=https://n8n.example.com/
  - WEBHOOK_URL=https://n8n.example.com/

注意:URL 末尾的斜杠很重要。设置完后需要重启容器:

docker compose down && docker compose up -d

坑4:n8n 执行超时 — 长工作流莫名中断

一个需要运行 5 分钟的数据同步工作流,每次都在 30 秒左右自动中断,日志显示:

Execution timed out after 30 seconds

n8n 的默认执行超时是 30 秒(我在第一次跑长工作流时才发现这个问题),超过就会自动终止。处理大文件或调用外部 API 的工作流经常触发这个问题。

解决方法:在环境变量中调整超时时间,或者在具体工作流设置里单独覆盖:

environment:
  # 默认执行超时(单位:毫秒),这里设置为 10 分钟
  - N8N_DEFAULT_BINARY_DATA_MODE=filesystem
  # 关闭超时限制(生产环境慎用)
  - N8N_EXECUTIONS_TIMEOUT=0
  # 或者设置具体超时时间(300000ms = 5分钟)
  - N8N_EXECUTIONS_TIMEOUT=300000

更安全的做法是在工作流内部设置超时,而不是全局关闭限制。进入具体工作流 → 设置 → 执行设置 → 自定义超时时间。

坑5:重启后凭证丢失 — N8N_ENCRYPTION_KEY 必须持久化

n8n 把所有凭证(API Key、密码等)加密存储在数据库里。加密密钥由 N8N_ENCRYPTION_KEY 环境变量指定。我在重启容器后,发现所有之前配置的 API 凭证全部失效。

原因:N8N_ENCRYPTION_KEY 没有持久化,每次重启容器时 docker-compose 如果没有正确传递这个变量,n8n 就会生成新的随机密钥,导致无法解密原有凭证。

**正确做法**:把加密密钥写在 .env 文件里(确保安全),并在 docker-compose.yml 中引用:

# .env 文件
N8N_ENCRYPTION_KEY=your-very-long-random-string-here-min-32-chars
DB_PASSWORD=your-postgres-password
ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
environment:
  - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}

生成强随机密钥的方法:

openssl rand -hex 32

**警告**:更换 N8N_ENCRYPTION_KEY 会导致所有现有凭证无法解密。如果需要轮换密钥,必须先导出所有凭证再重新导入。

完整的正确 docker-compose.yml

以下是我最终使用的完整配置,覆盖了所有坑:

version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: n8n
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - n8n_pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  n8n:
    image: docker.n8n.io/n8nio/n8n
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - GENERIC_TIMEZONE=Asia/Shanghai
      - TZ=Asia/Shanghai
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
      - N8N_WEBHOOK_URL=https://n8n.example.com/
      - DB_TYPE=postgresdb
      - DB_ADAPTER=postgres
      - DB_POSTGRESDB=n8n
      - DB_POSTGRESHOST=postgres
      - DB_POSTGRESUSER=n8n
      - DB_POSTGRESPASSWORD=${DB_PASSWORD}
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - N8N_EXECUTIONS_TIMEOUT=300000
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

volumes:
  n8n_data:
  n8n_pgdata:

配合 Nginx 反向代理(关键配置):

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 支持(n8n 编辑器实时更新需要)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

适合人群

适合部署 n8n 自托管的场景:

不适合的场景:


📚 相关阅读

成本参考

自托管 n8n 的最低成本:

方案月费用配置
VPS(最小)$6-101C1G
VPS(推荐)$12-202C2G
附加:PostgreSQL$0-5使用 Docker 内置或云数据库

相比 Zapier 免费版(100 次执行/月),自托管 n8n 执行次数无限制,$12/月的 VPS 性价比极高。

👉 如果你用 AI API 来驱动 n8n 工作流,建议搭配 MiniMax API 使用——成本比 OpenAI 低 80%,中文支持更好。

👉 立即参与:https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link

总结:踩坑检查清单

部署 n8n Docker 之前,逐项确认:

如果你的工作流需要调用 AI 接口来生成内容、分类数据或处理文本,n8n + MiniMax API 的组合是目前性价比最高的自托管方案之一。

👉 立即参与:https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link

🔗 Related Tech Articles

Deep dive into related technical topics:

n8n自托管Docker部署实战避坑指南
技术标签: docker, 自托管
n8n自托管配置避坑实战
技术标签: n8n, 自托管
n8n自托管配置避坑实战
技术标签: n8n, 自托管
⚡ Automation Workflow Hardware
查看推荐 →