关于 n8n-self-hosting
面向运维人员的 n8n Linux 虚拟机部署指南,使用 Docker Compose、Caddy 和 HTTPS。内容涵盖单进程与队列模式选择、安装、安全、验证及维护。
主要功能
- 01单实例与队列部署方案
- 02Docker Compose 和 Caddy 配置
- 03HTTPS 证书验证
- 04密钥与网络安全指导
- 05部署健康检查
适用场景
- 01在全新 Linux 虚拟机上运行 n8n
- 02按预期负载选择部署模式
- 03检查 HTTPS 和服务状态
- 04保护密钥及内部服务
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ czlonkowski/ n8n-skills --skill n8n-self-hosting安装后在 Claude Code 中输入/n8n-self-hosting确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CREDENTIAL_OVERWRITES.mdDAY2.mdQUEUE_MODE.mdREADME.mdSECURITY.mdSINGLE_MODE.mdTASK_RUNNERS.mdassets/.env.queue.example.env.single.exampleCaddyfiledocker-compose.queue.ymldocker-compose.single.ymlinit-data.sh详细介绍
部署可自托管的 n8n
此技能可将一台全新的 Linux 虚拟机(Ubuntu/Debian,使用 root 或 sudo SSH)部署为可运行、启用 HTTPS、可用于生产环境的 n8n,通过 Docker Compose 在 Caddy 后运行(自动配置 Let's Encrypt TLS)。此方案适用于 Docker 上可自托管的 n8n,不适用于 n8n Cloud,也不用于构建工作流(本资源包的其他部分会介绍)。
有两种部署模式。两种架构有所不同,因此开始操作前请先选择模式。
你将通过 SSH 完成端到端部署:预检查 → 安装 Docker → 部署项目 → 生成密钥 → 启动 → 验证 TLS → 交接。模板文件位于 assets/ 中,各模式的详细说明和安全注意事项见下文列出的参考文件。
规则 0 — 选择模式(询问用户)
不要猜测。先询问,然后确定一种模式:
| 单机 / 常规 | 队列 | |
|---|---|---|
| 进程 | 一个 n8n | 主进程 + N 个工作进程 |
| 额外服务 | 无(SQLite) | Redis(队列)+ Postgres(数据库) |
| 执行工作流 | 在主进程中 | 由工作进程并行执行 |
| 适用场景 | 1 位用户、轻度/中度负载、运维最简单 | 高吞吐量、繁重/长时间执行、水平扩展 |
| Compose | assets/docker-compose.single.yml | assets/docker-compose.queue.yml |
| 深入了解 | SINGLE_MODE.md | QUEUE_MODE.md |
如果不确定,请从单机模式开始——它是最简单且正确的选择,适用于大多数需求。之后切换到队列模式需要替换 compose 文件,并将 SQLite 迁移到 Postgres;因此,如果用户已经预计会有较大流量,请直接从队列模式开始。
规则 1 — 密钥卫生(不可妥协)
这里一旦操作失误,就会泄露客户端凭据。务必谨慎:
- 在目标机器上为每个密钥重新生成。 切勿将其他 n8n 实例的加密密钥、数据库密码或
.env复制到此实例。SECURITY.md中提供了openssl命令。 - 密钥只能存放在
.env中(权限模式为 600),并通过 compose 中的${VAR}引用。切勿将密钥直接写入docker-compose.yml、Caddyfile 或任何会提交的内容中。 N8N_ENCRYPTION_KEY至关重要。 它用于加密所有已存储的凭据。如果丢失或发生变化,所有已保存的凭据都将无法解密。请明确设置,并提醒用户将其备份到机器之外。除了交接所需内容外,不要将其输出到长期日志或聊天记录中。- 绝不公开内部服务。 仅 Caddy(80/443)可公开访问。n8n(5678)、Postgres(5432)、Redis(6379)必须留在私有 Docker 网络中——模板已省略它们的主机端口映射。不要添加这些映射。
.env和 Caddy 的caddy_data卷(已签发的证书和 ACME 账户密钥)不得作为共享文件。 如果你在 git 仓库中操作,请在提交前确认.env已被 git 忽略。
预先收集的输入信息
- SSH 目标 —
user@host以及身份验证方式(密钥路径,或用户确认 Agent 已有访问权限)。使用 root 或 sudo 用户。 - 域名 — n8n 将使用的完整主机名,例如
n8n.example.com(→SUBDOMAIN=n8n,DOMAIN_NAME=example.com)。用户必须能控制其 DNS。 - TLS 邮箱 — 用于 Let's Encrypt(
SSL_EMAIL)。 - 时区 — Schedule/Cron 节点使用的 IANA 名称(例如
Europe/Warsaw),否则使用Etc/UTC。 - 模式 — 单机或队列(规则 0)。队列模式 → 确认服务器有足够的 RAM(最低约 4 GB;每个 worker 需要约 1–2 GB)。
- 可选模块 — 部分功能(目前为 Agents)属于默认关闭的后端模块,只有列入
N8N_ENABLED_MODULES后才会启用。只有用户主动提及时才询问;如果用户提及,请在启用前阅读QUEUE_MODE.md的模块部分,因为队列模式下还必须让 worker 能访问这些模块。 - Python Code 节点 / 谁会编辑工作流 — 询问 “工作流会使用 Python Code 节点吗?除了你之外,还会有人编辑工作流吗?” 任何一项回答“是”,都意味着要将 task runner 设为 external mode:使用
n8nio/runnerssidecar(队列模式下每个 worker 配置一个)。官方的n8nio/n8n镜像不包含 Python 3,因此在默认的 internal mode 下,每个 Python Code 节点都会失败,并显示Python runner unavailable: Python 3 is missing from this system。请在第 3 步之前阅读TASK_RUNNERS.md。
部署流程
请按顺序完成以下步骤。SINGLE_MODE.md / QUEUE_MODE.md 提供各模式的具体命令;SECURITY.md 介绍密钥生成和加固;DAY2.md 介绍更新/备份/恢复。
1. 部署前检查(越早发现问题,修复成本越低)
- 通过 SSH 登录;确认操作系统类似 Debian/Ubuntu(
. /etc/os-release)。 - DNS 必须已指向服务器。 将服务器的公网 IP(
curl -s ifconfig.me)与dig +short <fqdn>的结果比较(在服务器上运行,并最好也在你的笔记本电脑上运行)。如果两者不一致,请停止 — Caddy 的 ACME 验证会失败。请让用户创建 A 记录,等待其生效后再继续。 - 端口 80 和 443 必须可从互联网访问。检查主机防火墙以及任何云安全组 / 网络防火墙(Hetzner Cloud、AWS SG 等)——这些位于服务器之外,是常见的隐性拦截因素。
2. 安装 Docker(如果尚未安装)
- 检查
docker --version和docker compose version。如果缺少 Docker,请安装 Docker Engine 和 Compose 插件(在 Ubuntu/Debian 上使用 Docker 官方的get.docker.com脚本即可)。 继续之前,请重新检查docker compose version。
3. 部署项目文件
- 选择
DATA_FOLDER— 一个绝对路径,例如/opt/n8n。.env中的DATA_FOLDER值必须与此目录完全一致(compose 会挂载${DATA_FOLDER}/caddy_config/Caddyfile,而init-data.sh通过相对的./路径挂载),因此务必始终在此目录下运行docker compose。创建该目录,以及其中的caddy_config/和local_files/。 - 将模板文件传到服务器。 这些文件位于你本机上此 skill 的
assets/目录中,而不是服务器上——请逐个传输。可以使用scp上传,或者(无需本地副本)通过 SSH 写入各文件的内容,例如:ssh <target> 'cat > <DATA_FOLDER>/docker-compose.yml' < assets/docker-compose.single.yml。 请使用以下准确文件名放置文件:- 选定的 compose →
<DATA_FOLDER>/docker-compose.yml(重命名为此准确名称) Caddyfile→<DATA_FOLDER>/caddy_config/Caddyfile- 仅队列模式:
init-data.sh→<DATA_FOLDER>/init-data.sh,然后运行chmod +x - 对应的
.env.*.example→<DATA_FOLDER>/.env
- 选定的 compose →
- External task runner(Python): 现在将 runner 环境变量和
task-runnerssidecar 添加到 compose 中(TASK_RUNNERS.md提供各模式对应的代码片段)。在第 4 步生成N8N_RUNNERS_AUTH_TOKEN,与其他密钥一并生成。
4. 填写 .env + 生成密钥
- 设置
DATA_FOLDER、DOMAIN_NAME、SUBDOMAIN、SSL_EMAIL、GENERIC_TIMEZONE。 - 在主机上使用
openssl生成每个密钥(SECURITY.md中有相关命令),并将其写入.env,替换对应的REPLACE_WITH_…占位符:N8N_ENCRYPTION_KEY;队列模式还需要POSTGRES_PASSWORD+POSTGRES_NON_ROOT_PASSWORD。 - 启动前,确认没有未设置的密钥:
grep REPLACE_WITH_ .env必须无任何输出——遗留的占位符会变成字面密码,导致 Postgres/n8n 无法连接。 - 执行
chmod 600 .env。记录加密密钥,以便用户备份到主机外。
5. 防火墙
- 使用
ufw:允许 OpenSSH + 80 + 443,然后启用防火墙。不要开放 5678/5432/6379。
6. 启动
- 执行
cd <DATA_FOLDER> && docker compose up -d。 - 队列模式会启动 Redis + Postgres + 主服务 + 工作进程(工作进程通过
replicas启动)。要增加容量:docker compose up -d --scale n8n-worker=N。
7. 验证(未完成此项前不要宣告成功)
docker compose ps— 每个服务都应为Up/healthy(队列模式:先确认 postgres 和 redis 为healthy)。- 确认 n8n 本身已启动(内部):
docker compose exec n8n wget -qO- http://localhost:5678/healthz→{"status":"ok"}。这样可以区分“n8n 正在运行”和“TLS 尚未就绪”。 - 确认已签发证书:
docker compose logs caddy | grep -i 'certificate obtained'。首次启动时,ACME 可能需要一两分钟;在完成之前,访问公开的https://地址会发生 TLS 错误——这表示证书仍在等待签发,并不表示 n8n 已停止运行。 - 确认可从外部访问(带重试):
curl -fsS --retry 5 --retry-delay 10 https://<fqdn>/healthz→{"status":"ok"}。(/healthz只能证明进程可访问;/healthz/readiness还会确认数据库已连接并完成迁移——排查启动循环时请使用此端点。) - 队列模式 — 主服务和工作进程的配置必须一致。 对比它们的环境变量:
diff <(docker compose exec -T n8n env | sort) <(docker compose exec -T --index 1 n8n-worker env | sort)。 只有公开 URL/代理变量应该不同。其他任何差异都表示某个行为设置已传递给主服务,却未传递给工作进程——而工作流由工作进程执行,因此会在运行时而非启动时因某个节点配置不一致而失败。QUEUE_MODE.md解释了此规则。 - 外部任务运行器:
docker compose logs n8n | grep 'Registered runner'必须显示launcher-javascript和launcher-python(队列模式:检查每个工作进程)。然后对 Python Code 节点进行冒烟测试(TASK_RUNNERS.md→ Verify)。 - 打开
https://<fqdn>→ 所有者设置页面。第一个完成注册表单的人将获得该实例的所有权——暴露在外且尚未设置所有者的实例存在被抢先认领的风险,因此请立即创建所有者账户,然后再分享 URL。启用 2FA。(自动化部署也可以通过环境变量预先配置所有者——参见SECURITY.md中所有者对应的条目。)
8. 交接
- 向用户提供:URL、项目所在位置、需要妥善保存的加密密钥,以及来自
DAY2.md的日常维护基础知识(更新 / 备份 / 恢复)。
不要做的事
- 不要跳过 DNS/端口预检。 A 记录错误或云防火墙未开放,是 Caddy 无法获取证书、n8n 看起来“坏了”的 首要原因。
- 不要将 5678/5432/6379 发布到主机。 Caddy 通过专用网络访问 n8n。
- 不要重复使用其他实例的加密密钥或
.env。 每台主机都要使用全新的密钥。 - 不要在 SQLite 上运行队列模式。 队列需要 Postgres(模板已配置好)。
- 不要将密钥放在
docker-compose.yml或 Caddyfile 中。 只放在.env中。 - 不要只在主节点上添加行为相关的环境变量(队列模式)。 模块、数据库、队列、二进制数据和加密设置都应放在共享的
x-n8n-env锚点中,以便工作节点也能获取;只有公共 URL/代理变量仅用于主节点。参见QUEUE_MODE.md。 - 不要盲目使用
:latest。 固定N8N_IMAGE_TAG;谨慎更新(DAY2.md)。 - 不要承诺内部模式下的标准镜像支持 Python Code 节点。 它们需要
n8nio/runnerssidecar,且版本必须与 n8n 完全一致,并在启动器配置中将导入项加入允许列表。默认情况下,连import json都会被拒绝。参见TASK_RUNNERS.md。 - 外部运行器启用后,不要对队列工作节点使用
--scale。 一个 sidecar 只能服务一个工作节点。应添加工作节点 + 运行器配对(TASK_RUNNERS.md)。
参考文件
SINGLE_MODE.md— 单实例相关说明、SQLite 与 Postgres 的选择,以及何时升级到队列模式。QUEUE_MODE.md— 队列架构、工作节点/并发/扩展、共享加密密钥、主节点与工作节点之间的环境变量一致性规则、可选后端模块(N8N_ENABLED_MODULES,例如 Agents)、二进制数据(database模式——队列模式不支持文件系统;S3/Azure = Enterprise)、Webhook 处理器、多主节点许可。SECURITY.md— 生成密钥、加密密钥规则、完整的安全加固清单(关闭遥测、阻止访问环境变量、公共 API、防火墙、安全 Cookie)。CREDENTIAL_OVERWRITES.md— 托管 OAuth:在整个实例范围内注册一个 OAuth 应用,让用户永远看不到客户端 ID/密钥(自托管环境中的“使用 Google 登录”)。端点与环境变量的选择、必需的端点身份验证令牌、父类型继承、持久化和工作节点重新加载。TASK_RUNNERS.md— 外部模式下的任务运行器:Python Code 节点为何需要n8nio/runnerssidecar、单实例模式的 compose 片段和队列模式下每个工作节点对应一个 sidecar 的模式、通过/etc/n8n-task-runners.json将 Python/JS 模块加入允许列表、内置拒绝列表、验证、故障特征,以及同时升级 n8n 和运行器。DAY2.md— 安全地更改设置(环境变量)、更新镜像、备份(加密密钥 + 卷 + Postgres)和恢复。assets/— 模板:docker-compose.single.yml、docker-compose.queue.yml、Caddyfile、.env.single.example、.env.queue.example、init-data.sh。
权威上游参考资料:官方托管文档位于
https://docs.n8n.io/deploy/host-n8n(在 2026 年年中从旧的 /hosting/ 路径重组而来——
请优先使用这些 URL)。环境变量参考索引位于
https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables。
如果本文档与实时文档不一致,请以文档为准并告知用户。