在Linux上用Docker Compose部署n8n是最稳、最易维护的方式,因其能统一管理进程守护、日志、更新、数据持久化及多服务依赖(如PostgreSQL、Nginx),避免裸跑导致的Webhook失败、服务中断、数据库锁表和配置丢失等问题。

直接上结论:在 Linux 上用 docker-compose 部署 n8n 是最稳、最易维护的方式,不推荐用 npm install -g n8n 或二进制直跑——后者在生产环境会因进程管理、日志、更新、数据持久化等问题反复踩坑。
为什么必须用 Docker Compose 而不是裸跑 n8n
n8n 本身是 Node.js 应用,但它的运行依赖状态(工作流定义、凭证、执行历史)和外部服务(数据库、反向代理、HTTPS)。裸跑时:
-
N8N_WEBHOOK_URL容易配错,导致 Webhook 触发失败(常见错误:Webhook not found或404 on /webhook/xxx) - 进程无守护,
Ctrl+C或 SSH 断开后服务就停了 - 升级需手动停服、拉新镜像、迁移数据,极易丢工作流
- SQLite 默认数据库在容器重启后可能被覆盖(因为没挂载
/home/node/.n8n)
docker-compose.yml 关键配置项说明
以下是最小可用且生产就绪的 docker-compose.yml 片段,重点看这几个参数:
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
environment:
- N8N_HOST=n8n.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- N8N_WEBHOOK_URL=https://n8n.example.com/
- NODE_ENV=production
- DB_TYPE=postgres
- DB_POSTGRESDB_DATABASE=n8n_prod_db
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_USER=n8n_prod
- DB_POSTGRESDB_PASSWORD=StrongPassword123!
volumes:
- n8n_data:/home/node/.n8n
ports:
- "5678:5678"
depends_on:
- postgres
<p>postgres:
image: postgres:15-alpine
environment:</p><ul><li>POSTGRES_DB=n8n_prod_db</li><li>POSTGRES_USER=n8n_prod</li><li>POSTGRES_PASSWORD=StrongPassword123!
volumes:</li><li>postgres_data:/var/lib/postgresql/data</li></ul><p>volumes:
n8n_data:
postgres_data:-
N8N_WEBHOOK_URL必须和最终用户访问地址完全一致(含https://和结尾/),否则 Slack、GitHub 等回调会失败 -
DB_TYPE=postgres是硬性要求:SQLite 在多实例或高并发下会锁表,ERROR: database is locked几乎必现 -
volumes挂载不可省:不挂载n8n_data,每次docker-compose down后所有工作流和凭证清零
启动前必须验证的三件事
别急着 docker-compose up -d,先确认:
- DNS 已生效:
dig +short n8n.example.com能返回服务器 IP - 端口可通:
curl -I http://localhost:5678应返回HTTP/1.1 401 Unauthorized(说明容器已监听) - PostgreSQL 可连:
docker-compose exec postgres psql -U n8n_prod n8n_prod_db -c "SELECT 1"返回1
任一失败,n8n 容器会不断重启(docker-compose logs -f n8n 可见 Connection refused 或 invalid password)。
Nginx 反向代理与 HTTPS 的最小配置
n8n 不自带 HTTPS,必须由 Nginx 终止 SSL。关键点只有两个:
- 转发请求时必须透传 Host 和协议头:
proxy_set_header X-Forwarded-Proto $scheme;和proxy_set_header Host $host;,缺一则N8N_WEBHOOK_URL构造错误 - Certbot 自动续期后,Nginx 需重载:
sudo certbot renew --post-hook "systemctl reload nginx"
如果你跳过 Nginx 直接暴露 5678 端口,不仅无法用 HTTPS,还会让 Basic Auth 凭证明文传输——N8N_BASIC_AUTH_USER 和 N8N_BASIC_AUTH_PASSWORD 就形同虚设。
真正容易被忽略的是 N8N_WEBHOOK_URL 和反向代理头的联动关系:它既影响外部服务回调,也影响 n8n 内部生成的 Webhook URL 显示。配错一次,所有已保存的 Webhook 链接就全失效,只能手动重配——这个坑我见过太多人掉进去。


















