简介:N8N是GitHub上备受瞩目的开源自动化工作流工具,通过可视化编排界面即可连接Webhook、定时任务、数据库操作、邮件服务等常见节点,适用于企业内部流程自动化、IT运维与数据处理等复杂场景。压缩包内提供可直接运行的N8N本地部署源码,面向需要自主搭建自动化平台、摆脱云端限制的开发者与技术爱好者。资源包共4个文件、大小约12KB,包括Docker自动安装脚本(sh)、项目配置文件(inscode)、N8N功能导览页面(html)与Git忽略规则(gitignore),从环境准备、启动配置到部署验证均有覆盖,便于在Linux环境下快速完成本地部署。下载后可直接对照源码理解部署逻辑,也能基于此开展二次开发,深入掌握N8N的架构设计与扩展机制。已有207人学习下载,适合具备基础Linux操作能力、希望系统学习N8N部署与自动化工作流开发的读者。
1. N8N本地部署教程:为什么自托管才是n8n的正确打开方式
很多团队的 n8n 是从云端 SaaS 试水开始的,玩了两周发现流程跑起来了,但数据全在别人手里,想加一个内部系统的连接器要等官方排期,于是回头来找本地部署方案。这篇 N8N 本地部署教程把话说透:n8n 是一个基于 Node.js 的开源工作流自动化引擎,适合把内部系统、数据库、IM、邮件以及本地大模型 API 串成一条自动化链。自托管的意义不在于省那点订阅费,而在于流程、凭证和数据都归你控制,升级节奏、节点扩展、权限边界全部自己说了算。它适合开发者、运维,以及想把手头重复劳动沉淀成内部自动化平台的团队。下面按部署全链路走一遍,命令、参数、坑都在。
2. 部署前把账算清:三种跑 n8n 的方式与选型逻辑
2.1 Docker Compose、npm 与源码运行的真实差异
在动手之前,先回答一个最实际的问题:n8n 到底该怎么跑起来?常见做法有三种,我按生产环境的视角把它们放在一起对比过,结论比较明确。
| 部署方式 | 启动成本 | 升级与回滚 | 二次开发友好度 | 适合场景 |
|---|---|---|---|---|
| Docker Compose | 最低,一条命令拉起全家桶 | 镜像 tag 切换即可,回滚快 | 中,改代码需重建镜像或挂载自定义节点目录 | 绝大多数团队的首选 |
| npm 全局安装 | 需要 Node.js 20 LTS 环境 | npm 版本管理,依赖易漂移 | 中,可直接改源码目录但污染全局 | 已有 Node 运维体系、不想引入 Docker 的场景 |
| 源码 clone 运行 | 高,需要完整工具链 | 需手动管理 git 分支与 build | 最高,适合深度定制和贡献代码 | 需要改核心源码或自研节点的团队 |
从热词里能看出来,很多人搜“n8n企业级部署方案”“n8n下载”,说明大家跳过了选型这一步直接找安装包。但 n8n 的本地部署不是“装一个软件”那么简单,它背后是一套运行时、一个数据库、一组环境变量和凭证加密机制。Docker 方式把这些都封装好了,这也是我推荐绝大多数团队走 Docker 路线的原因。
有一类常见误用值得点名:拿 n8n 和扣子、dify、fastgpt 这类大模型应用编排平台比。它们不是同一层的东西。dify 解决的是“怎么把模型、知识库、Agent 串成 AI 应用”,n8n 解决的是“怎么把任意系统之间的事件流、数据流、定时任务粘起来”。你在本地部署了 deepseek 之后,想让它每天定时读数据库、生成摘要、推到企业微信,这才是 n8n 的活。定位搞清楚了,后面不会跑偏。
2.2 选 Docker 路线的三个理由与一条底线
第一个理由是可复现。docker-compose.yml 写进仓库,任何一台新机器docker compose up -d就能复现同样的环境,这对没有专职运维的团队是救命级的。第二个理由是升级成本。n8n 迭代很快,社区版功能持续更新,Docker 镜像换 tag 再 up 一次就完成升级,npm 全局安装则要面对 Node 版本、全局依赖、权限问题三个变量。第三个理由是隔离。n8n 的依赖链很长,直接装在宿主机上容易污染系统 Python 和 Node 环境,容器里随便折腾。
一条底线是:任何生产环境部署,必须显式设置N8N_ENCRYPTION_KEY。这个变量是 n8n 加密所有凭证(数据库密码、API Key、OAuth token)的机器密钥,不设置的话,每次容器重建都会生成一个新密钥,旧凭证全部解密失败。这是整个本地部署里最容易翻车、且翻车后几乎没有后悔药的点,后面避坑章节会专门展开。
如果 n8n 要暴露到公网,还要在部署前想清楚反向代理。常见做法是前置 Nginx 或 Caddy,此时必须同步设置三个环境变量:N8N_HOST(对外域名)、N8N_PROTOCOL(https)、WEBHOOK_URL(形如https://your.domain/)。不设置的话,webhook 回调地址和 OAuth 回调地址都会生成成内网 IP,外部系统根本访问不到。这个顺序应该是“先定域名和反代,再写 compose 文件”,而不是部署完再回头补。
3. 用 Docker Compose 跑通最小可运行实例:命令与参数逐个拆
3.1 目录结构、docker-compose.yml 与三个必配环境变量
我一般会把 n8n 的部署目录放在/opt/n8n下,目录结构固定成三件套:docker-compose.yml、.env、data/数据目录。先看最精简但可生产的 compose 文件。
services: n8n: image: docker.n8n.io/n8nio/n8n container_name: n8n restart: unless-stopped ports: - "5678:5678" environment: - GENERIC_TIMEZONE=Asia/Shanghai - TZ=Asia/Shanghai - N8N_DEFAULT_LOCALE=zh - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} - N8N_DIAGNOSTICS_ENABLED=false - N8N_PERSONALIZATION_ENABLED=false - WEBHOOK_URL=${WEBHOOK_URL} volumes: - ./data:/home/node/.n8n healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:5678/healthz || exit 1"] interval: 30s timeout: 5s retries: 3对应的.env文件:
N8N_ENCRYPTION_KEY=$(openssl rand -hex 16) WEBHOOK_URL=http://localhost:5678/逐个解释几个关键环境变量的作用。GENERIC_TIMEZONE控制的是 n8n 内部所有时间相关节点的时区,比如 Cron 触发器、Wait 节点,不设置就会按 UTC 跑,定时任务全部差 8 小时。N8N_DEFAULT_LOCALE=zh让界面语言直接是中文。N8N_DIAGNOSTICS_ENABLED和N8N_PERSONALIZATION_ENABLED关掉遥测与个性化引导,纯内网环境没外网时不会卡在初始化流程里。
N8N_ENCRYPTION_KEY必须写死在.env里,并且和生产环境隔离保存。openssl rand -hex 16生成的是一个 32 位十六进制字符串,足够作为 AES 加密密钥。注意这个值一旦投入使用就不能改,改了等于所有凭证作废。WEBHOOK_URL在初期可以先用http://localhost:5678/,等反代就绪后改成公网地址。
3.2 初始化账号、时区与语言:第一次打开前先做这三件事
docker compose up -d启动后,浏览器访问http://localhost:5678,第一次打开会让你创建管理员账号。这里我建议按三个步骤走,能避开大部分后续困扰。
第一步,确认容器时区生效。执行docker exec n8n date,如果输出的是北京时间而不是 UTC 时间,说明TZ变量生效了。GENERIC_TIMEZONE 和 TZ 是两个不同的东西:前者管 n8n 业务逻辑里的时间,后者管容器操作系统的时间,两个都要设。
第二步,创建完管理员账号后,进到设置 → 语言里确认界面语言。如果填了N8N_DEFAULT_LOCALE=zh但界面仍是英文,多半是初始化时还没来得及读到环境变量,刷新一次即可。这个问题很小,但会让团队里非技术的同事第一印象打折扣。
第三步,先别急着建工作流,先去设置 → 环境变量看一眼 n8n 自动生成的值。重点确认两件事:N8N_ENCRYPTION_KEY是否和.env里一致,WEBHOOK_URL是否是预期的对外地址。这一步很多人跳过,直到第一个 webhook 流程上线才发现地址不对,回头改环境变量要重启容器,所有运行中的流程全断一次。
3.3 升级、备份与恢复:n8n 数据的后悔药
n8n 的数据分成两部分:一部分是存在/home/node/.n8n下的 SQLite 数据库文件(工作流定义、凭证、执行历史),另一部分是N8N_ENCRYPTION_KEY这个密钥。备份时这两者是绑定的,缺了密钥,数据库备份就是一堆密文,恢复不回来。
升级操作本身很简单:
docker compose pull docker compose up -d但升级前必须先备份。我习惯用 n8n 自带的 CLI 导出功能,而不是直接拷贝数据库文件,因为导出的是结构化 JSON,跨版本兼容性更好。
# 在当前运行的容器里导出全部工作流和凭证 docker exec n8n n8n export:workflow --all --output=/home/node/.n8n/backup_workflows.json docker exec n8n n8n export:credentials --all --decrypted --output=/home/node/.n8n/backup_credentials.json # 把文件从容器里拷到宿主机 docker cp n8n:/home/node/.n8n/backup_workflows.json /opt/n8n/ docker cp n8n:/home/node/.n8n/backup_credentials.json /opt/n8n/注意 export 凭证时必须带--decrypted参数,否则导出的还是用机器密钥加密过的密文,换环境恢复时解不开。恢复到新环境用对应的 import 命令:
docker exec n8n n8n import:workflow --input=/home/node/.n8n/backup_workflows.json docker exec n8n n8n import:credentials --input=/home/node/.n8n/backup_credentials.json这套“先导出 JSON,再备份文件,最后才动 compose”的顺序,是我被线上环境升级搞挂过一次之后固定下来的流程。没有这套流程,升级就是开盲盒。
4. 从“能跑”到“可用”:credentials 管理、webhook 接入与源码部署
4.1 先理解 n8n credentials 的存储逻辑再连外部服务
很多人在 n8n 里配置第一个数据库连接或 API Key 时都遇到过“凭据保存了,但执行时提示 invalid credential”。要理解这个问题,得先知道 n8n credentials 的存储机制:所有凭证保存时用N8N_ENCRYPTION_KEY做 AES 加密,密文存在 SQLite 数据库里,读取时再用同一个密钥解密。
这就引出了三个实际结论。第一,密钥必须固定,这是反复强调的一点。第二,备份凭证时必须用--decrypted参数导出,否则换环境就是一堆密文。第三,如果你有多台 n8n 实例做高可用,所有实例必须使用同一个N8N_ENCRYPTION_KEY,否则 A 机器保存的凭证在 B 机器上全部解不开。
对于不想把第三方密钥写进 n8n 数据库的团队,n8n 支持环境变量注入凭证的方式。需要在环境变量里设置N8N_CREDENTIAL_PROVIDER=env,然后按规则定义凭证字段。这个做法适合把所有密钥统一收口到 Kubernetes Secret 或 .env 文件里统一管理,数据库里不落任何明文敏感信息。缺点是调试时不如 UI 配置直观,适合已经上了配置管理体系的团队使用。
4.2 用 webhook 节点接收内部系统事件:一个最小落地示例
本地部署最常见的需求是让 n8n 接收内部系统的事件推送,比如工单系统有新单、监控系统有告警。这一步用 webhook 节点实现,我拆成一个最小可复现的流程。
创建一个新工作流,添加一个 Webhook 节点,配置如下:
- HTTP Method:POST
- Path:
/internal/alert - 响应模式:使用“Respond to Webhook”节点返回内容
然后添加两个节点串起来:Webhook → Set 节点(格式化消息)→ Respond to Webhook。生产环境的 webhook 地址会自动生成http://localhost:5678/webhook/internal/alert,测试地址是http://localhost:5678/webhook-test/internal/alert。注意这两个地址前缀不同,一个带-test。
用 curl 做一次完整验证:
curl -X POST http://localhost:5678/webhook-test/internal/alert \ -H "Content-Type: application/json" \ -d '{"title": "磁盘告警", "level": "warning"}'如果流程配置正确,响应里会返回你在 Respond to Webhook 节点里设置的字段。测试通过后,把工作流从“测试”切换为“激活”状态,再改用不带-test的地址验证一次。很多人在这一步会踩坑,因为测试地址和正式地址的数据是隔离的,测试时跑通的流,激活后第一次请求仍然可能报错。
4.3 从源码跑 n8n:clone、build 与二次开发的边界
标题带了“可运行源码”,这里专门讲源码部署这条线。如果只是部署使用,Docker 镜像已经够了;需要从源码跑的人,通常是两类:要改 n8n 核心代码做定制,或者要自研节点并希望完整调试。
源码部署的步骤比较固定。先确认环境:Node.js 20 LTS、npm 9+、Python3 和 C++ 构建工具链(node-gyp 依赖),然后 clone 官方仓库并安装依赖。
git clone https://github.com/n8n-io/n8n.git cd n8n npm install安装依赖是这个方案里最慢也最容易出问题的一步。n8n 的依赖树很深,几百个包编译下来需要十几分钟,中途网络抖动就容易失败。建议用npm ci代替npm install,它会严格按 lock 文件安装,不引入版本漂移。构建并启动:
npm run build:backend npm run build:frontend npm run start源码跑起来后访问的还是 5678 端口,使用方式和 Docker 版一致。但要明确一个边界:直接改 core 代码的维护成本非常高,每次上游更新都要 rebase。我一般建议更轻量的二次开发路径:把自定义节点放在~/.n8n/custom/目录下,n8n 会自动加载,不需要 fork 整个仓库。这样既能扩展 n8n 的能力,又不卷入上游代码的合并地狱。
5. N8N 本地部署避坑清单:5 条来自生产环境的踩坑记录
5.1 现象:容器一启动就退出,日志只有一行报错
docker compose up -d之后容器秒退,docker logs n8n只有一行类似EACCES: permission denied的错误,宿主机目录./data的属主看起来是 root。
原因:n8n 镜像内以node用户运行,UID 是 1000,宿主机挂载的数据目录属主不匹配时,进程没有写权限。这是挂载卷最常见的坑。
解决:把数据目录的属主改成 UID 1000,而不是随手chmod 777。
chown -R 1000:1000 /opt/n8n/data docker compose up -d5.2 现象:升级后所有 credentials 全部解密失败
升级镜像版本后,之前配置的所有数据库连接、API Key 全部报 invalid credential,重新保存一次又能用,但下次升级又坏。
原因:.env里没有显式设置N8N_ENCRYPTION_KEY,容器重建时生成了一个新的随机密钥,旧数据在新密钥下全部解不开。这是本地部署里最隐蔽的黑匣子,因为升级前所有流程都是好的。
解决:把密钥写死进.env,并确保升级前后是同一个值。
# 生成一次并永久保存,不要重新生成 openssl rand -hex 165.3 现象:定时任务总是差 8 小时触发
Cron 节点配置的是每天 8 点执行,实际 16 点才跑,流程本身没有报错。
原因:容器时区默认 UTC,GENERIC_TIMEZONE未设置,n8n 的时间节点全走 UTC。同时注意,Cron 节点所在的工作流必须处于“激活”状态才会触发,很多人排查半天时区问题,结果只是流程没激活。
解决:在 compose 里同时设置GENERIC_TIMEZONE=Asia/Shanghai和TZ=Asia/Shanghai,重启容器后到“执行日志”里查看下一次计划触发时间是否正确。
5.4 现象:webhook 测试地址正常,生产地址 404
/webhook-test/前缀的测试地址能通,切换成/webhook/正式地址返回 404。
原因有三类,按概率排:工作流没激活(测试态和生产态的触发机制是独立的);反代后WEBHOOK_URL没设置或指向了内网地址;路径复制时漏掉或重复了前缀。第一类最常见。
解决:先把工作流激活,再用完整路径http://host/webhook/internal/alert访问;确认反代配置里把/webhook/和/webhook-test/两个路径都转发到了 5678 端口。
5.5 现象:源码部署的 npm install 反复失败
从源码安装依赖时,卡在 node-gyp 编译阶段报错,或者npm error code EINTEGRITY,重试还是失败。
原因:Node 版本不兼容(比如用了 Node 18 以下的版本),或者环境缺少编译工具链。n8n 的依赖里有需要原生编译的包,python3、make、g++缺一不可。
解决:锁死 Node 20 LTS,装齐编译工具后再装依赖。
nvm install 20 nvm use 20 # Ubuntu/Debian 系统先装编译工具链 apt install -y python3 make g++6. 把部署固化成标准动作:健康检查、密钥迁移与备份脚本
最后这部分,我把自己反复用的部署收尾流程整理成一个脚本,新环境直接跑,省掉所有手工步骤。它的核心不是“一键启动”,而是把密钥持久化、健康检查、备份出口一次性固化。
#!/usr/bin/env bash set -euo pipefail # 首次部署时生成并保存加密密钥,绝不允许每次生成新的 if [ ! -f /opt/n8n/.env ]; then echo "N8N_ENCRYPTION_KEY=$(openssl rand -hex 16)" > /opt/n8n/.env echo "WEBHOOK_URL=http://localhost:5678/" >> /opt/n8n/.env fi cd /opt/n8n docker compose up -d # 等待健康检查通过,最多重试 10 次 for i in $(seq 1 10); do if docker compose ps n8n | grep -q "healthy"; then echo "n8n is healthy" exit 0 fi sleep 3 done echo "health check timeout, check docker logs n8n" exit 1脚本里有两点是实战沉淀。第一,.env只在不存在时生成,防止覆盖已有密钥;第二,等待健康检查而不是直接 sleep 固定时间,镜像冷启动在慢盘机器上可能超过 30 秒,固定等待容易误判失败。
部署完成后,最后验证一件事:执行一次n8n export:credentials --all --decrypted,把导出内容放回.env旁边存档。这一步的意义是确认“当前配置的密钥能正确解密所有存量凭证”,验证通过才算部署闭环。很多团队部署完只看服务能打开界面,等第一个连接器配好才发现密钥对不上,那时已经浪费半天了。
我给自己定了一条规矩:任何一次部署不带明文N8N_ENCRYPTION_KEY就不算生产环境,新环境的第一个动作永远是先把密钥落进.env,再谈其他配置。这套流程从最初的手工敲命令到现在的脚本固化,帮团队省下的排障时间远大于写脚本的成本。希望帮到你。
本文还有配套的精品资源,点击获取