n8n-self-hosting
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDeploying self-hosted n8n
部署自托管n8n
This skill takes a fresh Linux VM (Ubuntu/Debian, root or sudo SSH) to a running,
HTTPS, production n8n via Docker Compose behind Caddy (automatic Let's Encrypt TLS).
It is for self-hosted n8n on Docker — not n8n Cloud, and not for building workflows
(that's the rest of this pack).
Two deployment modes. The architectures differ, so pick the mode before doing anything.
You drive this end-to-end over SSH: preflight → install Docker → lay down the project →
generate secrets → launch → verify TLS → hand off. The template files live in ;
the per-mode and security depth live in the reference files named below.
assets/本技能可将一台全新Linux虚拟机(Ubuntu/Debian系统,支持root或sudo权限SSH)通过Docker Compose搭配Caddy(自动Let's Encrypt TLS)部署为可运行、带HTTPS的生产级n8n。本技能针对的是Docker上的自托管n8n——而非n8n Cloud,也不涉及工作流构建(工作流构建属于该工具包的其他内容)。
支持两种部署模式。两种架构不同,因此在操作前请先选择模式。
整个流程通过SSH端到端完成:预检 → 安装Docker → 部署项目 → 生成密钥 → 启动服务 → 验证TLS → 交付。模板文件存放在目录下;各模式的细节和安全配置在下文提及的参考文件中。
assets/Rule 0 — choose the mode (ask the user)
规则0 — 选择模式(询问用户)
Do not guess. Ask, then commit to one:
| Single / regular | Queue | |
|---|---|---|
| Processes | one n8n | main + N workers |
| Extra services | none (SQLite) | Redis (queue) + Postgres (DB) |
| Executes workflows | in the main process | on workers, in parallel |
| Good for | 1 user, light/moderate load, simplest ops | high volume, heavy/long executions, horizontal scale |
| Compose | | |
| Deep dive | | |
If unsure, start single — it's the simplest correct thing and covers most needs. Moving
to queue later means swapping the compose file and migrating SQLite→Postgres, so if the user
already expects real volume, start queue.
请勿猜测。先询问用户,再确定其中一种:
| 单实例/常规模式 | 队列模式 | |
|---|---|---|
| 进程 | 单个n8n进程 | 主进程 + N个工作节点 |
| 额外服务 | 无(使用SQLite) | Redis(队列) + Postgres(数据库) |
| 工作流执行 | 在主进程中执行 | 在工作节点上并行执行 |
| 适用场景 | 单用户、轻/中等负载、运维最简单 | 高流量、重负载/长时执行、横向扩展 |
| Compose文件 | | |
| 详细指南 | | |
若不确定,建议先选择单实例模式——这是最简单的正确方案,能满足大多数需求。后续若要切换到队列模式,需要替换Compose文件并将SQLite迁移到Postgres;因此如果用户已明确需要处理大量流量,建议直接选择队列模式。
Rule 1 — secret hygiene (non-negotiable)
规则1 — 密钥安全(必须遵守)
A misstep here leaks client credentials. Be diligent:
- Generate every secret fresh, on the target box. Never copy an encryption key, DB
password, or from another n8n instance into this one. See
.envfor theSECURITY.mdcommands.openssl - Secrets live only in (mode 600), referenced by the compose as
.env. Never inline a secret into${VAR}, the Caddyfile, or anything you commit.docker-compose.yml - The is sacred. It encrypts every stored credential. If it's lost or changes, all saved credentials become undecryptable. Set it explicitly, and tell the user to back it up off the box. Don't echo it into long-lived logs or chat history beyond what's needed to hand it over.
N8N_ENCRYPTION_KEY - Never expose internal services. Only Caddy (80/443) is public. n8n (5678), Postgres (5432), Redis (6379) stay on the private Docker network — the templates already omit their host port mappings. Don't add them.
- and Caddy's
.envvolume (the issued certs + ACME account key) are not artifacts to share. If you're working inside a git repo, confirmcaddy_datais git-ignored before any commit..env
此处操作失误会导致客户端凭证泄露,请务必谨慎:
- 在目标设备上生成所有新密钥。切勿从其他n8n实例复制加密密钥、数据库密码或文件到本实例。
.env中提供了SECURITY.md命令示例。openssl - 密钥仅存储在文件中(权限设为600),Compose文件通过
.env引用。切勿将密钥直接写入${VAR}、Caddyfile或任何会被提交的文件中。docker-compose.yml - 至关重要。它用于加密所有存储的凭证。如果该密钥丢失或变更,所有已保存的凭证将无法解密。请显式设置该密钥,并告知用户将其备份到设备外的安全位置。除必要的交付环节外,切勿将其输出到长期日志或聊天记录中。
N8N_ENCRYPTION_KEY - 切勿暴露内部服务。仅将Caddy(端口80/443)对外开放。n8n(5678)、Postgres(5432)、Redis(6379)应保留在私有Docker网络中——模板已省略它们的主机端口映射,请勿添加。
- 文件和Caddy的
.env卷(包含已颁发的证书 + ACME账户密钥)不可共享。如果在git仓库中操作,请确认caddy_data已被git忽略后再进行提交。.env
Inputs to collect up front
需提前收集的信息
- SSH target — and how you authenticate (key path or the user confirms the agent already has access). Root or a sudo user.
user@host - Domain — the full hostname n8n will live at, e.g. (→
n8n.example.com,SUBDOMAIN=n8n). The user must control its DNS.DOMAIN_NAME=example.com - TLS email — for Let's Encrypt ().
SSL_EMAIL - Timezone — IANA name for Schedule/Cron nodes (e.g. ), else
Europe/Warsaw.Etc/UTC - Mode — single or queue (Rule 0). Queue → confirm the box has enough RAM (rough floor ~4 GB; each worker wants ~1–2 GB).
- SSH目标 — 以及认证方式(密钥路径或用户确认Agent已拥有访问权限)。需使用root或拥有sudo权限的用户。
user@host - 域名 — n8n将使用的完整主机名,例如(对应
n8n.example.com,SUBDOMAIN=n8n)。用户必须拥有该域名的DNS控制权。DOMAIN_NAME=example.com - TLS邮箱 — 用于Let's Encrypt证书申请(对应)。
SSL_EMAIL - 时区 — Schedule/Cron节点使用的IANA时区名称(例如),默认使用
Europe/Warsaw。Etc/UTC - 模式 — 单实例或队列模式(规则0)。若选择队列模式,请确认设备拥有足够内存(最低约4GB;每个工作节点需约1–2GB)。
The deploy flow
部署流程
Work through these in order. / give the mode-specific command
detail; covers secret generation and hardening; covers update/backup/restore.
SINGLE_MODE.mdQUEUE_MODE.mdSECURITY.mdDAY2.md请按以下顺序执行。 / 提供了各模式的具体命令细节;涵盖密钥生成和加固操作;涵盖更新/备份/恢复操作。
SINGLE_MODE.mdQUEUE_MODE.mdSECURITY.mdDAY2.md1. Preflight (the cheapest failure is the one you catch here)
1. 预检(提前发现问题成本最低)
- SSH in; confirm the OS is Debian/Ubuntu-like ().
. /etc/os-release - DNS must already point at the box. Compare the box's public IP () with
curl -s ifconfig.me(run it from the box AND ideally your laptop). If they don't match, stop — Caddy's ACME challenge will fail. Have the user create the A record, wait for it to propagate, then continue.dig +short <fqdn> - Ports 80 and 443 must be reachable from the internet. Check the host firewall AND any cloud security group / network firewall (Hetzner Cloud, AWS SG, etc.) — these are outside the box and a common silent blocker.
- 登录SSH;确认系统为Debian/Ubuntu系列(执行)。
. /etc/os-release - DNS必须已指向目标设备。对比设备的公网IP(执行)与
curl -s ifconfig.me的结果(在设备和本地笔记本上分别执行)。如果两者不匹配,立即停止操作——Caddy的ACME验证会失败。请让用户创建A记录,等待DNS生效后再继续。dig +short <fqdn> - 端口80和443必须能从互联网访问。检查主机防火墙以及任何云安全组/网络防火墙(Hetzner Cloud、AWS安全组等)——这些位于设备外部,是常见的隐性障碍。
2. Install Docker (if absent)
2. 安装Docker(若未安装)
- Check and
docker --version. If missing, install Docker Engine + the Compose plugin (Docker's officialdocker compose versionscript on Ubuntu/Debian is fine). Re-checkget.docker.combefore proceeding.docker compose version
- 检查和
docker --version。若未安装,安装Docker Engine + Compose插件(Ubuntu/Debian系统可使用Docker官方的docker compose version脚本)。继续操作前请重新检查get.docker.com。docker compose version
3. Lay down the project
3. 部署项目
- Pick — an absolute path, e.g.
DATA_FOLDER. The/opt/n8nvalue inDATA_FOLDERmust equal this exact directory (the compose mounts.env, and${DATA_FOLDER}/caddy_config/Caddyfileis mounted via a relativeinit-data.shpath), so always run./from here. Create it, plusdocker composeandcaddy_config/inside.local_files/ - Get the template files onto the box. They live in this skill's on your machine, not on the server — transfer each one. Either
assets/them up, or (no local copy needed) write each file's contents over SSH, e.g.scp. Land them with these exact names:ssh <target> 'cat > <DATA_FOLDER>/docker-compose.yml' < assets/docker-compose.single.yml- the chosen compose → (rename it to exactly this)
<DATA_FOLDER>/docker-compose.yml - →
Caddyfile<DATA_FOLDER>/caddy_config/Caddyfile - queue only: →
init-data.sh, then<DATA_FOLDER>/init-data.shitchmod +x - the matching →
.env.*.example<DATA_FOLDER>/.env
- the chosen compose →
- 选择——绝对路径,例如
DATA_FOLDER。/opt/n8n文件中的.env值必须与该路径完全一致(Compose文件挂载DATA_FOLDER,${DATA_FOLDER}/caddy_config/Caddyfile通过相对路径init-data.sh挂载),因此请始终在该目录下执行./命令。创建该目录,并在其中创建docker compose和caddy_config/子目录。local_files/ - 将模板文件传输到目标设备。这些文件存放在本地的本技能目录中,而非服务器上——请逐个传输。可使用
assets/上传,或(无需本地副本)通过SSH写入文件内容,例如:scp。 文件命名必须完全一致: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文件 →
4. Fill .env
+ generate secrets
.env4. 填充.env
+ 生成密钥
.env- Set ,
DATA_FOLDER,DOMAIN_NAME,SUBDOMAIN,SSL_EMAIL.GENERIC_TIMEZONE - Generate each secret on the box with (
opensslhas the commands) and write it intoSECURITY.md, replacing the matching.envplaceholder:REPLACE_WITH_…; queue alsoN8N_ENCRYPTION_KEY+POSTGRES_PASSWORD.POSTGRES_NON_ROOT_PASSWORD - Before launching, confirm none are left unset: must return nothing — a leftover placeholder becomes the literal password and Postgres/n8n fail to connect.
grep REPLACE_WITH_ .env - . Record the encryption key so the user can back it up off-box.
chmod 600 .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 - 启动前请确认所有占位符已替换:执行应无输出——若残留占位符,它会被当作明文密码,导致Postgres/n8n无法连接。
grep REPLACE_WITH_ .env - 执行修改文件权限。记录加密密钥,以便用户备份到设备外。
chmod 600 .env
5. Firewall
5. 防火墙配置
- : allow OpenSSH + 80 + 443, then enable. Do not open 5678/5432/6379.
ufw
- 使用:允许OpenSSH + 80 + 443,然后启用防火墙。请勿开放5678/5432/6379端口。
ufw
6. Launch
6. 启动服务
- .
cd <DATA_FOLDER> && docker compose up -d - Queue mode brings up Redis + Postgres + main + workers (workers via ). To add capacity:
replicas.docker compose up -d --scale n8n-worker=N
- 执行。
cd <DATA_FOLDER> && docker compose up -d - 队列模式会启动Redis + Postgres + 主进程 + 工作节点(工作节点数量由指定)。如需扩容:执行
replicas。docker compose up -d --scale n8n-worker=N
7. Verify (don't declare success without this)
7. 验证(未完成验证请勿宣布部署成功)
- — every service
docker compose ps/healthy (queue: postgres & redisUpfirst).healthy - n8n itself up (internal): →
docker compose exec n8n wget -qO- http://localhost:5678/healthz. This separates "n8n is running" from "TLS isn't ready yet."{"status":"ok"} - Cert issued: . First-boot ACME can take a minute or two; until it finishes, a public
docker compose logs caddy | grep -i 'certificate obtained'request fails TLS — that means the cert is still pending, not that n8n is down.https:// - Public reachability (with retry): →
curl -fsS --retry 5 --retry-delay 10 https://<fqdn>/healthz. ({"status":"ok"}only proves the process is reachable;/healthzadditionally confirms the DB is connected and migrated — use it when debugging a boot loop.)/healthz/readiness - Open → the owner setup screen. Whoever completes that signup form first claims the instance — an exposed un-owned instance is a race, so create the owner account immediately, before sharing the URL. Enable 2FA. (Automated deploys can pre-provision the owner via env vars instead — see the owner row in
https://<fqdn>.)SECURITY.md
- 执行——所有服务状态应为
docker compose ps/healthy(队列模式:postgres和redis需先变为Up)。healthy - n8n内部服务正常运行:执行→ 返回
docker compose exec n8n wget -qO- http://localhost:5678/healthz。这可区分“n8n已运行”和“TLS尚未就绪”两种状态。{"status":"ok"} - 证书已颁发:执行。首次启动时ACME验证可能需要1-2分钟;在此之前,公网
docker compose logs caddy | grep -i 'certificate obtained'请求会TLS失败——这表示证书仍在申请中,并非n8n服务故障。https:// - 公网可达性(带重试):执行→ 返回
curl -fsS --retry 5 --retry-delay 10 https://<fqdn>/healthz。({"status":"ok"}仅验证进程可达;/healthz还会确认数据库已连接并完成迁移——调试启动循环时可使用该接口。)/healthz/readiness - 打开→ 进入所有者设置界面。第一个完成注册表单的用户将获得实例所有权——暴露的未归属实例存在被抢占的风险,因此请立即创建所有者账户,再分享URL。启用双因素认证(2FA)。(自动化部署可通过环境变量预配置所有者账户——详见
https://<fqdn>中的所有者相关内容。)SECURITY.md
8. Hand off
8. 交付
- Give the user: the URL, where the project lives, the encryption key to store safely, and the
Day-2 basics (update / backup / restore) from .
DAY2.md
- 向用户提供:访问URL、项目存储路径、需安全备份的加密密钥,以及****中的日常运维基础知识(更新/备份/恢复)。
DAY2.md
What NOT to do
禁止操作
- Don't skip the DNS/ports preflight. A wrong A record or a closed cloud firewall is the #1 reason Caddy can't get a cert and n8n looks "broken."
- Don't publish 5678/5432/6379 to the host. Caddy reaches n8n over the private network.
- Don't reuse another instance's encryption key or . Fresh secrets per box.
.env - Don't run queue mode on SQLite. Queue requires Postgres (the template already wires it).
- Don't put secrets in or the Caddyfile.
docker-compose.ymlonly..env - Don't use blindly. Pin
:latest; update deliberately (N8N_IMAGE_TAG).DAY2.md
- 请勿跳过DNS/端口预检。A记录错误或云防火墙未开放是导致Caddy无法获取证书、n8n看似“故障”的头号原因。
- 请勿将5678/5432/6379端口暴露到主机。Caddy通过私有网络访问n8n。
- 请勿复用其他实例的加密密钥或文件。每个设备需使用全新密钥。
.env - 请勿在SQLite上运行队列模式。队列模式需要Postgres(模板已配置)。
- 请勿将密钥写入或Caddyfile。密钥仅能存放在
docker-compose.yml中。.env - 请勿盲目使用标签。请固定
:latest;按计划更新(详见N8N_IMAGE_TAG)。DAY2.md
Reference files
参考文件
- — single-instance specifics, SQLite vs Postgres, when to graduate to queue.
SINGLE_MODE.md - — queue architecture, workers/concurrency/scaling, shared encryption key, binary data (
QUEUE_MODE.mdmode — filesystem is unsupported in queue mode; S3/Azure = Enterprise), webhook processors, multi-main licensing.database - — generating secrets, the encryption-key rules, the full hardening checklist (telemetry off, env-access block, public API, firewall, secure cookies).
SECURITY.md - — updating the image, backing up (encryption key + volume + Postgres), and restoring.
DAY2.md - — the templates:
assets/,docker-compose.single.yml,docker-compose.queue.yml,Caddyfile,.env.single.example,.env.queue.example.init-data.sh
Authoritative upstream reference: the official hosting docs live at
https://docs.n8n.io/deploy/host-n8n (restructured mid-2026 from the old paths —
prefer these URLs). The env-var reference index is at
https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables.
When this skill and the live docs disagree, trust the docs and tell the user.
/hosting/- — 单实例细节、SQLite与Postgres对比、何时升级到队列模式。
SINGLE_MODE.md - — 队列架构、工作节点/并发/扩展、共享加密密钥、二进制数据(
QUEUE_MODE.md模式——队列模式不支持文件系统;S3/Azure为企业版功能)、webhook处理器、多主进程许可。database - — 密钥生成、加密密钥规则、完整加固清单(关闭遥测、阻止环境变量访问、公网API、防火墙、安全Cookie)。
SECURITY.md - — 镜像更新、备份(加密密钥 + 卷 + Postgres)、恢复操作。
DAY2.md - — 模板文件:
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年年中从旧路径重构——请优先使用此URL)。环境变量参考索引位于https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables。若本技能与实时文档存在冲突,请以官方文档为准并告知用户。
/hosting/