☰
用Cloudflare Tunnel安全发布RustFS:从零配置到避坑指南
2026/10/13 8:08:36 网站建设 项目流程

RustFS 跑起来之后,下一件事通常就是让团队伙伴在外面也能安全访问到里面的文件。直接把服务端口映射到公网?最多撑三天就会被扫描器盯上,不现实。买台云主机做中转?又多了个需要维护的安全对象。我的做法是用 Cloudflare Tunnel:在运行 RustFS 的机器上多跑一个 cloudflared 进程,它主动向外和 Cloudflare 的边缘网络建立一条隧道,然后我们把一个自定义域名挂到这个隧道上,外部请求经过 Cloudflare 边缘和这条隧道进来,最终打到本机的 RustFS 端口。整个过程不需要公网 IP,不开放任何入站端口,源站地址也不会暴露在公网上。

本文会把完整配置从头走一遍:连接模型、域名准备、隧道创建、ingress 规则、Access 身份认证,以及我在实际部署中遇到的几个高频翻车点。适合自托管玩家、小团队运维,也适合第一次用 Cloudflare Tunnel 的开发者参考。

1. 为什么选 Cloudflare Tunnel:对比传统暴露方式的取舍

1.1 传统方式到底差在哪

先说最常见的做法:如果有公网 IP,很多人会直接在路由器或防火墙上做端口映射,把 RustFS 的 Web 端口丢到公网。这在早期确实省事,但代价是你把一个完整的服务入口裸奔到了全世界面前。扫描器会在几分钟内发现这个端口,然后开始尝试常见漏洞、弱口令、协议探测。如果 RustFS 不带自带防爆破机制,你的登录页就是别人练手的靶子。就算你加了个强密码,DDoS、慢速连接、未知零日漏洞这些风险依然在。

另一种常见做法是找一台有公网 IP 的云主机做中转,让流量从云主机转发到家里的服务器。这类方案的问题在于:中转机本身变成了新的安全单点。它要监听公网端口、要处理 TLS 证书、要管理转发规则,一旦中转机被攻破,背后所有内网服务都跟着遭殃。而且如果你只是把 frp 这类工具默认配置跑起来,日志、鉴权、端口管理全堆在一起,后面维护起来相当痛苦。

1.2 Cloudflare Tunnel 是个什么连接模型

Cloudflare Tunnel(原名 Argo Tunnel)的核心思路是“反向出站连接”。在运行 RustFS 的机器上,你额外跑一个 cloudflared 进程,这个进程主动向 Cloudflare 的边缘网络发起一条出站连接并保持长连接。当用户访问你的域名时,请求先到 Cloudflare 边缘,边缘再把请求顺着这条已经建立好的连接反向送到本机的 cloudflared,cloudflared 再把请求转发给 localhost 上的 RustFS。

这个模型最大的改变是:服务器不再需要任何入站公网端口。家里宽带没有公网 IP 也行,云主机防火墙默认拒绝入站也行,因为 cloudflared 是主动往外连的。打个比方,你家大门从来没有对外敞开,访客先到小区门卫(Cloudflare 边缘)登记,门卫确认身份后,通过内部通道把人领进来。外人看到的永远是门卫,而不是你家门牌号。

1.3 这套方案的安全收益和边界

我实际用下来的感受是三个字:省心。第一,TLS 证书由 Cloudflare 自动签发和续期,不用自己去处理证书到期提醒;第二,源站不暴露公网 IP,常规的端口扫描和针对 IP 的攻击基本打不到你的服务;第三,它和 Cloudflare Access 是原生打通的,可以在边缘加一层身份认证,访问者在到达 RustFS 之前就必须先登录。

当然它也有自己的边界。注意,这套方案解决的是“把你有权限管理的服务发布给指定访问者”的问题,它的正当用途是向外提供服务,而不是用来做访问外部资源的中转,别用错方向。另外,链路可用性确实依赖 Cloudflare 边缘节点,如果边缘侧故障,服务访问会直接受影响;不过对我们自托管的场景来说,这个代价换来的是安全基线的极大简化,我觉得非常划算。

2. 开工前的准备:域名、DNS 和把 RustFS 先跑到 127.0.0.1

2.1 域名为什么要迁到 Cloudflare DNS

Cloudflare Tunnel 的 DNS 路由本质上是在你的域名下创建一条 CNAME 记录,指向一个隧道ID.cfargotunnel.com的地址。虽然理论上你也可以用第三方 DNS 手动加这条 CNAME,但后续的 Access 身份认证、边缘证书、访问日志都依赖 Cloudflare 对域名的完整控制。所以最简单可靠的做法是:把域名整个托管到 Cloudflare。

操作很简单:在 Cloudflare 添加站点,填入你的域名,它会给你两个 Nameserver 地址,然后去域名注册商那边把 NS 记录改成这两个地址。等生效时间一般在几分钟到几小时,生效后 Cloudflare 面板里域名状态会变成 Active。如果你用的域名之前就有解析记录,记得先确认一下现有记录有没有被自动导入,免得后面服务访问出问题。

2.2 服务器侧需要动的地方很少

服务器端不需要开放任何 TCP 入站端口给公网。SSH 管理端口按你自己的安全策略处理,和 RustFS 这件事无关。cloudflared 需要访问 Cloudflare 边缘,所以出站方向要能访问到 Cloudflare 的相关端点,常规云主机和家庭宽带默认都能满足,不需要额外调整防火墙。

还有一件容易被忽略的事:确保系统时间是正确的。HTTPS 证书校验、Access 的 JWT 校验都依赖系统时钟,如果 NTP 没开或者时间偏移太大,排错的时候会非常诡异——日志里全是证书错误,但你的证书明明没问题。我之前就踩过这种坑,后来凡是涉及 TLS 的服务,第一件事就是先看一眼date。

2.3 让 RustFS 先稳定跑在本机端口

在配置 Tunnel 之前,先把 RustFS 本身搞定。假设你已经在服务器上按照 RustFS 官方 README 完成了部署,并通过配置文件让它监听在127.0.0.1的某个端口上。本文以8080作为示例端口,你实际部署时请替换成自己配置的真实端口。

验证本机访问:

curl -I http://127.0.0.1:8080

如果能看到 HTTP 响应头,说明 RustFS 的服务进程已经正常工作。注意这里我特意建议监听 127.0.0.1 而不是 0.0.0.0,因为 cloudflared 和 RustFS 在同一台机器上,走回环地址即可,没必要让 RustFS 暴露到内网其他机器。

3. 建一条命名隧道:登录授权、创建隧道、生成 DNS 路由

3.1 安装 cloudflared

cloudflared 官方提供 Linux 二进制和各大发行版的包源。我用的是直接下载二进制的方式,以 Linux amd64 为例:

cd /usr/local/bin wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 mv cloudflared-linux-amd64 cloudflared chmod +x cloudflared cloudflared --version

确认能输出版本号,工具就装好了。如果你用的架构是 arm64,把下载文件名里的 amd64 换成 arm64 即可。

3.2 登录授权:让 cloudflared 拿到域名管理权

第一次使用要先授权:

cloudflared tunnel login

命令会输出一个本地的认证链接,复制到浏览器打开,选择你想用来发布 RustFS 的域名,点授权。完成后 cloudflared 会在~/.cloudflared/目录下生成一个cert.pem文件。这个文件代表你对该域名的管理权限,后续创建隧道、添加 DNS 路由都要用到它。

这里有个值得注意的细节:cert.pem有明确的域名 scope,只对授权时的那个域名有效。如果你有多个域名,后期想用同一个账号管理不同域名的隧道,需要重新登录授权对应域名,证书会覆盖或者需要按域名分别保存好。

3.3 创建命名隧道

我不建议用 quick tunnel(临时隧道),它的随机域名每次重启都会变,也没法配合 Access。正确做法是创建一条命名隧道(named tunnel):

cloudflared tunnel create rustfs-tunnel

执行成功后,输出里会给你一个 Tunnel ID(一串 UUID),同时在~/.cloudflared/下生成对应的<Tunnel-UUID>.json凭证文件。这个 JSON 文件就是隧道的身份凭证,cloudflared 靠它和 Cloudflare 边缘建立信任关系,一定要保管好。

顺便说一句,如果你是从旧版本升级上来的,配置文件里可能还在用tunnel: 名字加cert: /path/cert.pem的旧格式,建议迁移成 UUID + credentials-file 的新写法,后面维护更清晰。

3.4 自动生成 DNS 路由

命名隧道创建好之后,把域名指到隧道上:

cloudflared tunnel route dns rustfs-tunnel fs.example.com

这个命令会在 Cloudflare DNS 面板里自动创建一条 CNAME 记录,指向隧道ID.cfargotunnel.com,不用你去面板里手动敲。执行后可以去 Cloudflare 的 DNS 页面确认记录存在。

到这里你已经完成了隧道基础设施的搭建。做个小对比,方便理解为什么我坚持用命名隧道:

对比维度quick tunnelnamed tunnel
域名每次启动随机,无法固定绑定自己的域名,稳定
DNS 路由不需要配置,但不可控自动创建 CNAME 记录
身份认证集成不方便天然支持 Access、mTLS
用途临时测试、演示正式发布服务

4. 定义 ingress 规则:把域名流量引进 RustFS 端口

4.1 配置文件完整示例

隧道要转发哪些域名、转发到本机哪个端口,是在 ingress 规则里定义的。创建一个配置文件/etc/cloudflared/config.yml,内容如下:

tunnel: 你的隧道UUID credentials-file: /root/.cloudflared/你的隧道UUID.json ingress: - hostname: fs.example.com service: http://127.0.0.1:8080 - service: http_status:404

第一行tunnel填创建隧道时输出的 UUID 字符串;credentials-file是凭证 JSON 的绝对路径。ingress 的规则很好理解:当外部请求的 Host 是fs.example.com时,cloudflared 将它转发到本机的http://127.0.0.1:8080,也就是 RustFS 的监听地址。

4.2 为什么要保留最后一条兜底规则

ingress 规则从上到下匹配,取第一个符合条件的 hostname。最后一条没有 hostname 的http_status:404是兜底规则,用来拦截所有没有显式匹配的域名请求。

这是很多第一次配置的人容易忽略的点。如果配置文件里没有任何一条不带 hostname 的兜底规则,cloudflared 会直接拒绝启动,报错提示你缺少默认 ingress 规则。即使你只有一个域名,也建议保留兜底 404,避免别人把你的其他子域名硬解析到隧道上时,请求被意外转发到 RustFS。

4.3 前台的确认运行

写好后先不要急着做成服务,前台跑一次,确认整个过程能通:

cloudflared tunnel --config /etc/cloudflared/config.yml run rustfs-tunnel

日志里正常情况下会显示Registered tunnel connection,代表隧道已和 Cloudflare 边缘建立连接。此时换另一台电脑(或者直接用手机流量,不要和服务器走同一条局域网)访问https://fs.example.com,应该能看到 RustFS 的页面。如果后台 RustFS 返回 401 或者让你登录,都是正常的,说明流量已经成功穿透到了本机服务。

4.4 转成 systemd 服务常驻后台

确认没问题之后,把它注册为系统服务,保证重启后自动拉起。在/etc/systemd/system/cloudflared.service写入:

[Unit] Description=Cloudflare Tunnel for RustFS After=network-online.target Wants=network-online.target [Service] Type=simple User=root ExecStart=/usr/local/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run rustfs-tunnel Restart=on-failure RestartSec=5s LimitNOFILE=1048576 [Install] WantedBy=multi-user.target

然后依次执行:

systemctl daemon-reload systemctl enable --now cloudflared systemctl status cloudflared

看到 active (running) 就说明服务已经常驻。有一点我要特别提醒:生产环境不建议用 root 账号跑 cloudflared。更稳妥的做法是创建一个专用系统用户,给它配置目录的读写权限,然后在 service 文件里指定User=cloudflared。凭证文件权限设为600,避免同机其他用户读到。

5. 在 Cloudflare 边缘加一道身份锁:配置 Access

5.1 隧道通了不等于安全访问

Tunnel 帮你解决了“如何不被暴露公网 IP 地访问”的问题,但它不做身份认证。任何知道域名的人都能直接请求到 RustFS。所以“安全访问”的最后一块拼图是 Cloudflare Access:在流量到达边缘时,先要求访问者完成身份认证,只有通过认证的请求才会被转发到 cloudflared。

5.2 创建 Access Application 和 Policy

进入 Cloudflare Zero Trust 面板,在 Access 下的 Applications 里创建一个 Self-hosted Application。域名填fs.example.com,注意不用写https://。接下来配置 Policy,我通常的做法是:

  • Policy 名称随意,比如rustfs-allow;
  • 规则选 Include + Emails / Email domain;
  • 填入团队成员的邮箱,或者允许一个企业域名后缀下的所有邮箱;
  • Session duration 按需设置,个人项目选 24h 或 1h 都行。

如果你有企业 IdP(比如 Google Workspace、Azure AD),也可以先在 Zero Trust 里接入作为身份源,Policy 里直接选 IdP + 组,这样和公司现有账号体系打通,管理成本会低很多。

5.3 验证登录流程

配置完成后,用无痕窗口访问https://fs.example.com,浏览器会被重定向到 Cloudflare Access 的登录页。输入邮箱后,Cloudflare 会发送一次性验证码到你的邮箱,输入验证码通过后,会写入CF_AuthorizationCookie,然后跳转回 RustFS 页面。

整套流程走下来,你会发现登录过程完全由 Cloudflare 边缘接管,RustFS 本身甚至不需要知道访问者的身份信息。日志里也只会看到一堆来自 Cloudflare 边缘的转发请求,源站彻底隐身在隧道后面。

5.4 给脚本和 API 调用预留 Service Token

如果你的 RustFS 不光是给人用,还要给脚本或者 CI 流程用,浏览器登录的方式就不好使了。这时可以在 Access 里创建一个 Service Token,Cloudflare 会给你一对 Client ID 和 Client Secret。脚本请求时带上这两个请求头:

curl -H "CF-Access-Client-Id: 你的ClientID" \ -H "CF-Access-Client-Secret: 你的ClientSecret" \ https://fs.example.com

把 Service Token 加进 Policy 的 Include 规则里,脚本就能以机器身份绕过邮箱验证直接访问了。Secret 的保管要谨慎,这相当于给脚本开的后门,别把它写进提交到代码仓库的配置文件里。

6. 验证链路和高频翻车点:从 521 到登录回环

6.1 按分层顺序做检查清单

配置全部完成后,遇到问题不要慌乱,按下面顺序从内向外排查:

  1. 本机curl -I http://127.0.0.1:8080是否正常;
  2. cloudflared 日志里是否有Registered tunnel connection;
  3. 关闭 Access 的临时测试域名路径是否能正常返回(如果有);
  4. 从公网访问时,是否能被引导到 Access 登录页;
  5. 登录后是否能正常访问 RustFS 页面。

大多数问题都集中在最内层。先确认后端服务没问题,再往上查隧道,效率最高。

6.2 521 / 522 / 502 分别指向什么问题

这几个错误码是在 Cloudflare Tunnel 场景下最常见的,我直接列个表:

错误码含义常见根因
521源站服务器不可达cloudflared 没有运行,或服务因防火墙规则无法连接网络
522连接到源站超时config 里的端口写错,或者 RustFS 没有监听在预期地址
502网关错误cloudflared 能连上,但握手失败,通常是后端协议配置不对

遇到 522,先执行ss -ltnp | grep 8080确认端口在监听,然后看 cloudflared 日志;遇到 502,检查 config 里service一段是http://还是https://。如果 RustFS 自己用的是 HTTPS 端口(比如自签证书),你直接写http://就会握手失败。

6.3 回环地址的 IPv4/IPv6 陷阱

这个坑很典型:cloudflared 配置里写成http://localhost:8080,而 RustFS 监听在127.0.0.1:8080。某些机器上localhost优先解析到::1,cloudflared 试图去连 IPv6 回环地址,结果连接被拒绝。日志里看起来像是“connect refused”,但实际不是端口问题。

解决办法是永远显式写127.0.0.1而不是localhost,在 config.yml 的 service 字段里固定成http://127.0.0.1:8080。类似的弯路我建议直接避开,别让 DNS 解析成为变量。

6.4 登录回环和 Cookie 问题

配置完 Access 之后,浏览器访问域名,却一直在登录页和跳转页之间循环,怎么都进不去。这个情况通常是两种原因:一是同一域名下有多个 Access Application 规则重叠,导致策略匹配混乱;二是浏览器里残留了旧的 Cloudflare 认证 Cookie。

处理方式很直接:在 Zero Trust 面板里检查是否重复创建了覆盖同一子域的 Application,保留一条明确的 Policy;浏览器用无痕窗口重新测试,排除 Cookie 干扰。还有一种少见的情况是域名用了国内访问不稳定的身份源,导致回调延迟,遇到时换个身份源登录对比一下就能定位。

6.5 用 debug 日志抓住关键证据

如果上面这些检查都没发现问题,那就打开 cloudflared 的调试日志:

cloudflared tunnel --loglevel debug --config /etc/cloudflared/config.yml run rustfs-tunnel

日志里能看到每一条请求的转发路径、后端连接耗时、HTTP 状态码、TLS 握手细节。比如你能清楚看到请求到了 cloudflared、它尝试连接127.0.0.1:8080、连接耗时多少、RustFS 返回了什么状态码。到这一步,问题出在哪一层基本就锁定了。

文章写到这里,最后分享两个我在实际操作里的体会。第一个是关于维护成本:自从把服务改成 Cloudflare Tunnel 之后,我几乎不再需要操心入站安全策略和证书续期。服务器防火墙默认拒绝入站,所有对外入口都收敛到 cloudflared 这一条隧道上,出事时排查范围小很多。第二个是关于迭代节奏:Cloudflare 的配置项偶尔会调整格式,更新 cloudflared 版本前我会先看 release notes,尤其是 ingress 和 credentials 相关字段,避免升级后服务起不来。这套方案我跑了大半年,稳定性超出预期,如果你也正为自建服务的安全访问发愁,照着上面流程走一遍,应该很快就能跑通。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询