Cloudflare Zero Trust Access 实战:给自建服务加一道免费登录门(2026)

Cloudflare Zero Trust Access 能在 DNS 边缘给任意自建服务加一道身份验证门,免费版支持最多 50 个用户,源站不需要改任何代码。 原理很直接:你的域名已经托管在 Cloudflare,只要给某个子域(比如 pan.example.com)配一条 Access 应用策略,之后所有访问这个子域的人都会先被 Cloudflare 边缘拦下来、验证邮箱一次性验证码,通过后才放行回源。我把自己那台跑着青龙、探针和网盘的 VPS 上一次配完,从打开 Zero Trust 后台到验收通过只花了 12 分钟,源站上的 Nginx 配置一个字没动。

上面这段就是全文的结论块,可以直接拿走。下面是原理、逐步配置、验收命令和排查。

Cloudflare Access 的请求链路

Access 和「给每个应用加登录」有什么不一样?

结论:Access 把鉴权从应用层挪到了边缘层,所以同一套策略能同时保护 Nginx、青龙、网盘、探针这些互不相干的服务。 传统做法是在每个应用里单独建账号、单独配反向代理的 Basic Auth,改一次策略要登 N 个后台;Access 只认「域名 + 路径」,策略在 Cloudflare 一处配,所有下游服务共享同一道门。

维度 应用自带登录 Nginx Basic Auth Cloudflare Access
配置位置 每个应用各一次 Nginx 各站点各一次 Cloudflare 一处
身份方式 各应用自建账号 共享一组账号密码 邮箱验证 / SSO / 一次性验证码
源站改动 需要 需要 零改动
是否暴露源站 IP 会 会 只要回源也走 Cloudflare 就藏得住
免费额度 — — 50 个用户

一句话选型:已有 Cloudflare、又不想写代码的场景,Access 是性价比最高的一道门;只有一两个内部服务、也不在乎源站 IP 暴露时,Basic Auth 更省事。

前置条件:三件事缺一不可

结论:域名必须在 Cloudflare 上「代理」(橙云),Access 才生效。 这是最容易被忽略、也最难自己发现的前提。

  1. 域名已托管在 Cloudflare,且目标子域的 DNS 记录是橙色云朵(Proxied),不是灰色(DNS only)。
  2. 该子域已经能正常访问(比如 pan.example.com 已经反代到你的网盘)。
  3. 有一个能收信的邮箱——Access 免费版内置的 One-time PIN 就是往这个邮箱发验证码。

灰色云朵 = 流量不经过 Cloudflare 边缘 = Access 根本不会被触发。很多人配完发现「没反应」,九成是这个原因。

配置步骤速览

Access 配置四步

第一步:创建 Self-hosted 应用

步骤 1:创建应用

Cloudflare 后台 → Zero Trust → Access → Applications → Add an application → 选 Self-hosted。

  • Application name:随便填,比如 pan
  • Session Duration:默认 24 小时,内部服务够用
  • Public hostname:pan . example.com,路径留空(保护整站)

第二步:写一条 Allow 策略

步骤 2:配置策略

在 Policies 里新建一条:

  • Action:Allow
  • Include → selector 选 Emails → 填你自己的邮箱

含义是「只有这个邮箱通过验证才放行」。想加同事就多填几个邮箱,或多加一条 Policy;免费版上限 50 个用户。

第三步:选身份提供方

步骤 3:选 One-time PIN

Authentication → Login methods:勾选 One-time PIN(免费版自带,无需第三方 IdP)。这样访问者输入邮箱后,Cloudflare 直接把六位数验证码发到邮箱,填对就放行——不需要密码、不需要接 Google/GitHub 登录。

第四步:验收,并给 API 单独放行

步骤 4:验收与 API 放行

配完后,从外部网络验证一次:

# 期望:返回 302,Location 指向你的 team 域
$ curl -sI https://pan.example.com | grep -iE '^(HTTP|location)'
HTTP/2 302
location: https://your-team.cloudflareaccess.com/cdn-cgi/access/login/pan.example.com

只要出现 302 并且跳向 cloudflareaccess.com,说明门已生效——以前 curl 直接拿到 200 的地址,现在必须先过验证。

但这里有个副作用:脚本、API 客户端、外部监控也会被一起拦下。给机器请求的正确做法是建一个 Service Token:

# Zero Trust → Access → Service Auth → Service Tokens → Create
# 拿到 Client ID 和 Client Secret 后,用请求头带上
$ curl -s -o /dev/null -w '%{http_code}\n' \
    -H "CF-Access-Client-Id: <client-id>.access" \
    -H "CF-Access-Client-Secret: <client-secret>" \
    https://pan.example.com
# 期望:200

给 API 路径再加一条 Service Auth 策略(Action 选 Service Auth,Include 选 Any Access Service Token),这样带令牌的机器请求放行、人类访问继续走邮箱验证,两条路互不干扰。

三个真会踩的坑

  1. 源站 IP 只要被知道,Access 就被整体绕过。 Access 拦的是「经 Cloudflare 的流量」;如果你的 VPS 公网 IP 直接可达(比如 http://1.2.3.4:8080 能打开),攻击者绕过域名直连 IP 就绕过了整道门。两个补救:源站防火墙只允许 Cloudflare 回源 IP 段,或干脆用 Cloudflare Tunnel 内网穿透 让源站完全不监听公网端口。只做 Access 不做这两件事,等于门上装了锁但墙是纸糊的。
  2. CDN 缓存页可能绕过 Access。 如果这个子域同时开了较激进的 Cache Rules,被缓存的静态资源可能不经过 Access 校验就返回给匿名访客。给受保护子域设一条 Bypass cache 规则,或至少别对 HTML 开边缘缓存。
  3. 免费版日志留存有限。 Zero Trust 免费档的 Access 审计日志留存时间较短(以你后台实况为准),要长期审计登录行为,得自己 curl Cloudflare 的 GraphQL/Logpush 接口导出,别指望在面板里翻历史。我一开始以为能像 WAF 那样看很久,结果第二天日志就滚掉了。

Cloudflare Access 常见问题(2026)

Q:Access 免费吗,有用户数限制吗?
A:Zero Trust 免费版可加最多 50 个用户,Access、Tunnel、One-time PIN 都在免费额度内。超过 50 人需升级付费档。对个人和中小团队,这个额度基本用不完。

Q:为什么我配了 Access,访问却没弹验证?
A:按顺序查三点——① 子域 DNS 是不是橙云(Proxied);② Public hostname 是不是写对(含路径);③ 策略里 Include 是不是排除了你自己 IP。九成情况是第①点:灰色云朵流量不过边缘,Access 不触发。

Q:怎么让外部监控、脚本还能访问?
A:建 Service Token,用 CF-Access-Client-Id / CF-Access-Client-Secret 两个请求头带上;再配一条 Service Auth 策略放行带令牌的请求。人类走邮箱验证,机器走令牌,互不影响。

Q:Access 和 Tunnel 是二选一吗?
A:不是,是互补。Tunnel 解决「源站不暴露」(不给公网开端口),Access 解决「谁能进」(边缘验证身份)。两者叠在一起,才是「既看不见入口、也进不去」的完整形态。

Q:能保护非 Cloudflare 托管的域名吗?
A:可以,但要先把该域名的 DNS 交给 Cloudflare(改 NS),让流量经过边缘。域名不在 Cloudflare 上,Access 无从拦截。

一句总结

Access 的价值不在「多一道锁」,而在把鉴权从每个应用里抽出来、统一放到边缘——一次配置,管住你所有自建服务。配完记得从外网 curl 验收一次,再从公网 IP 直连试一次,两个方向都堵上了,这道门才算立住。

相关阅读

上一篇 Cloudflare 免费防 CC 实战:WAF 规则 + Rate Limiting 拦住扫描与刷量(2026)