用 Cloudflare Tunnel 访问随身 NAS 上的 Gitea
我把 Gitea 跑在一台 ARM64 的随身 NAS 上。带着 NAS 换 Wi-Fi 时,路由器分配的地址可能会变,但我希望电脑上配置的 Git 地址一直能用。这次用 Cloudflare Tunnel 给 Gitea 接了一个固定的 HTTPS 入口。NAS 上的 cloudflared 主动连接 Cloudflare,路由器无需做入站端口转发。
下文使用示例域名和路径。离线导入部分给出可复用的命令,验收结果以本次部署实际打开的公网页面为准。
1. 把域名解析迁到 Cloudflare
在 Cloudflare 添加已有域名 example.com,选择 Free,检查扫描出来的 DNS 记录。迁移的是权威 DNS 托管,域名仍在原注册商续费。以已注册的 .cn 域名为例,只要注册商允许更换名称服务器,就可以接入 Cloudflare DNS。
先核对旧解析里的网站记录和邮件记录,再去注册商后台替换名称服务器。自动扫描可能漏掉 DKIM 等记录。如果域名在用 Fastmail,把原有 MX、SPF、DKIM 和已设的 DMARC 一起迁入。MX 保留服务商给出的目标及优先级,DKIM 的 CNAME 设为 DNS only,并关闭 Flatten。DKIM 的目标应复制邮件服务商给出的值,填成 MX 服务器会一直验证失败。若原域名启用了 DNSSEC,按迁移指南处理旧 DS 记录和缓存,再更换 NS。
把注册商处的 NS 改成 Cloudflare 分配的两条,等域名显示 Active。可用下面的命令核对公网 NS,随后到邮箱后台重查 DNS,并测试收发信。
nslookup -type=ns example.com 1.1.1.1
Cloudflare 完整接入指南 · Fastmail 的 Cloudflare 配置
2. 创建 Tunnel,准备 ARM64 镜像
在 Cloudflare 控制台打开 Networking → Tunnels → Create Tunnel,取名 gitea。在安装连接器时选择 Docker,从生成的命令中取出 --token 后面的值。以后需要重新查看安装命令,可以进该隧道的 Add a replica。Tunnel Token 能让持有者运行连接器,保存时避开仓库、日志和截图。Cloudflare Tunnel 快速开始 · Tunnel Token 文档
极空间在创建容器时提示镜像与 ARM 架构不兼容。对 64 位 ARM 的 NAS,可以选 Cloudflare 官方的 latest-arm64 标签。如果 NAS 能直接下载,在镜像仓库选该标签即可。如果 NAS 访问镜像仓库不稳定,在另一台可访问 Docker Hub 的电脑上执行下面三行。电脑可以是 x86-64,目标平台由 --platform 指定。
docker pull --platform linux/arm64 cloudflare/cloudflared:latest-arm64
docker image inspect --format '{{.Os}}/{{.Architecture}}' cloudflare/cloudflared:latest-arm64
docker save -o cloudflared-arm64.tar cloudflare/cloudflared:latest-arm64
第二行应输出 linux/arm64。把 cloudflared-arm64.tar 复制到 NAS,在极空间 Docker → 镜像 中选择本地导入镜像文件,导入完成后确认列表里有 cloudflare/cloudflared:latest-arm64。如果通过 NAS 的 SSH 操作,可在 tar 所在目录运行:
docker load -i cloudflared-arm64.tar
docker load 会还原用 docker save 打包的镜像及标签。这个 tar 只包含镜像,容器设置和 Tunnel Token 由后续步骤填入。官方镜像标签 · Docker 镜像命令
3. 用正确镜像重新创建容器
从导入的 ARM64 镜像创建 cloudflared 容器。我的配置如下。
| NAS 容器设置 | 填法 |
|---|---|
| 镜像 | cloudflare/cloudflared:latest-arm64 |
| 网络 | Docker 默认桥接网络 bridge |
| 命令 | tunnel --no-autoupdate run,入口点使用镜像默认值 |
| 环境 | 名称 TUNNEL_TOKEN,值为 Tunnel 安装命令中的完整令牌 |
| 端口 | 留空 |
| 开机自启 | 开启 |
如果之前用错了镜像,可以先停止原来的连接器,再用导入的镜像重新创建。界面提供「应用并重建」时,可用该入口应用环境变量或命令变更。启动后在日志中找 Registered tunnel connection,在 Cloudflare 控制台确认隧道显示 Healthy。连不上时也要检查 NAS 到 Cloudflare 的出站 7844 是否可用。Cloudflare 隧道防火墙说明
我第一次把环境变量写成了小写 token。容器随即反复退出,日志要求提供隧道 ID 或名称。改成 TUNNEL_TOKEN 后,连接器能读到令牌。也可以用 tunnel --no-autoupdate run --token <TUNNEL_TOKEN>,把令牌作为命令行参数传入。两种写法选一种即可。启动参数文档
4. 配置 Tunnel 回源,解决 502
Gitea 在 NAS 上以 Host 网络运行,HTTP 监听 0.0.0.0:3000。先在局域网打开 http://192.168.50.10:3000/ 测试,其中 192.168.50.10 是示例 NAS 地址。有旧容器时,先确认数据挂载,再备份并停止旧实例。我这次的两个 Compose 项目共用 /data,其中存放 SQLite、仓库和 LFS,因此切换期间只运行一套。
在 Gitea Compose 的 environment 中把对外地址设为 HTTPS,保存后重建 Gitea 容器应用配置。它仍在本机使用 HTTP 端口 3000。
environment:
- GITEA__server__ROOT_URL=https://git.example.com/
- GITEA__server__HTTP_PORT=3000
在 Cloudflare 打开刚建的隧道,进入 Routes → Add route → Published application。子域填 git,域选 example.com,路径留空。Service URL 填 http://172.17.0.1:3000。这里的 172.17.0.1 是本次部署中 Docker 网桥的宿主机地址。在自己的 NAS 上,从 cloudflared 容器详情的「网络」页确认 IPv4 网关,再填写实际值。完整 DNS 接入下,Cloudflare 会为已发布应用创建相应的 DNS 记录。
最初填的是 http://localhost:3000,浏览器返回 502。Gitea 的 Host 模式只对它自己的容器生效。对桥接模式下的 cloudflared 来说,localhost 是连接器自己的容器。把回源改成 NAS 局域网地址后网页能打开,再改为 Docker 网桥地址并复测,避免回源跟着 Wi-Fi 分配的地址一起变。如果两个服务都在同一个自定义 Docker 网络里,也可以用 Gitea 的服务名和容器端口回源。Docker 桥接网络 · Cloudflare 502 排查 · Gitea 反向代理配置
5. 验证公网入口
保存路由后,从浏览器访问 https://git.example.com/ 并打开登录页。在这次部署中,公网 HTTPS 首页和登录页均正常加载。实际切换 Wi-Fi、登录后的私有仓库及 Git 拉取和推送还没有实测。自己部署时可以用手机流量复测,再从另一个网络拉取测试仓库。当前路由承载 HTTP(S),Git SSH 需走已有内网入口或单独配置。
可选升级:内网直连,外网走 Tunnel
目前所有设备都使用同一个公网域名。以后若常在局域网里拉大仓库,可以在自管的路由器或本地 DNS 上添加一条覆盖,让 git.example.com 在内网指向 NAS 的局域网地址。NAS 上的 HTTPS 反代监听 443 并转发到 Gitea 的 3000,证书可通过 Let's Encrypt DNS-01 签发。公网 DNS 的查询仍会把客户端带到 Tunnel。这样 Git remote 可以继续用同一个 HTTPS 地址。
随身使用时,这条覆盖由你能管理的路由器提供。接入酒店 Wi-Fi 或手机热点时,可以让随身路由器连接上游,NAS 和电脑仍连自己的 Wi-Fi。内网直连会绕过 Cloudflare 上的访问策略,若有 Access 登录限制,内网入口也应按自己的访问范围配置。本地 DNS 重写 · Let's Encrypt DNS-01