如何把n8n部署到线上:vps篇

给小白的 n8n VPS 部署教程:从域名、Docker Compose、PostgreSQL 与 HTTPS 开始,每一步都解释用途、成功标志、与教程不一致时的处理方式,以及最后的完整排障清单。

当你需要让 n8n 在电脑关机后继续运行、稳定接收 Webhook、每天按时执行任务时,就该考虑 VPS。VPS 可以理解为“放在数据中心、一直联网的一台 Linux 小电脑”。你租用它的计算和网络资源,然后在上面运行自己的 n8n。

本文会带你搭建一个最小但完整的线上架构:域名负责让人找到你的服务,反向代理负责 HTTPS,n8n 容器负责自动化,PostgreSQL 负责保存数据,备份负责在出错时救回来。

本文不是让你一次记住所有名词。每一步先做最小操作,再解释它做了什么、看到什么算成功、如果和教程不同该怎么处理。

先看最终会搭出什么

线上 n8n 的组成:域名、HTTPS、n8n、数据库、持久化数据和备份
组件 小白解释 缺少它会怎样
VPS 一台 24 小时开机的远程电脑 任务仍会依赖你的个人电脑
Docker Compose 一份“同时启动几个服务”的说明书 每个服务要手动配置,容易遗漏
PostgreSQL 存工作流和执行记录的数据库 长期线上运行不够稳妥
Caddy 自动处理 HTTPS 的门卫 外部服务难以安全访问 Webhook
volume 容器外面的持久化硬盘空间 重建容器后数据可能丢失
备份 出错时的后悔药 误删、硬盘故障或升级失败无法恢复

n8n 官方将 Docker Compose 作为适合包含数据库和附加服务的生产部署选择之一。n8n 自托管指南

第 0 步:开始前准备什么

你需要一台 Linux VPS、一个可以管理 DNS 的域名、SSH 登录权限,以及半小时到一小时的安静时间。建议先准备子域名,例如 n8n.example.com,不要把 n8n 管理界面直接放在主站域名下。

你暂时不需要: Kubernetes、复杂监控、多个服务器或高可用集群。先把一个可恢复的单机环境跑稳,比一开始堆很多组件更重要。

第 1 步:让域名指向 VPS

在 DNS 服务商后台新增一条 A 记录:主机名填写 n8n,记录值填写 VPS 的 IPv4 地址。保存后等待解析生效。

这一步在做什么? 把 n8n.example.com 翻译成 VPS 的 IP。之后 Caddy 才能为这个域名申请 HTTPS 证书。

成功标志: 在本地终端执行 nslookup n8n.example.com 或使用任意 DNS 查询工具,结果显示为你的 VPS IP。

如果和教程不同: 有些 DNS 面板叫“记录名称”“Host”或“子域名”,含义相同;如果你使用 Cloudflare,先确保 DNS 记录正确,再处理代理模式和证书配置。

第 2 步:登录服务器并准备目录

用 SSH 登录 VPS。创建一个专门放部署文件和备份的目录:

mkdir -p ~/n8n-production/backups
cd ~/n8n-production

这一步在做什么? 以后 compose.yaml、.env 和备份都会放在这里。目录固定,升级和排查时不会找不到文件。

接下来安装 Docker Engine 和 Docker Compose 插件。不同 Linux 发行版的安装命令不同,请优先使用 Docker 官方安装文档。安装完成后检查:

docker version
docker compose version

两个命令都能显示版本号,就说明 Docker 已准备好。

第 3 步:创建 .env,把密码和配置分开保存

.env 是一个只存变量的文件。不要把密码直接写在 compose.yaml 中,更不要上传到 GitHub。

N8N_HOST=n8n.example.com
N8N_ENCRYPTION_KEY=<一串长期保存的随机密钥>
POSTGRES_DB=n8n
POSTGRES_USER=n8n
POSTGRES_PASSWORD=<强随机数据库密码>

生成随机密钥可执行:

openssl rand -hex 32
chmod 600 .env

这一步在做什么? N8N_ENCRYPTION_KEY 是 n8n 保护凭据的总钥匙;POSTGRES_PASSWORD 是数据库密码。chmod 600 让同一台服务器上的其他普通用户不能读取该文件。

成功标志: ls -l .env 显示该文件只允许当前用户读写。

非常重要: 换服务器、恢复备份或升级时,要保留原来的 N8N_ENCRYPTION_KEY。否则之前保存的 API Key、OAuth 凭据可能无法解密。

第 4 步:创建 Compose 配置

新建 compose.yaml,将下面内容复制进去。它会启动三个服务:PostgreSQL、n8n 和 Caddy。PostgreSQL 不直接暴露端口给公网,只有 n8n 能在内部网络里访问它。

services:
  postgres:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks: [n8n_internal]

  n8n:
    image: docker.n8n.io/n8nio/n8n:stable
    restart: unless-stopped
    depends_on: [postgres]
    environment:
      N8N_HOST: ${N8N_HOST}
      N8N_PROTOCOL: https
      N8N_PORT: 5678
      N8N_WEBHOOK_URL: https://${N8N_HOST}/
      N8N_PROXY_HOPS: 1
      GENERIC_TIMEZONE: Asia/Shanghai
      TZ: Asia/Shanghai
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      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}
    volumes:
      - n8n_data:/home/node/.n8n
    networks: [n8n_internal]

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    depends_on: [n8n]
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks: [n8n_internal]

volumes:
  postgres_data:
  n8n_data:
  caddy_data:
  caddy_config:

networks:
  n8n_internal:

n8n 默认使用 SQLite,但官方支持通过 DB_TYPE=postgresdb 与 DB_POSTGRESDB_* 变量连接 PostgreSQL。n8n 数据库变量参考 即使已使用 PostgreSQL,也建议保留 /home/node/.n8n 的 volume,因为这里仍包含加密密钥、日志等重要资产。n8n Docker 文档

第 5 步:创建 HTTPS 反向代理配置

新建 Caddyfile,把域名换成你自己的:

n8n.example.com {
    reverse_proxy n8n:5678
}

这一步在做什么? Caddy 接收公网的 HTTPS 请求,再安全地转发给内部的 n8n。外部只需要访问 443 端口,n8n 的 5678 端口不暴露在互联网。

n8n 位于反向代理后时,应设置 N8N_WEBHOOK_URL 和 N8N_PROXY_HOPS=1,让它生成正确的公网 Webhook 地址。n8n 反向代理与 Webhook 指南

第 6 步:先检查,再启动

先运行:

docker compose config

成功标志: 命令没有报错,并输出整理后的配置。它相当于启动前的语法检查。

再启动:

docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 n8n

docker compose ps 中三个服务都显示 running 或 up,说明容器已启动。然后打开 https://n8n.example.com 创建 n8n owner 账户。

第 7 步:第一次上线后必须做的三个测试

  1. 手动测试。 创建 Manual Trigger → Set,执行成功说明 n8n 基础可用。
  2. Webhook 测试。 创建一个测试 Webhook,从手机流量或外部 HTTP 工具访问它,确认不是只在服务器内部可用。
  3. 定时测试。 建一个短时间间隔的测试任务,确认时区正确、日志有执行记录。

如果时间偏差八小时,优先检查 GENERIC_TIMEZONE 与 TZ;如果 Webhook 显示内部地址,检查域名、N8N_WEBHOOK_URL 和 Caddy。

跟教程不同怎么办:按这个顺序排查

你看到的情况 不要急着做什么 应该先做什么
域名打不开 不要反复重启容器 检查 DNS 是否指向 VPS、80/443 是否开放
Caddy 申请证书失败 不要关闭 HTTPS 检查域名解析、端口、防火墙和是否被其他服务占用
n8n 一直重启 不要删除 volume 查看 docker compose logs n8n 和 postgres 日志
数据库报认证失败 不要随意换密钥 检查 .env 密码、变量是否被 Compose 正确读取
升级后流程异常 不要先执行 down -v 停止写入、保留日志、按备份与版本记录回滚

备份:把“能恢复”当成目标

volume 能防止容器重建时丢数据,但不是备份。至少要保存三类东西:PostgreSQL 数据库、.env 里的加密密钥和密码、n8n_data 中的重要文件。

数据库备份示例:

mkdir -p backups
set -a && source .env && set +a
docker compose exec -T postgres \
  pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" \
  > "backups/n8n-$(date +%F).sql"

成功标志: backups 目录出现非零大小的 .sql 文件。更进一步,请在单独环境做一次恢复演练;只有真正恢复成功,备份才算有效。

常见问题与排障汇总

问题 原因解释 解决顺序
浏览器出现 502/Bad Gateway Caddy 找不到 n8n,或 n8n 未启动 docker compose ps → docker compose logs n8n → 检查 Caddyfile
Docker 提示端口已被占用 80、443 或 5678 被其他程序使用 sudo ss -ltnp 查占用;不要同时运行两套代理
n8n 能打开但第三方回调失败 公开 URL、HTTPS 或 Webhook 地址错误 用外网测试 URL → 检查 N8N_WEBHOOK_URL → 查看代理日志
重启后数据不见 没有使用 volume 或误删 volume 检查 docker volume ls;恢复备份;以后不要随意 down -v
凭据全部失效 加密密钥变了 恢复原 .env 中的 N8N_ENCRYPTION_KEY
升级后工作流报错 n8n 版本变化或节点行为变化 阅读变更说明、用测试工作流验证、必要时回滚镜像
服务器磁盘越来越满 执行记录、日志或备份没有轮换 定期检查 df -h,清理过期备份,设置执行数据保留策略

小结

VPS 的价值不只是“让 n8n 在线”,而是让运行、数据、密钥和备份都有明确位置。只要你坚持每次升级前备份、不要暴露内部端口、保管好加密密钥,并在出现问题时先看日志而不是先删数据,这套架构足够服务大多数个人与小团队的长期自动化。

参考资料

  1. n8n:自托管方式与部署选择
  2. n8n:Docker 安装、持久化数据与更新
  3. n8n:数据库环境变量参考
  4. n8n:反向代理下配置 Webhook URL
  5. Docker:安装 Docker Engine 的官方文档