凭据:文件与 token
模块支持 三种凭据来源,三选一。同时写两个,nginx -t 直接报 凭据来源只能写一个(配置期 EMERG,不是运行时才发现)。
| 来源 | 指令 | 等价于 cloudflared |
|---|---|---|
| 凭据 JSON 文件 | cfd_tunnel_credentials / 块内 credentials | --credentials-file |
| 内联 token | cfd_tunnel_token / 块内 token | --token |
| token 文件 | cfd_tunnel_token_file / 块内 token_file | --token-file |
三者都与快速隧道互斥(cfd_tunnel_quick_tunnel on 时不能再写凭据)。
一、凭据 JSON 文件
就是 cloudflared 的凭据格式:
{
"AccountTag": "0123456789abcdef0123456789abcdef",
"TunnelID": "11111111-2222-3333-4444-555555555555",
"TunnelSecret": "<base64 的 32 字节>"
}cfd_tunnel_credentials /etc/nginx/cloudflared/creds.json;文件必须 worker 用户可读:
sudo install -m 600 -o www-data -g www-data creds.json /etc/nginx/cloudflared/creds.json读不到时 error_log 会明确报「读取凭据 … 失败」,而不是静默不启动隧道。
二、控制台给的 token
Cloudflare Zero Trust 控制台「添加隧道 → 安装连接器」页面只给一串 token, 长得像 eyJhIjoi...;cloudflared service install <token> 也只是把它写进 /etc/cloudflared/token,再让 systemd 单元用 --token-file 读它。0.14.0 起模块直接收:
# 写法 A:把控制台那串原样贴进来(等价 --token,不 trim)
cfd_tunnel_token eyJhIjoi...;
# 写法 B:从文件读(等价 --token-file,也就是 service install 写出来的文件)
cfd_tunnel_token_file /etc/nginx/cloudflared/token;这串 token 到底是什么
它是 base64(JSON),解开就是凭据文件里的那几个字段:
{"a":"<账号标签>","t":"<隧道 UUID>","s":"<base64 的 32 字节 secret>","e":"<可选区域>"}cloudflared 自己在 cmd/cloudflared/tunnel/subcommands.go 的 ParseToken() 里就是 base64.StdEncoding.DecodeString + json.Unmarshal 到 connection.TunnelToken。 它不是新协议,只是 credentials 的第三种写法 —— 解析结果并进同一个凭据结构, 注册、心跳、注入三条路径完全不变。
照抄 cloudflared 的细节(不是疏忽)
| 行为 | 原因 |
|---|---|
内联 cfd_tunnel_token 不 trim | cloudflared 的 --token 原样用;尾随空格会让 base64 变非法 |
token_file 内容 先 TrimSpace | cloudflared 的 --token-file 先 strings.TrimSpace;文件结尾换行没关系 |
base64 用标准 alphabet、必须有 = 填充 | StdEncoding 的规则;-/_(URL-safe)与空格一律拒 |
只忽略 base64 里的 \r\n | Go 的 base64 解码器就是只跳过 \r\n |
未知字符串键忽略、a/t/s 缺失不算错、s:null 允许、重复键后者胜 | 与 json.Unmarshal 进 struct 的行为一致;缺字段留给边缘去拒 |
| 校验发生在 worker 启动期 | 与 cloudflared 一样,所以 nginx -t 通过 ≠ token 对 |
两处有意偏离(都用真 cloudflared 二进制证明"它确实接受")
- token 带
e(endpoint / region)⇒ 模块启动期报错。 模块只按cfd_tunnel_edge连一个固定边缘,遇到e不猜地址、直接说清原因(例如 FedRAMP 区域)。 - JSON 里未知键的值是嵌套对象或数字 ⇒ 报错。 模块的 JSON 走查只接受 object + string/null 两类值;Go 的
json.Unmarshal会忽略这种未知键。这条偏离的方向是「宁可拒绝也不误读」。
坏 token 长什么样
启动期会明确写出是哪一种错,并且只跳过这一条隧道,nginx 其余功能照常:
cfd_tunnel: token 不是合法的 base64
cfd_tunnel: token 解出来不是 JSON 对象
cfd_tunnel: token 里的 t 不是合法 uuid
cfd_tunnel: token 里的 s 不是合法的 base64
cfd_tunnel: token 带 endpoint/region(e=...),本模块只连一个 cfd_tunnel_edge日志只打来源、字节数与账号标签,从不打 token、不打 secret。
旧版本:一行命令转成凭据文件
不想升级模块时,旧版本也能直接用:
python3 -c 'import base64,json,sys; d=json.loads(base64.b64decode(sys.argv[1].strip()));
print(json.dumps({"AccountTag":d["a"],"TunnelID":d["t"],"TunnelSecret":d["s"]},indent=2))' \
"$(cat /etc/cloudflared/token)" > /etc/nginx/cloudflared/creds.json三、三种来源都没写 = 模块静默不启用
装了 .so、也配了边缘地址,但既没有 cfd_tunnel_credentials、也没有 cfd_tunnel_token / cfd_tunnel_token_file、也没开快速隧道时:模块不建连接、不挑监听器、不占 fd。 这是刻意的 —— 让「装了但还没配」和「配错了」在日志上能区分开。
块内写法
每条隧道一个来源:
cfd_tunnel {
name edge-a;
token_file /etc/nginx/cloudflared/a.token;
inject_listen 127.0.0.1:8080;
}块内 credentials / token / token_file / quick on 四选一,写两个该块的 nginx -t 就失败。详见 多隧道。