Cloudflare Tunnel 连接 NAS 笔记
这篇记录如何在 NAS 上运行 cloudflared,把只监听内网的 Web 服务连接到 Cloudflare,再通过公开主机名和 Access 策略控制访问。
它适合 NAS 管理页、照片服务、下载面板等 HTTP/HTTPS 应用。教程采用 Cloudflare 控制台管理 Tunnel、Docker 运行连接器的方式,不涉及 WARP 私网路由,也不适合直接公开 SMB、数据库等不应暴露到浏览器的服务。
Cloudflare 控制台的菜单名称会随版本调整,操作时应以 Cloudflare Tunnel 官方文档 和当前界面为准。
先理解访问链路
cloudflared 从 NAS 主动向 Cloudflare 建立出站连接,因此路由器不需要转发公网入站端口,家庭宽带没有固定公网 IP 也能使用。Tunnel 本身只负责连接链路;如果没有 Access 策略,公开主机名仍然可以被互联网上的任何人访问。
这篇笔记使用以下占位值:
公开地址:https://nas.example.comTunnel 名称:nas-tunnelNAS 服务:http://127.0.0.1:5000Token 文件:/volume1/docker/cloudflared/tunnel-tokenexample.com 是文档保留域名,实际配置时需要替换成自己的域名。端口 5000 也只是示例,必须以 NAS 上服务的实际监听地址为准。
前提条件
- 域名已在 Cloudflare 中处于活动状态;
- NAS 或同一局域网中的 Linux 主机可以运行 Docker;
- 已确认目标是 HTTP 或 HTTPS Web 服务;
- 有权限创建 Cloudflare Tunnel、Access 应用和 DNS 记录;
- NAS 可以主动访问互联网,防火墙允许 Tunnel 所需的出站流量。
SSH 不是 Cloudflare Tunnel 的硬性要求。如果 NAS 的容器管理界面可以设置镜像、挂载文件、网络模式和启动命令,也可以全程通过图形界面操作。下面使用 SSH 和 Docker CLI,只是为了让步骤更容易复现。
1. 找到 NAS 服务的真实地址
先在 NAS 本机确认目标服务是否正常,不要一开始就把问题交给 Cloudflare。
Linux 主机优先使用 ss 查看监听端口:
sudo ss -tlnp已知端口后直接测试:
curl -v http://127.0.0.1:5000如果服务使用 HTTPS:
curl -vk https://127.0.0.1:5001这里需要记录三件事:
- 服务使用 HTTP 还是 HTTPS;
- 服务实际监听的 IP 和端口;
- HTTPS 证书对应的主机名,以及它是否由受信任 CA 签发。
群晖、QNAP 等产品有常见默认端口,但用户可以修改,应用套件也可能使用完全不同的端口。不要把品牌默认值当成实际配置。
2. 先创建 Access 保护
对于 NAS 管理页这类敏感入口,建议先创建 Access 应用,再发布 Tunnel 路由。否则从公开主机名生效到 Access 配置完成之间,服务会短暂暴露在互联网上。
当前控制台大致位于:
Zero Trust→ Access controls→ Applications→ Create new application→ Self-hosted and private→ Add public hostname公开主机名填写 nas.example.com。这一步保护的是浏览器访问的公开域名,不是 localhost、NAS 内网 IP 或 Tunnel 名称。
选择登录方式
新建 Zero Trust 组织通常会提供 Cloudflare 身份提供商。也可以接入 Google、GitHub 等身份提供商并启用 MFA。
如需使用邮箱一次性验证码,应先在身份提供商设置中添加 One-time PIN,再在 Allow 策略中限制到明确的邮箱地址或邮箱域。OTP 是一种登录方式,不等同于第二因素;只把“Login Methods: One-time PIN”作为允许条件,会让任何有效邮箱都有机会通过认证。
一个个人 NAS 的最小策略可以是:
| 项目 | 示例 |
|---|---|
| Action | Allow |
| Include | 指定邮箱地址 |
| Require | 指定登录方式或 MFA |
| Session duration | 按自己的风险接受程度设置 |
Access 应用默认拒绝未命中 Allow 策略的用户。保存后先确认应用主机名确实是 nas.example.com,避免保护了错误的地址。
3. 创建远程管理 Tunnel
进入 Cloudflare Tunnel 页面:
Zero Trust→ Networks→ Connectors→ Cloudflare Tunnels→ Create a tunnel选择 cloudflared,名称填写 nas-tunnel,运行环境选择 Docker。控制台会生成一条带 Tunnel token 的启动命令。
Tunnel token 等同于连接器凭据。拿到 token 的人可以启动这个 Tunnel 的副本,因此不要把它写进文章、截图、Git 仓库、Compose 文件或公开日志。怀疑泄露时应立即在控制台轮换 token。
4. 用 token 文件启动 cloudflared
官方镜像不会在容器内自动更新,因此容器启动参数保留 –no-autoupdate,更新时由 Docker 拉取新镜像并重建容器。
先创建仅管理员可读的 token 文件:
sudo install -d -m 700 /volume1/docker/cloudflaredsudo sh -c 'umask 077; printf "%s" "<YOUR_TUNNEL_TOKEN>" > /volume1/docker/cloudflared/tunnel-token'将 <YOUR_TUNNEL_TOKEN> 替换为控制台生成的实际值。不要在多人共享的终端中直接执行带真实 token 的命令,以免进入 shell 历史。
拉取镜像:
sudo docker pull cloudflare/cloudflared:latest然后启动容器:
sudo docker run -d \ --name cloudflared \ --restart unless-stopped \ --network host \ --mount type=bind,src=/volume1/docker/cloudflared/tunnel-token,dst=/run/secrets/tunnel-token,readonly \ cloudflare/cloudflared:latest \ tunnel --no-autoupdate run --token-file /run/secrets/tunnel-token为什么示例使用 host 网络
在普通 Docker bridge 网络中,容器里的 127.0.0.1 指向容器自己,不是 NAS 主机。示例使用 –network host,是为了让 cloudflared 可以访问 NAS 主机上的 127.0.0.1:5000。
host 网络会扩大容器可见的主机网络范围,并不是所有 NAS 平台都支持。若不使用 host 网络,可以把路由目标改成 NAS 的局域网地址,或者在平台支持时加入 host.docker.internal 映射。无论采用哪种方式,都要从 cloudflared 容器所在网络实际测试,不能默认 localhost 一定正确。
5. 确认 Tunnel 已连接
查看容器状态和日志:
sudo docker ps --filter name=cloudflaredsudo docker logs cloudflared --tail 100控制台中 Tunnel 应显示为 Healthy。日志格式会随 cloudflared 版本变化,不需要匹配某一整段固定文本;重点是没有持续出现 DNS、QUIC、HTTP/2 或认证错误。
Tunnel 使用出站连接访问 Cloudflare。防火墙受限时,需要允许 cloudflared 通过 TCP 和 UDP 端口 7844 连接 Cloudflare Tunnel 端点。QUIC 使用 UDP,HTTP/2 使用 TCP;默认配置会根据网络情况选择可用协议。
较新的版本还可以执行连接诊断:
sudo docker exec cloudflared cloudflared tunnel diag如果当前镜像不支持该命令,直接查看连接器日志和控制台状态即可。
6. 添加 Published application route
回到 nas-tunnel,打开 Published application routes 并添加公开主机名:
| 字段 | 示例 |
|---|---|
| Subdomain | nas |
| Domain | example.com |
| Service type | HTTP |
| Service URL | 127.0.0.1:5000 |
路由协议必须与 NAS 服务实际协议一致:
本地是 http://127.0.0.1:5000 → 路由选择 HTTP本地是 https://127.0.0.1:5001 → 路由选择 HTTPS保存公开主机名后,Cloudflare 全量 DNS 托管通常会自动创建指向 Tunnel 的代理记录。DNS 页面中可以看到对应主机名;不要再手工添加一条指向家庭公网 IP 的 A 记录。
7. HTTPS 源站与证书验证
浏览器到 Cloudflare 边缘始终使用公开地址的 HTTPS。这里讨论的 HTTP/HTTPS,指的是 cloudflared 到 NAS 本地服务这一段。
如果 NAS 本地 HTTPS 证书有效,优先保持证书验证,并在需要时设置 Origin Server Name,让 cloudflared 使用证书中的主机名验证源站。
如果使用自签名证书,更稳妥的处理顺序是:
- 为
cloudflared提供签发该证书的 CA; - 设置正确的 Origin Server Name;
- 只在无法完成前两项时临时启用 No TLS Verify。
No TLS Verify 会关闭 cloudflared 到源站这一段的证书校验,不应被当成默认修复方案。如果 NAS 与 cloudflared 位于同一受控主机,且本地服务本来就提供 HTTP,也可以直接使用 HTTP,避免无意义的自签名 TLS 排错。
8. Host 头只解决虚拟主机问题
HTTP Host Header 用来告诉源站“用户访问的是哪个主机名”。只有 NAS 的反向代理根据 Host 选择站点,或者默认主机返回了错误页面时,才需要在 Additional application settings 中覆盖 Host 头。
例如源站只接受 nas.internal.example:
HTTP Host Header: nas.internal.example不要把它统一填写成 localhost:端口。Host 头不能修复协议选错、端口错误、源站未运行或证书校验失败,也不会阻止正常的 HTTP 重定向。
9. 验证 Access 和 DNS
使用未登录 Cloudflare Access 的浏览器打开:
https://nas.example.com正确流程应当是:
- 先出现 Access 登录页;
- 只有命中 Allow 策略的身份才能继续;
- 认证成功后才显示 NAS 自身登录页;
- NAS 仍然保留自己的账号、密码和 MFA。
Access 不是 NAS 登录的替代品。两层认证使用不同密码或不同身份因子,可以减少单一凭据泄露带来的风险。
还可以在 Tunnel 路由中启用 Protect with Access,让 cloudflared 在转发前验证 Access JWT。官方也建议源站验证 Access token,以防其他错误路由绕过入口策略。
10. 按错误层级排查
1033:Cloudflare 找不到健康连接器
这表示问题在 Cloudflare 与 cloudflared 之间。检查:
- 容器是否正在运行;
- Tunnel token 是否有效;
- NAS DNS 是否能解析 Tunnel 端点;
- 出站 TCP/UDP 7844 是否被防火墙拦截;
- 控制台状态是 Inactive、Down 还是 Degraded。
502:连接器无法访问 NAS 服务
Tunnel 已经连接,但 cloudflared 到本地服务失败。检查:
sudo docker logs cloudflared --tail 100curl -v http://127.0.0.1:5000sudo ss -tlnp | grep 5000常见原因是服务未启动、端口不对、容器网络看不到主机,或者路由把 HTTP 与 HTTPS 写反。
TLS 握手或 x509 错误
first record does not look like a TLS handshake 通常表示把 HTTP 服务按 HTTPS 连接;x509 主机名或 CA 错误则表示协议已经是 HTTPS,但证书验证失败。先核对协议,再处理 Origin Server Name 或 CA,不要直接把所有 TLS 校验关闭。
重定向次数过多
用 curl -vkL 观察每一步 Location。检查 NAS 是否强制跳转到另一个端口、反向代理是否又跳回公开地址,以及 Origin Server Name 是否与证书匹配。Host 头只是其中一个可能因素。
Access 页面没有出现
立即检查 Access 应用绑定的是否为同一个公开主机名。公开路由存在而 Access 应用主机名写错时,服务可能处于未保护状态,应先暂停路由或停止连接器,再修正策略。
Docker 镜像更新
容器中的 cloudflared 不会自行替换镜像。更新前先阅读版本说明,再执行:
sudo docker pull cloudflare/cloudflared:latestsudo docker rm -f cloudflared然后使用原来的挂载、网络和启动参数重新创建容器。删除容器不会删除控制台中的 Tunnel,也不会删除主机上的 token 文件。
不建议教程直接覆盖 /etc/docker/daemon.json 来设置第三方镜像加速。不同 NAS 对 Docker 配置的管理方式不同,覆盖文件可能删除原有日志、存储或网络设置;镜像站本身也有可用性和供应链风险。确实无法访问 Docker Hub 时,应优先使用 NAS 厂商支持的代理配置或可信的内部镜像仓库。
安全检查
- 路由器没有为 NAS 管理端口保留公网端口转发;
- 公开主机名已经绑定 Access 应用和严格的 Allow 策略;
- 没有使用 Everyone 或仅 Login Methods 作为放行条件;
- NAS 自身账号启用了强密码和 MFA;
- 默认管理员账户已经停用或限制;
- Tunnel token 不在命令历史、截图、Git 和 Compose 文件中;
- NAS 系统、应用和
cloudflared镜像定期更新; - 不需要的厂商远程访问入口已经关闭;
- 对外只发布必要的 Web 服务,不发布 SMB、数据库或 Docker API;
- 定期检查 Access 审计日志和 Tunnel 连接器状态。
常用命令
# 查看连接器sudo docker ps --filter name=cloudflared
# 查看最近日志sudo docker logs cloudflared --tail 100
# 持续查看日志sudo docker logs -f cloudflared
# 重启连接器sudo docker restart cloudflared
# 查看监听端口sudo ss -tlnp
# 测试 HTTP 源站curl -v http://127.0.0.1:5000
# 测试 HTTPS 源站及跳转curl -vkL https://127.0.0.1:5001
# 查询公开主机名dig nas.example.com参考资料
- Cloudflare Tunnel 概览
- 发布受 Access 保护的自托管应用
- Tunnel 防火墙与出站端口
- Tunnel Origin 参数
- One-time PIN 登录
- Tunnel 常见故障排查
小结
Cloudflare Tunnel 解决的是“如何从内网主动连接 Cloudflare”,Access 解决的是“谁可以通过公开主机名继续访问”。两者需要一起配置,NAS 自身认证也不能省略。
实际排错时先分清三段链路:浏览器到 Cloudflare、Cloudflare 到 cloudflared、cloudflared 到 NAS 服务。1033、502、TLS 和 Access 错误分别属于不同层级,按层判断会比反复修改 Host 头或关闭证书验证更有效。