根路径站点验证文件
放在这个目录里的文件,会被 Go 服务直接吐到域名根路径,用于各类「域名所有权 / 站点所有权」验证:
- 备案与域名所有权验证:
1XXl8fPHr9.txt(阿里云、腾讯云) - 搜索引擎站点验证:
googleXXXX.html、msXXXXXXXX.txt、BingSiteAuth.xml - 第三方平台域名校验:各平台下发的
.txt/.html
为什么需要这个目录
线上 nginx 对所有域名都是「全量反代给 Go」(location / → proxy_pass),
Go 不认识的路径一律回 beego 404 页,所以放在服务器网站根目录里的验证文件根本取不到。
改成由 Go 统一托管后,不再依赖 nginx 规则 —— 宝塔重生成 vhost 也不会被冲掉。
实现见 go/routers/verifyfiles.go(过滤器)与 go/pkg/verifyfiles/(路径解析与安全校验)。
生效规则
- 只处理
GET/HEAD; - 只认根路径下的单段文件名(如
/1XXl8fPHr9.txt),不支持子目录; - 文件名必须形如「字母或数字开头 + 字母数字与
._-」,长度 ≤ 64; - 扩展名必须在允许列表内(默认
.txt/.html/.htm); - 文件必须真实存在,否则放行给正常路由(最终仍是 beego 404,行为不变)。
配置项在 app.conf:
| 配置 | 说明 | 默认值 |
|---|---|---|
verify_dir |
验证文件目录 | <服务根目录>/verify |
verify_exts |
允许的扩展名,逗号分隔 | .txt,.html,.htm |
verify_hosts |
限定生效域名,逗号分隔(不含端口) | 空 = 所有走本服务的域名 |
「服务根目录」=
conf/app.conf所在目录的上一级。 线上即/www/wwwroot/api.yunzer.cn(systemd 的WorkingDirectory), 所以验证文件目录是/www/wwwroot/api.yunzer.cn/verify。 目录跟着app.conf走,不管用go run main.go还是编译后的二进制、 不管从哪个目录启动,结果都一致。
新增一个验证文件
- 把平台给的验证文件放进本目录(文件名保持原样,内容不要加多余字符);
git add && git commit && git push;- 服务器上
git pull后重启 Go 服务:systemctl restart go-api(或bash scripts/service.sh restart); - 访问
https://api.yunzer.cn/1XXl8fPHr9.txt验证。
注意:本目录下的
.md等非白名单扩展名不会被吐出去,README 不会被当成静态文件泄露。
部署注意:本仓库(allinone)与服务器不是同一个仓库
排查问题时确认过,线上是两套独立的 git 仓库,别混用:
| 位置 | 角色 | |
|---|---|---|
| 源仓库 | 本地 yunzerwebsiteallinone(远端 10.31.100.4:8418/.../yunzerwebsiteallinone.git) |
唯一真相源,go/ 只是其中一个子目录 |
| 部署目录 | 服务器 /www/wwwroot/api.yunzer.cn |
只放 go/ 的内容,里面是另一个 Go 仓库(HEAD 与 allinone 不一致,例如 269fbd0) |
所以:
- allinone 的
master与服务器仓库的master是两条线,git pull拉不到对方; - 部署 = 把
go/的内容同步到服务器目录(手工拷文件 / scp / rsync),新增目录最容易漏—— 本目录就是漏传过一次导致验证 404 的典型; - 同步本目录用文件路径,别用目录路径,否则会多出一层
verify/verify:
# Windows 本地 → 服务器(只同步新增的验证文件)
scp "E:\Demo\Go\yunzerwebsiteallinone\go\verify\1XXl8fPHr9.txt" root@10.31.100.2:/www/wwwroot/api.yunzer.cn/verify/
# 服务器上确认
ls -l /www/wwwroot/api.yunzer.cn/verify/
curl -i http://127.0.0.1:9000/1XXl8fPHr9.txt # 直连 Go,绕过 nginx
Go 每次请求都会实时
os.Stat验证目录,文件放进去立即生效,不需要重启服务。
⚠️ 本项目 nginx 的两个既定事实(改配置时别踩)
api.yunzer.cn 的 vhost(/www/server/panel/vhost/nginx/api.yunzer.cn.conf)有两个特点,
直接影响本机制的配置方式:
proxy_set_header Host 10.31.100.2;—— 转发给 Go 时 Host 头被改成了 IP, Go 侧看不到api.yunzer.cn这个域名。 → 因此verify_hosts必须留空(留空 = 所有走本服务的域名都放行)。 一旦填了api.yunzer.cn,Go 会因为 Host 对不上而拒绝提供文件。location ^~ / { proxy_pass ... }——^~匹配后 nginx 不再检查正则 location, 后面那两条「禁止访问的敏感文件 / 敏感目录」的location ~*规则在这个站点实际不生效。 目前没有泄露风险(Go 侧不提供工作目录文件,未知路径一律 404),但要知道这层保护是空的。
⚠️ 微信 / 小程序业务域名校验:必须让 http 也能直接访问
微信公众平台配置「业务域名」时,会去 http:// 你的域名根目录抓取校验文件
(http://api.yunzer.cn/1XXl8fPHr9.txt)。宝塔默认的 HTTP→HTTPS 强制跳转会把
这个请求 301 到 https,微信拿到重定向就直接判「校验文件验证失败」。
症状:浏览器访问 https://域名/校验文件.txt 完全正常,微信后台却报
「校验文件验证失败,请确认已在域名根目录正确放置校验文件」。
修法:宝塔 → 网站 → 对应站点 → 设置 → 配置文件,在 #HTTP_TO_HTTPS_START 块里
加一条例外(放在 if ($isRedcert != 1) 之前):
# 域名校验文件(微信 / 搜索引擎 / 第三方平台)必须能用 http 直接访问,不能 301 跳 https
if ( $uri ~ "^/[A-Za-z0-9._-]+\.txt$" ) {
set $isRedcert 1;
}
注意:这条必须加在 HTTP_TO_HTTPS 块里。在
location里加location = /xxx.txt没用——server 层的rewrite在 location 匹配之前就执行了,重定向照样发生。
改完 nginx -t && nginx -s reload,然后确认:
curl -i http://api.yunzer.cn/1XXl8fPHr9.txt # 期望 200 + 文件内容,且没有 Location 头
curl -i https://api.yunzer.cn/1XXl8fPHr9.txt # 仍是 200
其它常见原因(按排查顺序):
- 文件必须原样:文件名区分大小写、不能改后缀;内容与微信下载的那份字节级一致,
不能带 BOM / 结尾换行。
xxd verify/xxx.txt确认没有efbbbf开头、没有结尾0a。 - 备案要同步到微信侧:截图里写明「新备案域名需 24 小时后才可配置」,工信部数据同步 到微信侧通常 24~48 小时;备案主体须与小程序主体一致,接入商须与服务器提供商一致。 部分省份还要求已完成公安联网备案。
- 微信侧缓存:全部正确仍失败时,重新点「下载文件」换一个随机文件名放进
verify/, 再保存,可绕过平台短时缓存。 - 小程序主体类型:业务域名只支持企业主体小程序,个人主体 / 海外类型小程序 在微信侧根本不支持配置业务域名(报错形态与校验失败一样)。
- 修改次数限制:服务器域名每月只能改 5 次,业务域名至多 20 个,别反复试。
判定要点:如果访问日志里能看到微信爬虫(UA 类似
Mozilla/4.0)请求校验文件并返回 200, 说明文件校验已通过,剩下的失败只能是备案 / 主体 / 缓存这类平台侧原因, 不要再改服务器配置。
用访问日志判读卡在哪一步
改完 nginx 后,点微信「保存」的同时在另一个窗口执行:
tail -f /www/wwwlogs/api.yunzer.cn.log | grep -i "1XXl8fPHr9\|MP_verify"
| 日志表现 | 卡在哪 | 怎么办 |
|---|---|---|
新增一行,状态 200 |
文件链路正常 | 剩下是备案同步 / 微信缓存,等 24~48 小时或换文件名重试 |
新增一行,状态 404 |
微信要的文件名和你放的不一致 | 重新「下载文件」,原文件原样传进 verify/ |
新增一行,状态 301 |
nginx 例外没生效 | 检查 if ( $uri ~ ^/[A-Za-z0-9._-]+[.]txt$ ) 是否加在 if ($isRedcert != 1) 之前 |
| 一行都没有 | 微信压根没来拉 | 微信在备案校验阶段就拦下了,与文件无关 → 等备案同步,核对主体/接入商 |
公网可达性自查
服务器本机 curl 走的是回环,不代表公网通。微信爬虫在公网,必须用外部验证:
# 从任意一台外部机器/手机流量执行
curl -i http://api.yunzer.cn/1XXl8fPHr9.txt # 期望 200 + 内容,且无 Location 头
或用手机切 4G/5G(不连 WiFi)打开 http://api.yunzer.cn/1XXl8fPHr9.txt,
能看到 1XXl8fPHr9 即为公网可达。