这类工具最值得先看的不是功能列表,而是能不能在普通环境里稳定跑起来,以及从本地到外网访问的链路能不能走通。n8n 作为一个开源的工作流自动化平台,很多人想把它部署在本地服务器或家用电脑上,但问题往往出在最后一步——如何让外网安全地访问到它。直接暴露端口风险太高,用传统的云服务器做跳转又需要额外成本。Cloudflare Tunnel 提供了一种免费、相对安全的内网穿透方案,正好能解决这个痛点。
我建议先从最小样例开始。整个流程可以拆成三步:在本地把 n8n 用 Docker Compose 跑起来、配置 Cloudflare Zero Trust 账号并创建隧道、最后把隧道指向本地的 n8n 服务。这里最容易忽略的是路径和权限,尤其是 Docker 容器网络、Cloudflare 的令牌权限以及本地防火墙设置。下面按实际落地顺序拆一遍,重点讲清楚每个环节的判断标准和常见坑点。
1. 先理清本地部署 n8n 的核心依赖和前置条件
在考虑内网穿透之前,必须确保 n8n 在本地环境能独立、稳定地运行。很多人一上来就折腾隧道配置,结果发现本地服务都没起来,排查方向就错了。
1.1 环境准备:Docker 与 Docker Compose 的版本确认
n8n 官方推荐使用 Docker 部署,这是为了隔离环境依赖,避免和系统已有的 Node.js 或数据库冲突。你需要的是 Docker Engine 和 Docker Compose 插件(或独立的 docker-compose 工具)。
首先,别急着拉镜像,先确认基础环境:
# 检查 Docker 服务状态和版本 docker --version sudo systemctl status docker # 对于 Linux 系统,确保服务是 active (running) # 检查 Docker Compose 可用性 docker compose version # 如果上述命令报错,尝试旧版命令 docker-compose --version关键点在于docker compose version这个命令。在较新的 Docker 安装中,compose是作为一个插件(Plugin)存在的,命令是docker compose(中间有空格)。如果你看到docker: ‘compose‘ is not a docker command.这类错误,说明可能需要单独安装docker-compose这个二进制文件,或者你的 Docker 版本太旧。对于 Ubuntu/Debian 系统,可以通过apt install docker-compose-plugin来安装插件。版本号建议在 v2.0 以上。
1.2 编写最小化的 docker-compose.yml 文件
不要直接使用过于复杂的生产配置。先用一个最简配置把服务拉起来,验证核心功能。下面是一个专注于“能跑通”的配置:
version: ‘3.8‘ services: n8n: image: n8nio/n8n:latest container_name: n8n_app restart: unless-stopped ports: - "5678:5678" # n8n 默认的 Web 界面和 API 端口 environment: - N8N_PROTOCOL=http - N8N_HOST=localhost - N8N_PORT=5678 - N8N_EDITOR_BASE_URL=http://localhost:5678/ - WEBHOOK_URL=http://localhost:5678/ - GENERIC_TIMEZONE=Asia/Shanghai # 数据库配置:先使用内置的 SQLite,简化初次部署 - DB_TYPE=sqlite - DB_SQLITE_DATABASE=/home/node/.n8n/database.sqlite volumes: - n8n_data:/home/node/.n8n networks: - n8n_network volumes: n8n_data: networks: n8n_network: driver: bridge这个配置做了几件事:
- 端口映射:将容器内的 5678 端口映射到宿主机的 5678 端口。这意味着你在本地浏览器访问
http://localhost:5678就能看到 n8n 界面。 - 数据持久化:通过命名卷
n8n_data将 n8n 的工作流、凭证等数据保存在 Docker 管理的数据卷中,即使容器删除,数据也不会丢失。 - 使用 SQLite:对于初次部署和测试,内置 SQLite 数据库完全足够,避免了额外部署 PostgreSQL 或 MySQL 的复杂度。生产环境再考虑迁移。
- 设置时区:
GENERIC_TIMEZONE环境变量让 n8n 内部任务调度使用东八区时间。
把上面的内容保存为docker-compose.yml,然后在同一目录下执行:
docker compose up -d命令中的-d是让容器在后台运行。如果一切正常,你会看到类似[+] Running 2/2的提示,并且容器状态为Up。
1.3 验证本地服务状态与常见启动问题
启动后,不要假设它一定成功了。按顺序做下面几个检查:
检查容器状态:
docker compose ps应该看到
n8n_app服务的状态是Up。如果状态是Exit或Restarting,就需要查看日志。查看启动日志:
docker compose logs n8n重点关注日志末尾。成功的启动日志会包含
Server is running on http://0.0.0.0:5678这样的信息。常见的启动失败原因有:- 端口冲突:宿主机 5678 端口已被其他程序占用。可以改用其他端口,如
- "5679:5678"。 - 权限问题:Docker 守护进程没有权限创建或写入卷。在 Linux 上,可能需要用
sudo运行,或者将当前用户加入docker用户组。 - 镜像拉取失败:网络问题导致无法拉取
n8nio/n8n:latest镜像。可以尝试配置 Docker 镜像加速器。
- 端口冲突:宿主机 5678 端口已被其他程序占用。可以改用其他端口,如
访问 Web 界面: 在本地机器的浏览器中打开
http://localhost:5678。你应该能看到 n8n 的注册/登录界面。如果能打开,说明本地部署成功。
注意:如果本地都访问不了,那么内网穿透配置得再完美也无济于事。务必先确保这一步是通的。
2. 理解 Cloudflare Tunnel 的原理与账号准备
本地服务通了,接下来是打通内网到公网的通道。Cloudflare Tunnel(以前叫 Argo Tunnel)的原理是在你的本地网络和 Cloudflare 的边缘网络之间建立一个加密的、出站(outbound-only)的连接。因为连接是由本地发起的,所以你不需要在路由器上设置端口转发,也不需要公有 IP,防火墙通常也不会阻挡。
2.1 为什么选择 Cloudflare Tunnel 而不是其他工具?
对比一下常见的方案:
- Ngrok:非常方便,但免费版有域名随机、连接时长和带宽限制。
- frp:需要自己有一台有公网 IP 的 VPS 作为服务端,配置稍复杂,但可控性强。
- Cpolar:国内类似 Ngrok 的服务,免费版也有限制。
- Cloudflare Tunnel:完全免费,不限流量(但有合理使用政策),可以使用你自己的域名,连接稳定,且集成在 Cloudflare 的安全生态中(Zero Trust)。
对于 n8n 这种可能需要长期运行、偶尔从外网访问的服务,Cloudflare Tunnel 在免费、稳定和安全性上是一个不错的平衡点。它的核心组件是cloudflared这个守护进程,运行在你的本地环境,负责建立和维护隧道。
2.2 注册 Cloudflare 并添加域名
这是必要的前置条件:
- 访问 Cloudflare 官网注册一个免费账户。
- 你需要拥有一个自己的域名(例如
yourdomain.com)。在 Cloudflare 控制台添加这个域名,并按照指引将其 DNS 服务器切换到 Cloudflare 提供的地址。这个过程可能需要几分钟到几小时生效。 - 域名在 Cloudflare 上状态变为“有效”后,进入Zero Trust面板(以前叫 Teams)。这是配置 Tunnel 的地方。
注意:Cloudflare 的 Zero Trust 功能有免费套餐,足够个人和小团队使用。确保你的账号能访问 Zero Trust 面板。
2.3 在 Zero Trust 中创建隧道并获取连接凭证
- 在 Zero Trust 面板,导航到Access->Tunnels。
- 点击Create a tunnel。给隧道起个名字,比如
n8n-tunnel。 - 选择连接器类型为Docker。页面上会显示一个 Docker 运行命令,其中包含一个长长的令牌(Token),格式类似
docker run cloudflare/cloudflared tunnel --no-autoupdate run --token eyJ...。这个令牌是关键,它授权你的本地cloudflared实例连接到 Cloudflare 并归属到这个隧道。 - 非常重要:先不要关闭这个页面,也不要急着运行命令。先把令牌复制并安全地保存下来(例如保存在本地的
credentials.txt文件)。页面上的 Docker 运行命令是通用示例,我们需要将它整合到我们的docker-compose.yml中,而不是单独运行。
3. 将 Cloudflare Tunnel 集成到 Docker Compose 环境
我们的目标不是单独运行一个cloudflared容器,而是让它和 n8n 容器在同一个 Docker 网络里,并能将流量代理到 n8n 服务。这样更便于管理。
3.1 修改 docker-compose.yml 以包含 cloudflared
更新你的docker-compose.yml文件,添加cloudflared服务:
version: ‘3.8‘ services: n8n: image: n8nio/n8n:latest container_name: n8n_app restart: unless-stopped # 注意:我们不再需要将端口映射到宿主机,因为外部访问将通过 Cloudflare Tunnel # ports: # - "5678:5678" environment: - N8N_PROTOCOL=http - N8N_HOST=n8n_app # 改为容器名,供 cloudflared 内部访问 - N8N_PORT=5678 - N8N_EDITOR_BASE_URL=https://n8n.yourdomain.com # 必须改为你的隧道公网地址 - WEBHOOK_URL=https://n8n.yourdomain.com # 必须改为你的隧道公网地址 - GENERIC_TIMEZONE=Asia/Shanghai - DB_TYPE=sqlite - DB_SQLITE_DATABASE=/home/node/.n8n/database.sqlite volumes: - n8n_data:/home/node/.n8n networks: - n8n_network cloudflared: image: cloudflare/cloudflared:latest container_name: n8n_tunnel restart: unless-stopped command: tunnel --no-autoupdate run --token ${CLOUDFLARED_TOKEN} # 从环境变量读取令牌 environment: - CLOUDFLARED_TOKEN=${CLOUDFLARED_TOKEN} # 令牌通过外部环境文件传入,更安全 networks: - n8n_network depends_on: - n8n volumes: n8n_data: networks: n8n_network: driver: bridge关键改动解析:
- 注释掉 n8n 的
ports映射:既然不走宿主机的端口映射,我们可以移除它,让服务完全在 Docker 内部网络运行,更安全。 - 修改 n8n 的环境变量:
N8N_HOST: 从localhost改为n8n_app(n8n 容器的服务名)。这样,在 Docker 网络内部,cloudflared容器可以通过http://n8n_app:5678访问到 n8n 服务。N8N_EDITOR_BASE_URL和WEBHOOK_URL:这是至关重要的一步。必须将它们设置为你的隧道将要使用的公网 HTTPS 地址(例如https://n8n.yourdomain.com)。因为 n8n 生成工作流 URL 或 Webhook URL 时,会基于这个变量。如果这里还是localhost,那么从外网访问时,链接会指向错误的地方。
- 新增
cloudflared服务:- 使用官方镜像。
command指定了运行隧道的命令,并引用了环境变量CLOUDFLARED_TOKEN。depends_on: 确保cloudflared在n8n服务启动之后才启动。- 它们共享
n8n_network,使得容器间可以互相通信。
3.2 安全地管理 Cloudflare Token
把 Token 直接写在docker-compose.yml里是不安全的,特别是如果你要把文件提交到 Git。标准的做法是使用环境变量文件。
- 在
docker-compose.yml同目录下,创建一个名为.env的文件(注意开头有个点)。 - 在
.env文件中写入:CLOUDFLARED_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...(你的完整Token) - 确保
.env文件被添加到.gitignore中,避免泄露。
Docker Compose 会自动读取同目录下的.env文件,并将其中的变量注入到服务环境中。
3.3 配置隧道公网域名(CNAME 记录)
回到 Cloudflare Zero Trust 的 Tunnels 页面,找到你刚才创建的隧道(n8n-tunnel)。
- 在隧道详情页,点击Configure(配置)你的隧道。
- 在Public Hostnames(公共主机名)标签页下,点击Add a public hostname。
- 进行如下配置:
- Subdomain: 输入
n8n(或其他你喜欢的子域名) - Domain: 选择你在 Cloudflare 上托管的域名(如
yourdomain.com) - Path: 留空(表示根路径)
- Service: 选择HTTP
- URL: 输入
http://n8n_app:5678(注意:这里填的是 Docker 内部地址和端口,不是 localhost:5678)
- Subdomain: 输入
- 点击Save hostname。
配置完成后,Cloudflare 会自动为你创建一条CNAME记录,将n8n.yourdomain.com指向你的隧道地址(形如xxxxx.trycloudflare.com)。这个过程是瞬间完成的。
4. 启动、验证与排错全流程
所有配置完成后,现在是启动和验证的时候了。
4.1 启动复合服务栈
在包含docker-compose.yml和.env文件的目录下,运行:
docker compose up -d这次会启动两个服务:n8n_app和n8n_tunnel。使用docker compose ps检查两者状态是否都为Up。
4.2 验证隧道连接与公网访问
查看隧道日志:
docker compose logs cloudflared关注日志输出。成功的连接会显示
Registered tunnel connection、Connection X registered等信息,并且没有持续的报错。如果看到ERR Failed to connect to edge或permission denied,通常是 Token 无效或网络问题。验证公网访问: 在任何能上互联网的设备上(比如你的手机,关闭 WiFi 用蜂窝数据),打开浏览器,访问
https://n8n.yourdomain.com。- 成功:你应该看到和本地
localhost:5678一样的 n8n 登录界面。Cloudflare 会自动提供 HTTPS 证书,地址栏会有锁标志。 - 失败:如果看到 Cloudflare 的
502 Bad Gateway、1033 Error或隧道未连接等错误页面,说明隧道没有正确代理到后端服务。
- 成功:你应该看到和本地
4.3 系统性排错指南
如果公网访问失败,不要盲目重试。按照以下顺序排查:
第一步:检查本地 n8n 服务是否健康在宿主机上,执行docker compose exec n8n curl -s http://localhost:5678/healthz(如果 n8n 有健康检查端点)或者直接docker compose logs n8n查看 n8n 容器是否在正常运行并监听端口。确保 n8n 本身没问题。
第二步:检查 Docker 内部网络连通性进入cloudflared容器内部,测试是否能访问到 n8n 服务:
docker compose exec cloudflared /bin/sh # 进入容器后执行 curl -v http://n8n_app:5678如果这里curl失败(超时或连接拒绝),说明 Docker 网络配置有问题,或者 n8n 服务没有在5678端口监听。检查docker-compose.yml中的网络定义和服务名称。
第三步:检查 Cloudflare Tunnel 配置登录 Cloudflare Zero Trust 面板,进入你的隧道:
- 检查Connectors状态,应该有一个连接器在线(显示为绿色)。
- 检查Public Hostnames配置,确认 URL 字段确实是
http://n8n_app:5678,并且没有拼写错误。 - 检查 Cloudflare 域名管理的DNS页面,确认
n8n.yourdomain.com的 CNAME 记录已正确创建并生效(灰色云朵图标应为橙色,表示流量经过代理)。
第四步:检查环境变量与 Token
- 确认
.env文件中的CLOUDFLARED_TOKEN完整且正确,没有多余空格或换行。 - 可以运行
docker compose exec cloudflared printenv CLOUDFLARED_TOKEN来验证容器内环境变量是否已正确设置。 - Token 过期或失效?在 Zero Trust 面板的隧道设置中,可以Rotate(轮转)Token,生成一个新的,然后更新你的
.env文件并重启服务docker compose restart cloudflared。
第五步:检查防火墙与出站连接虽然 Cloudflare Tunnel 是出站连接,但某些严格的网络环境(如公司网络)可能会限制出站连接到特定端口。cloudflared默认使用 7844 等端口与 Cloudflare 通信。确保你的本地网络允许这些出站连接。
4.4 配置 n8n 的 Webhook 与外部触发
这是部署 n8n 的最终目的。由于我们使用了隧道,Webhook URL 必须是公网可访问的。
- 在 n8n 中创建一个 Webhook 触发节点。
- 生成的 Webhook URL 将会是
https://n8n.yourdomain.com/webhook/xxxxx格式。这个 URL 可以被其他互联网服务(如 GitHub、Slack、飞书机器人等)调用。 - 测试这个 Webhook:你可以使用
curl或 Postman 向这个 URL 发送一个 POST 请求,看看 n8n 工作流是否能被触发。curl -X POST https://n8n.yourdomain.com/webhook/your-webhook-path -H “Content-Type: application/json“ -d ‘{“test“: “value“}‘
5. 生产环境考量与长期维护建议
把服务跑起来只是第一步。如果要长期、稳定地使用,还需要考虑以下几个问题。
5.1 数据持久化与备份
我们使用了 Docker 卷n8n_data。你可以找到这个卷在宿主机上的实际位置进行备份:
# 查找卷的实际路径 docker volume inspect n8n_n8n_data | grep “Mountpoint“定期备份这个目录下的所有文件。更稳妥的做法是将数据库从 SQLite 迁移到 PostgreSQL,并配置数据库的定期备份策略。
5.2 安全性加固
- n8n 身份验证:务必在 n8n 的设置中启用用户认证,设置强密码,不要使用默认凭证。
- Cloudflare Zero Trust 策略:Cloudflare Access 可以让你在隧道入口设置额外的安全策略,例如要求使用特定邮箱登录、要求来自特定国家 IP 等。这对于保护管理界面非常有用。
- 限制公开访问:如果 n8n 只是你自己管理,可以考虑不设置 Public Hostname,而是通过 Cloudflare WARP 客户端和 Zero Trust 规则,只允许你自己的设备接入专用网络后访问,实现真正的“零信任”内网访问。
- 保持更新:定期更新
n8n和cloudflared的 Docker 镜像到最新版本,以获取安全补丁。
5.3 监控与日志
- 日志收集:使用
docker compose logs -f n8n cloudflared可以实时查看日志。对于生产环境,建议将容器日志导出到集中式日志系统(如 Loki、ELK)。 - 健康检查:可以在
docker-compose.yml中为服务添加healthcheck配置,让 Docker 能监控服务健康状态。 - 资源监控:使用
docker stats或cAdvisor、Prometheus等工具监控容器 CPU、内存使用情况。
5.4 性能与扩展
- 资源限制:在
docker-compose.yml中为服务设置deploy.resources.limits,防止单个容器占用过多资源影响宿主机。 - 高可用考虑:单点部署有风险。对于关键业务,可以考虑在多个宿主机上部署 n8n 实例,前面用负载均衡器,或者探索 n8n 的企业版高可用方案。
- 工作流优化:复杂的、长时间运行的工作流可能会阻塞 n8n 实例。合理使用队列、定时触发和错误处理机制。
我个人更建议先把单任务跑稳,再考虑批量和接口。这个方案真正落地时,最该盯住的不是功能列表,而是输入格式、资源占用和失败重试。踩过几次之后我发现,很多问题不是工具能力不够,而是前置环境和输入材料没有处理干净。对于 n8n 加 Cloudflare Tunnel 这个组合,成功的关键就在于三处配置:n8n 容器内的BASE_URL、隧道配置中的Service URL,以及 Docker 内部网络的连通性。把这三点对齐,剩下的就是按部就班的启动和验证了。