我一直想在公网上访问家里的 NAS,但不想每次都先打开 Tailscale。
Tailscale 是好东西——它把手机和 NAS 放进同一个虚拟网络,手机拿到固定的 100.x 地址,改用流量也能连回家里。我之前那套跨网 ADB 方案就是靠它跑通的。但它有个前提:访问方得先装客户端、先登录、先连上。对我自己来说这不算什么,可要是想在朋友的电脑上临时看一眼,或者设备刚换还没配好,这一步就成了门槛。
所以这次我想试另一条路:Cloudflare Tunnel——不用开端口,不用公网 IP,浏览器直接打开域名就能进。
第一版:把隧道拉起来
Cloudflare Tunnel 的基本思路其实很朴素:在家里跑一个叫 cloudflared 的小程序,让它主动向 Cloudflare 建立一条出站长连接,然后把公网域名上的请求,从这条连接送到家里。
好处很直接:
- 路由器上不用做端口转发,一个入站端口都不用开;
- 家庭宽带的动态 IP 无所谓,源站 IP 也不暴露;
- 顺带还能吃到 Cloudflare 的 DDoS 缓解和 HTTPS 证书。
飞牛应用商店里正好有个现成的 Tunnel 应用,装上、填账号、建隧道,十分钟就跑起来了。顺手把域名的 DNS 解析也从 DNSPod 迁到了 Cloudflare。
那一刻我确实有点得意:家里两个服务,现在都有公网域名了。
——然后我意识到一件事。
得意了大概十分钟
我习惯性地查了一下隧道到底把哪些东西挂上去了,结果是:
| 域名 | 实际指向 |
|---|---|
nas.huey314.online |
飞牛 NAS 的管理后台 |
ai.huey314.online |
我的 AI Agent 的 Web 界面 |
没有任何访问控制。
任何人知道这两个域名,就能看到飞牛后台的登录页,就能敲我 Agent 的控制台。这两样东西的分量我心里清楚:NAS 管理后台被拿下,等于全盘数据落在别人手里;Agent 控制台里是会话记录和工具权限。
装隧道的时候,我只想着"能访问了",完全没想"谁能访问"。
这是这次最该记住的一条:暴露面和访问控制应该同时上线,而不是先开门、事后再想装锁。 中间那段时间,它们就是裸着的。
安全方案:先做排除法
接下来是选型。我把能想到的路挨个试了一遍,过程比结论更有意思。
Cloudflare Access 是最顺手的选择,它本来干的就是这个。但我卡在第一步:创建 Zero Trust 组织时必须填付款信息。官方文档写得很直白——"A credit card is required for our user-limited Free Plan",选免费版也一样要填,只是不扣费。我不想为这件事绑定支付方式,排除。
免费版 Rate Limiting 看着挺美,实际窄得超出预期。官方可用性表里,免费版的限制是这样:
| 项目 | 免费版 |
|---|---|
| 规则可用字段 | 只有 Path、Verified Bot |
| 计数特征 | 只有 IP |
| 计数周期 | 只有 10 秒 |
| 缓解时长 | 只有 10 秒 |
| 规则条数 | 1 条 |
也就是说,"按 URI Path 限制"不是可选项,而是免费版唯一能用的匹配字段。它是限流器,不是门锁——10 秒的窗口,攻击者把速度放慢就绕过去了。
按省份限制 IP 这个思路我本来挺喜欢:只让江苏的 IP 进来。查了字段文档,ip.src.subdivision_1_iso_code(省级 ISO 码)明确标着 "Requires a Cloudflare Business or Enterprise plan"。省级判断是付费功能,免费版的地理字段只到国家级。
国家级 IP 限制 免费可用,配合 WAF 自定义规则能挡掉绝大多数扫描。但它挡不住有心人——任何人在国内,或者挂个国内代理,就进来了。
绕了一圈,我明白了一件事:这些方案回答的都是"这个人从哪来",没有一个在回答"这个人是谁"。
最终选择:mTLS
mTLS 的思路跟上面几个都不一样。
平时我们上 HTTPS,只验证一边:服务器给你看证书,你确认"这确实是 huey314.online"。你的浏览器在这个过程中没有任何身份。
mTLS(mutual TLS,双向 TLS)加了一步:客户端也要出示证书,服务器反过来验证你。
关键在于,拒绝发生在 TLS 握手阶段——没证书的设备,连一个字节的 HTML 都拿不到,浏览器直接报握手失败。它根本到不了登录页,也就没有机会去猜密码、撞验证码、被限流规则统计。
这跟前面所有方案的本质区别是:
- IP 限制是在看邮戳——写着江苏就放行,但邮戳可以伪造,人也可以在别处寄;
- mTLS 是只给自家人发钥匙——钥匙在谁手里谁才能进,跟从哪来、什么网络、什么 IP 全无关系。
你在南京、在外地、在飞机上连卫星网,只要设备带着证书就能进;别人就算把服务器放在你家隔壁,也进不来。
实施:三张证书
Cloudflare 免费区支持用它的托管 CA 签发客户端证书(每域名 100 张配额,自建 CA 才要企业版)。
签发时我留了个心眼:私钥在 NAS 本地生成,只把 CSR(证书签名请求)交给 Cloudflare。这样私钥从头到尾不离开自己的机器,Cloudflare 只是签个名。
openssl req -new -newkey rsa:2048 -nodes -keyout key.pem -out csr.pem -subj '/CN=honor-phone'
# 把 csr.pem 提交给 Cloudflare,换回证书
openssl pkcs12 -export -out honor-phone.p12 -inkey key.pem -in cert.pem
手机、平板、电脑,一台一张。一台一张不是为了限制数量,是为了吊销粒度——p12 本身没有任何设备绑定,同一张装十台都行,交叉着装也行;但设备丢了的时候,一台一张只吊销那一张,其他设备不受影响。
Cloudflare 的 mTLS 是两步,少一步都不行
这是第一个坑。它的机制分成两截:
- 把域名加入 mTLS Hosts 列表——让 Cloudflare 在握手时请求客户端证书。注意是"请求",不是"要求",没证书照样能进;
- WAF 规则——这才是真正的门:
(http.host in {"nas.huey314.online" "ai.huey314.online"} and not cf.tls_client_auth.cert_verified)
→ Block
只做第一步,等于门框装好了没装门;只做第二步,Cloudflare 压根不会跟客户端要证书,所有人都过不了验证。
顺序上也有讲究:先把证书签好、发下去、装好、确认能用,最后才上 WAF 规则。反过来做,你自己第一个被关在门外。
装证书踩的坑
三台设备的证书都装好了,结果只有平板能进。
Windows:证书导入位置是对的("个人"存储、带私钥),问题出在浏览器没有完全重启。Chrome 只在启动时读一次系统证书存储——任务栏关窗口不够,得让所有后台进程都结束。另外导入向导默认那个"根据证书类型自动选择证书存储",很容易把证书扔到"受信任的根证书颁发机构"去,那样浏览器根本不会用它。
Android 这边坑更深:
- 装的时候必须选「VPN 和应用用户证书」,不能选「WLAN 证书」。后者是给 Wi-Fi 企业认证用的,浏览器不去那儿找;
- 装完要重启设备,不是重启浏览器——其它应用要等设备重启才能看到新凭据;
- 荣耀、华为这类 ROM 还会要求先设锁屏密码,否则私钥可能没真正写进 KeyChain,表现就是"装了等于没装";
- 设备上如果有多张客户端证书,浏览器会弹选择框,选错照样被拒。
最后手机是靠"重启设备 + 确认证书落在正确的类别"解决的。
现在是什么状态
两个域名现在是:不带证书 → 403,带证书 → 正常访问。
日常使用最直接的变化:不用再打开 Tailscale 了,浏览器直接打域名,证书自动带上。
但代价也得说清楚:
- 慢了。 实测从 NAS 回环访问自己的公网域名要 1.1–1.4 秒,而内网直连是 0.5 毫秒。查了下隧道连接,四条全落在洛杉矶(lax01/lax08/lax10)——也就是说,我在南京打开家里的后台,数据先绕到美西再回来。这个延迟是有体感的。
- 能碰到的东西变窄了。 Cloudflare 只放行配置过的那两个域名;Tailscale 是网络层的,进了虚拟网就能碰 NAS 上的一切——SSH、文件共享、相册、任意端口。在外面想拖个文件或者 SSH 一下,走 Cloudflare 这条路是断的。
- 加新设备变重了。 Tailscale 是装个 App 登录一下;现在是签证书、安装、可能还要重启。
所以这两个方案我没有二选一,而是各管一段:随手看看(AI 界面、NAS 后台)走 Cloudflare,不用开客户端,什么设备都行;要传文件、要 SSH、要速度,把 Tailscale 打开。
最后一点反思
"绝对安全"是不存在的。
mTLS 只解决了一件事——没有钥匙的人进不来。它挡不住钥匙被复制(私钥就躺在设备的文件系统里)、挡不住设备被借用或丢失、挡不住流量在 Cloudflare 那里被解密(TLS 终止在它的边缘)、也挡不住证书到期那天突然失效。
更值得说的是,它把风险从一个地方挪到了另一个地方。为了签发和分发证书,NAS 上就多出了私钥文件、p12 文件和一枚能改 WAF 规则的 API Token。现在整个体系里最弱的一环不是 Cloudflare,而是这几个文件——外面的门焊死了,钥匙却还插在门内的锁孔上。
链条的强度取决于最弱的那一环。这句话今天体会得格外具体。