WordPress 接入 CDN 后登录失败、重定向过多 —— 完整排查与缓存配置
适用环境:WordPress + Zibll 主题 / 宝塔面板 / Dooki CDN
站点示例:www.333610.xyz,根目录/www/wwwroot/test
一、故障现象
- 走 CDN 打开站点,点登录后提示「验证失败,请刷新 / 400 错误」
- 本地改 hosts 直连源站 IP,登录完全正常
- 修改
wp-config.php之后,全站开始ERR_TOO_MANY_REDIRECTS(重定向过多) - 开发者工具里
admin-ajax.php大量 400,响应体是0 - 后来在后台发布文章,报「此响应不是合法的 JSON 响应」
二、根因分析
1. CDN 回源丢失 www,WordPress 自己跳自己(真正的元凶)
CDN 回源时 Host 是裸域 333610.xyz,而 WordPress 的站点地址是 https://www.333610.xyz,于是每次请求都被 301 到 www;浏览器到了 www 之后,CDN 回源又变成裸域,再次 301,形成无限循环。
决定性证据:
- 公网 301 响应的
location与当前 URL 完全一致 - 响应头带有
x-redirect-by: WordPress
2. wp-config.php 被粘贴进反引号
出现过这种写法:
define('WP_HOME','`https://333610.xyz`');
字符串里混入了反引号,站内地址随之错乱。这是复制粘贴带来的,肉眼极难发现。
3. 源站证书是别的域名
源站 SSL 目录里挂的是 *.383007.xyz 的通配符证书,与本站域名不匹配,所以当时只能走 HTTP 回源,一旦改成 HTTPS 回源立刻报 526。
4. CDN 不发送 X-Forwarded-Proto
wp-config 里按条件判断的写法永远不成立,源站始终以为自己是被 HTTP 访问,Cookie 与跳转判断跟着出错。正确做法是不再判断,直接声明为 HTTPS。
5. admin-ajax 的 400 大部分是噪音
不带 action 参数的 GET 打到 admin-ajax.php,WordPress 固定返回 400 且响应体为 0,这是正常行为。带上 ?action=search_box 时就是 200。
看到 400 先别慌:看它有没有
action参数、响应体是不是0。两者都符合就不用管。
三、最终生效的配置
1. wp-config.php
以下内容必须放在 require_once ABSPATH . 'wp-settings.php'; 之前:
// 站点前面有 CDN 终结 HTTPS,源站一律按 HTTPS 处理,避免 301 循环
$_SERVER['HTTPS'] = 'on';
// 站点地址统一为 https + www(字符串里千万不要有反引号)
define( 'WP_HOME', 'https://www.333610.xyz' );
define( 'WP_SITEURL', 'https://www.333610.xyz' );
改完必须自查,输出里的地址前后不能出现反引号:
grep -n "WP_HOME\|WP_SITEURL" /www/wwwroot/aonan/wp-config.php
php -l /www/wwwroot/aonan/wp-config.php
# 必须输出 No syntax errors detected
2. Nginx 站点配置
文件位置:/www/server/panel/vhost/nginx/333610.xyz.conf
| 位置 | 错误写法 | 正确写法 |
|---|---|---|
| 497 跳转 | error_page 497 `https://$host$request_uri; | error_page 497 https://$host$request_uri; |
| 访问日志 | access_log /dev/null; | access_log /www/wwwlogs/333610.xyz.log; |
| TLS 版本 | ssl_protocols TLSv1.3; | ssl_protocols TLSv1.2 TLSv1.3; |
改完执行:
nginx -t && nginx -s reload
3. CDN 源站设置(决定性一项)
| 选项 | 值 | 说明 |
|---|---|---|
| 回源 Host / 回源域名 | www.333610.xyz | 修复登录与重定向的关键,不要改回裸域 |
| 回源协议 | HTTPS | 证书正确后才可改,否则先用 HTTP |
| 回源端口 | 443 | 配合 HTTPS 回源 |
四、CDN 缓存配置教程
缓存是优化手段,不是修复手段。它治不了登录 400,也治不了重定向循环。先保证站点正常,再开缓存。
核心原则
- HTML 一律不缓存。 开启伪静态后绝大多数页面都是 HTML,缓存 HTML 会把登录态、nonce、验证码固定住。
- 只按文件扩展名缓存静态资源。 图片、CSS、JS、字体才缓存。
- 动态入口一律不缓存:
wp-admin、wp-login.php、wp-json、user-sign、captcha.php。
步骤 1:缓存对象选「文件扩展名」
每个扩展名都要带前导点,用空格分隔:
.css .js
.zip .gzip .tar .7z .bzip2 .dmg .gz
.tif .tiff .bmp .png .gif .jpg .jpeg .svg .webp .ico .psd .tga .imb
.mp3 .mp4 .avi .mpeg .aac .rmvb .mkv .flv .swf .mov
.woff .woff2 .ttf .otf .eot
两个常见错误: 一是 css、js 忘了前面的点;二是漏掉
.png、.gif、.svg、.webp、.ico,而它们恰恰是最主要的图片。
步骤 2:有效期与参数
| 选项 | 建议值 | 原因 |
|---|---|---|
| 缓存有效期 | 30 天 | 命中率高、回源压力小,WordPress 自带 ?ver= 版本号兜底 |
| 忽略 URI 参数 | 不勾选 | 勾了以后 style.css?ver=1.2 失效,改了主题 CSS 访客看到旧的 |
步骤 3:不缓存规则(必须保留)
URL目录前缀: /wp-admin/*
URL目录前缀: /wp-login.php
URL目录前缀: /wp-json/*
URL目录前缀: /user-sign
captcha.php 没有文件后缀,按「扩展名规则」永远不会命中,所以滑块验证图天然不会被缓存。
步骤 4:验证是否生效
看响应头里的 x-cache:MISS / BYPASS 表示回源了,HIT 表示命中缓存。
# 连续两次请求同一静态文件,第二次应出现 HIT
curl -sI https://www.333610.xyz/wp-content/themes/zibll/css/main.min.css | grep -i x-cache
curl -sI https://www.333610.xyz/wp-content/themes/zibll/css/main.min.css | grep -i x-cache
# 登录页必须是 BYPASS,绝不能是 HIT
curl -sI https://www.333610.xyz/wp-login.php | grep -i x-cache
五、防火墙误拦:后台发布文章报「此响应不是合法的 JSON 响应」
现象
古腾堡编辑器点「发布」失败,提示:
发布失败。此响应不是合法的 JSON 响应。
定位
F12 → 网络 → 发布时失败的那条请求(POST /wp-json/wp/v2/posts)→ 看状态码和响应体。返回的是 HTML 而不是 JSON。
最快验证:临时关掉宝塔 Nginx 防火墙,再点发布。能发 → 就是防火墙拦的。
真正的拦截规则
在防火墙日志里可以看到:
| 项目 | 内容 |
|---|---|
| 类型 | POST |
| 过滤器 | 拦截分块请求 |
| 过滤规则 | 拦截 Transfer-Encoding 块请求 |
宝塔防火墙把「分块传输(chunked)」的 POST 一律当攻击拦掉。古腾堡发布、admin-ajax 都可能触发,属于误杀。
处理
- 防火墙 → 全局配置 / 基础设置 → 找到「拦截分块传输 / Transfer-Encoding / Chunked 请求」开关 → 关闭,保存
关掉不影响安全:现代浏览器、WordPress、CDN 回源都正常使用 chunked,防请求走私应该在 Nginx 层做,而不是业务 WAF 一刀切。 - 日志里标注「并且被封锁IP」的,去 IP 黑名单 把误封 IP 删掉。
- 补充 URL 白名单(防火墙 → URL 白名单):
^/wp-json/
^/wp-admin/
^/wp-login.php
^/wp-cron.php
顺带:别误封正常爬虫
日志里的 Bytespider(字节跳动 / 头条蜘蛛)是正常爬虫,被封锁会影响头条收录,发现误封要解封。
长期建议
WordPress 走 CDN 时,下面这些路径必须放行,属于正常业务而非攻击面:
/wp-json/ # 古腾堡发布、区块编辑器
/wp-admin/admin-ajax.php
/wp-login.php
/wp-cron.php
安全防护重点应放在 /wp-login.php 的登录失败限速上,而不是拦 /wp-json/。
六、排错速查表
| 现象 | 大概率原因 | 处理 |
|---|---|---|
| 526 Invalid SSL certificate | HTTPS 回源但源站证书域名不匹配或过期 | 换正确证书,或先改回 HTTP 回源 |
| 525 SSL handshake failed | 源站只允许 TLS1.3 | 改为 TLSv1.2 TLSv1.3 |
| 444 | 回源落到 catch-all 块 | server_name 同时包含 www 与非 www |
| 重定向过多 | 回源 Host 丢 www / wp-config 有反引号 / 两条方向相反的 301 | 固定回源 Host,检查字符串与跳转方向 |
| admin-ajax 400 且响应体为 0 | 无 action 参数的正常噪音 | 忽略即可 |
| 验证失败,请刷新 | nonce / session / Cookie 失效 | 先确认 HTTPS 识别,再清 Cookie 与缓存 |
| 502 Bad Gateway | php-fpm worker 卡死 | pkill -9 php-fpm 后按版本逐个启动 |
| 发布文章报「不是合法的 JSON 响应」 | 防火墙拦截 chunked POST(Transfer-Encoding) | 关闭「拦截分块传输」规则,加 /wp-json/ 白名单 |
七、上线检查清单
必须
- 回源 Host 固定为
www.333610.xyz WP_HOME/WP_SITEURL无多余的反引号、无空格php -l通过,php-fpm 已重启wp-admin/wp-login.php/wp-json/user-sign全部不缓存- 防火墙放行
/wp-json/、/wp-admin/、/wp-login.php、/wp-cron.php - 无痕窗口登录测试通过
禁止
- 把
.php、.log、.sql加进缓存扩展名 - 勾选「忽略 URI 参数」
八、通用排查顺序
- 先分清是谁在出错:开发者工具响应头里,
server是 Dooki CDN 还是 nginx;响应体是 HTML 错误页还是0。 - 直连源站对照:
curl -sI http://127.0.0.1/ -H "Host: www.域名"。源站 200 而公网异常,问题就在 CDN。 - 看跳转链:
location等于当前 URL 就是自己跳自己。 - 改 hosts 直连:能通说明源站没问题,把排查集中在 CDN。
- 逐项关闭防护:5 秒盾、CC 防护、WAF、防火墙、内容压缩、页面优化,一次只改一项。
- 最后才动缓存:缓存几乎不会是登录类故障的原因。













暂无评论内容