Background
In the previous article, I completed the migration of the Polylang English site from:
https://www.shuijingwanwq.com/en/
to:
https://en.shuijingwanwq.com/
I also verified several key points at the origin:
Polylang 多域名模式正常
W3 Total Cache Page Cache 正常
W3 Total Cache Object Cache 正常
Redis 中旧的 Polylang option 已清理
en 与 www 的页面缓存目录已经分开
At this point, the English subdomain was accessible directly from the origin.
However, my goal was not merely to make en.shuijingwanwq.com accessible. I wanted a clearer CDN architecture:
www.shuijingwanwq.com → EdgeOne → 中文主站 + WordPress 后台
en.shuijingwanwq.com → Cloudflare → 英文前台
media.shuijingwanwq.com → Cloudflare → 上传媒体资源
In other words, the Chinese site would remain behind EdgeOne, the English frontend would use Cloudflare independently, and media assets would continue to be served through Cloudflare.
This arrangement offers several benefits:
英文站可以独立使用 Cloudflare 免费版缓存
中文主站继续保留 EdgeOne 的国内访问表现
媒体资源已经拆分,不会继续增加主站 CDN 流量压力
中英文前台缓存策略可以分开控制

1. Verify That the Origin Is Stable First
Before enabling the Cloudflare proxy, the origin must be confirmed stable.
If Polylang, W3TC, canonical URLs, or hreflang output are still incorrect at the origin, enabling Cloudflare HTML caching too early can easily cache the wrong page.
I had already verified the following:
https://www.shuijingwanwq.com/
→ lang = zh-CN
→ canonical = https://www.shuijingwanwq.com/
https://en.shuijingwanwq.com/
→ lang = en-US
→ canonical = https://en.shuijingwanwq.com/
https://en.shuijingwanwq.com/2026/07/05/18871/
→ lang = en-US
→ canonical = https://en.shuijingwanwq.com/2026/07/05/18871/
W3TC had also generated separate page-cache files for the English subdomain:
wp-content/cache/page_enhanced/en.shuijingwanwq.com/_index_slash_ssl.html
wp-content/cache/page_enhanced/en.shuijingwanwq.com/_index_slash_ssl.html_gzip
wp-content/cache/page_enhanced/en.shuijingwanwq.com/2026/07/05/18871/_index_slash_ssl.html
wp-content/cache/page_enhanced/en.shuijingwanwq.com/2026/07/05/18871/_index_slash_ssl.html_gzip
This confirmed that WordPress, Polylang, and W3TC were functioning correctly at the origin.

2. Switch the en Subdomain from DNS-Only to Proxied in Cloudflare
Next, open Cloudflare and locate:
DNS → en.shuijingwanwq.com
Change this DNS record from DNS-only (gray cloud) to proxied (orange cloud).
After making the switch, do not enable the HTML caching rule yet. First, confirm that Cloudflare is actually proxying the requests.
Run the following command on the server:
getent ahosts en.shuijingwanwq.com | head
The output shows Cloudflare IP addresses:
172.67.216.242 STREAM en.shuijingwanwq.com
172.67.216.242 DGRAM
172.67.216.242 RAW
104.21.78.52 STREAM
104.21.78.52 DGRAM
104.21.78.52 RAW
This confirms that DNS now points to Cloudflare.

Next, use curl -v to confirm that the connection reaches a Cloudflare IP:
curl -4 -v -o /tmp/en-cloudflare-test.html --max-time 20 "https://en.shuijingwanwq.com/?_cfcheck=$(date +%s)" 2>&1 | sed -n '1,80p'
Key output:
Trying 172.67.216.242...
Connected to en.shuijingwanwq.com (172.67.216.242) port 443
Then inspect the response headers:
curl -4 -sS -D - -o /dev/null --max-time 20 "https://en.shuijingwanwq.com/?_cfcheck=$(date +%s)" | grep -Ei "HTTP/|server:|cf-|cache|age|via|ray"
Output:
HTTP/2 200
server: cloudflare
cf-cache-status: DYNAMIC
cf-ray: a18ebf9e4cd9de50-AMS
The cf-cache-status: DYNAMIC value is expected here because Cloudflare is only proxying the request at this stage; HTML caching has not yet been enabled.

3. Confirm That the Cloudflare Proxy Does Not Break Polylang Output
Once Cloudflare is proxying the subdomain, the next step is to confirm that the Polylang output remains intact.
Run:
curl -4 -sS -D - -o /tmp/en-cloudflare-page.html --max-time 20 "https://en.shuijingwanwq.com/" | sed -n '1,30p'
grep -o '<html[^>]*>' /tmp/en-cloudflare-page.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]canonical["'\''"][^>]*>' /tmp/en-cloudflare-page.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]alternate["'\''"][^>]*hreflang=["'\''"][^>]*>' /tmp/en-cloudflare-page.html | head -n 10
Output:
HTTP/2 200
server: cloudflare
cf-cache-status: DYNAMIC
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
<link rel="alternate" href="https://www.shuijingwanwq.com/" hreflang="zh" />
<link rel="alternate" href="https://en.shuijingwanwq.com/" hreflang="en" />
This confirms that:
Cloudflare 橙云已经接管 en
Polylang 输出仍然是英文首页
canonical 正确
hreflang 正确
当前还没有启用 Cloudflare HTML 缓存

4. Enable the Cloudflare HTML Page Cache Rule
After confirming that the proxy works correctly, enable the HTML page cache rule that was prepared in Cloudflare earlier.
The rule set is designed roughly as follows:
普通英文前台页面:允许 HTML 缓存
/wp-admin/:绕过缓存
/wp-login.php:绕过缓存
/wp-json/:绕过缓存
带 wordpress_logged_in Cookie:绕过缓存
In Cloudflare Cache Rules, locate the rule that was configured earlier but left disabled:
HTML 页面缓存(SEO安全)
Enable it.
I did not change the rule expression or reorder the rules because the cache-bypass rules for the admin area, login page, REST API, and logged-in users had already been configured.

After enabling the rule, first test whether it matches a URL containing a query parameter:
for i in 1 2 3
do
echo "================ request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-html-cache.html --max-time 20 \
"https://en.shuijingwanwq.com/?_cfhtmltest=$(date +%s)" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|vary|etag|last-modified|cf-ray"
grep -o '<html[^>]*>' /tmp/en-cf-html-cache.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]canonical["'\''"][^>]*>' /tmp/en-cf-html-cache.html | head -n 1
echo
sleep 2
done
The output includes:
cache-control: max-age=14400
cf-cache-status: MISS
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
Each request returns MISS because every URL contains a different timestamp parameter.
From Cloudflare’s perspective:
/?_cfhtmltest=178367xxxx
Each request is a different URL, so Cloudflare creates a separate cache object every time.
The result is still useful because it confirms that:
Cloudflare HTML 缓存规则已经匹配到了
页面仍然是 en-US
canonical 仍然指向 en
5. Verify That the English Homepage Moves from MISS to HIT
Next, test the English homepage without a query parameter:
for i in 1 2 3
do
echo "================ request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-html-cache.html --max-time 20 \
"https://en.shuijingwanwq.com/" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|vary|etag|last-modified|cf-ray"
grep -o '<html[^>]*>' /tmp/en-cf-html-cache.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]canonical["'\''"][^>]*>' /tmp/en-cf-html-cache.html | head -n 1
echo
sleep 2
done
Output:
================ request 1 ================
HTTP/2 200
server: cloudflare
cache-control: max-age=14400
cf-cache-status: MISS
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
================ request 2 ================
HTTP/2 200
server: cloudflare
age: 4
cache-control: max-age=14400
cf-cache-status: HIT
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
================ request 3 ================
HTTP/2 200
server: cloudflare
age: 9
cache-control: max-age=14400
cf-cache-status: HIT
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
This confirms that the English homepage is now stored in Cloudflare’s HTML cache.
Even after the cache is hit, the page still reports:
lang = en-US
canonical = https://en.shuijingwanwq.com/

6. Verify That an English Post Moves from MISS to HIT
After the homepage passes the test, an English post should be checked as well.
Run:
for i in 1 2 3
do
echo "================ request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-post-cache.html --max-time 20 \
"https://en.shuijingwanwq.com/2026/07/05/18871/" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|vary|etag|last-modified|cf-ray"
grep -o '<html[^>]*>' /tmp/en-cf-post-cache.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]canonical["'\''"][^>]*>' /tmp/en-cf-post-cache.html | head -n 1
echo
sleep 2
done
Output:
================ request 1 ================
HTTP/2 200
server: cloudflare
cache-control: max-age=14400
cf-cache-status: MISS
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/2026/07/05/18871/" />
================ request 2 ================
HTTP/2 200
server: cloudflare
age: 4
cache-control: max-age=14400
cf-cache-status: HIT
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/2026/07/05/18871/" />
================ request 3 ================
HTTP/2 200
server: cloudflare
age: 8
cache-control: max-age=14400
cf-cache-status: HIT
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/2026/07/05/18871/" />
This confirms that the English post has also been cached successfully by Cloudflare.

7. Verify That Logged-In User Cookies Do Not Hit the Public Cache
When caching WordPress HTML with Cloudflare, the main concern is not whether the page can produce a HIT. The real risk is serving the public cache to a logged-in user, or exposing a logged-in page to public visitors.
Requests carrying a login cookie must therefore be verified as non-HIT responses.
Run:
for i in 1 2
do
echo "================ logged-in cookie request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-cookie-bypass.html --max-time 20 \
-H "Cookie: wordpress_logged_in_test=1" \
"https://en.shuijingwanwq.com/" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|vary|cf-ray"
grep -o '<html[^>]*>' /tmp/en-cf-cookie-bypass.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]canonical["'\''"][^>]*>' /tmp/en-cf-cookie-bypass.html | head -n 1
echo
sleep 2
done
Output:
HTTP/2 200
server: cloudflare
cf-cache-status: DYNAMIC
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
The important result is:
cf-cache-status: DYNAMIC
rather than:
cf-cache-status: HIT
This confirms that requests containing a wordpress_logged_in-related cookie do not hit Cloudflare’s public HTML cache.

8. Verify That the REST API Is Not Cached
The WordPress REST API must also be excluded from HTML caching.
Run:
for i in 1 2
do
echo "================ wp-json request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-rest-api.html --max-time 20 \
"https://en.shuijingwanwq.com/wp-json/" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|content-type|cf-ray"
head -c 120 /tmp/en-cf-rest-api.html
echo
echo
sleep 2
done
The final result confirms:
server: cloudflare
content-type: application/json; charset=UTF-8
cf-cache-status: DYNAMIC
As long as /wp-json/ does not return HIT, the REST API has not been incorrectly stored in Cloudflare’s HTML cache.

9. Verify That the Login Page and Admin Entry Point Are Not Cached
Next, test the login page:
for i in 1 2
do
echo "================ wp-login request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-login.html --max-time 20 \
"https://en.shuijingwanwq.com/wp-login.php" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|content-type|set-cookie|cf-ray"
grep -o '<title[^>]*>.*</title>' /tmp/en-cf-login.html | head -n 1
echo
sleep 2
done
Output:
HTTP/2 200
content-type: text/html; charset=UTF-8
server: cloudflare
cache-control: no-cache, must-revalidate, max-age=0, no-store, private
set-cookie: wordpress_test_cookie=WP%20Cookie%20check; path=/; secure; HttpOnly
cf-cache-status: DYNAMIC
<title>Log In ‹ Yongye — WordPress</title>
Then verify the admin URL:
for i in 1 2
do
echo "================ wp-admin request $i ================"
curl -4 -sS -D - -o /tmp/en-cf-admin.html --max-time 20 \
"https://en.shuijingwanwq.com/wp-admin/" \
| grep -Ei "HTTP/|server:|location:|cf-cache-status|age:|cache-control|content-type|set-cookie|cf-ray"
echo
sleep 2
done
Output:
HTTP/2 302
location: https://en.shuijingwanwq.com/wp-login.php?redirect_to=https%3A%2F%2Fen.shuijingwanwq.com%2Fwp-admin%2F&reauth=1
server: cloudflare
cache-control: no-cache, must-revalidate, max-age=0, no-store, private
cf-cache-status: DYNAMIC
This confirms that:
/wp-login.php 不缓存
/wp-admin/ 不缓存
登录页会正常设置 wordpress_test_cookie
后台入口会正常跳转到登录页

10. Consolidate Non-www Admin URLs on the www Domain
After completing these checks, I noticed one more structural issue:
Although en.shuijingwanwq.com/wp-admin/ and en.shuijingwanwq.com/wp-login.php were correctly excluded from Cloudflare caching, the English subdomain should not serve as an admin entry point in the first place.
A cleaner structure is:
英文前台:en.shuijingwanwq.com
WordPress 后台:www.shuijingwanwq.com
This avoids several problems:
避免后台入口分散在多个 Host 上
避免登录 Cookie 在 en 与 www 之间混乱
避免后续安全规则、缓存规则越来越复杂
后台管理统一从 www 进入,更容易维护
I therefore decided to add a rule at the Nginx layer:
只要不是 www.shuijingwanwq.com
并且访问的是 /wp-admin/ 或 /wp-login.php
就统一 301 到 www.shuijingwanwq.com
Note that /wp-json/ is intentionally not included in this redirect.
Frontend pages, the block editor, and REST API output may still use /wp-json/ on the corresponding language domain. Keeping /wp-json/ as DYNAMIC is safer for now, so there is no need to force a redirect.
11. Add the Nginx Redirect Rule for Admin URLs
First, back up the Nginx virtual host configuration:
cp /usr/local/nginx/conf/vhost/www.shuijingwanwq.com.conf \
/usr/local/nginx/conf/vhost/www.shuijingwanwq.com.conf.bak.$(date +%Y%m%d%H%M%S)
Then open:
/usr/local/nginx/conf/vhost/www.shuijingwanwq.com.conf
and, immediately before:
include /usr/local/nginx/conf/rewrite/wordpress.conf;
insert:
# Redirect non-www admin/login requests to the main www domain.
set $redirect_non_www_admin "";
if ($host != www.shuijingwanwq.com) {
set $redirect_non_www_admin "${redirect_non_www_admin}H";
}
if ($uri ~* "^/(wp-admin(?:/|$)|wp-login\.php$)") {
set $redirect_non_www_admin "${redirect_non_www_admin}U";
}
if ($redirect_non_www_admin = "HU") {
return 301 https://www.shuijingwanwq.com$request_uri;
}Test the Nginx configuration:
nginx -t
Output:
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
Finally, restart Nginx:
service nginx restart

12. Verify That en Admin URLs Redirect to www
After adding the rule, first verify the origin Nginx response directly:
curl -k -sS -D - -o /dev/null --max-time 10 \
--resolve en.shuijingwanwq.com:443:127.0.0.1 \
"https://en.shuijingwanwq.com/wp-login.php" \
| grep -Ei "HTTP/|server:|location:|cache-control"
Output:
HTTP/2 301
server: nginx
location: https://www.shuijingwanwq.com/wp-login.php
This confirms that the origin rule works correctly.
Next, verify the behavior through the public network and Cloudflare:
for i in 1 2 3
do
echo "================ en wp-login public request $i ================"
curl -4 -sS -D - -o /dev/null \
--connect-timeout 10 --max-time 30 \
"https://en.shuijingwanwq.com/wp-login.php?_redirecttest=$(date +%s)" \
| grep -Ei "HTTP/|server:|location:|cf-cache-status|cache-control|cf-ray"
echo
sleep 2
done
Output:
HTTP/2 301
location: https://www.shuijingwanwq.com/wp-login.php?_redirecttest=1783679154
server: cloudflare
cf-cache-status: DYNAMIC
Then verify the admin URL:
https://en.shuijingwanwq.com/wp-admin/
→ 301
→ https://www.shuijingwanwq.com/wp-admin/
The admin URLs on www continue to behave normally:
https://www.shuijingwanwq.com/wp-admin/
→ 302 到 www 的 wp-login.php
https://www.shuijingwanwq.com/wp-login.php
→ 200
The admin entry points are now consolidated on the main domain.

13. Final Regression Test: Confirm That English Frontend Caching Still Works
Finally, confirm that the new Nginx rule has not affected the English frontend.
Run:
for u in \
"https://en.shuijingwanwq.com/" \
"https://en.shuijingwanwq.com/2026/07/05/18871/"
do
echo "================ $u ================"
curl -4 -sS -D - -o /tmp/en-final-check.html --max-time 20 "$u" \
| grep -Ei "HTTP/|server:|cf-cache-status|age:|cache-control|location:|cf-ray"
grep -o '<html[^>]*>' /tmp/en-final-check.html | head -n 1
grep -o '<link[^>]*rel=["'\''"]canonical["'\''"][^>]*>' /tmp/en-final-check.html | head -n 1
echo
done
Output:
================ https://en.shuijingwanwq.com/ ================
HTTP/2 200
server: cloudflare
age: 28
cache-control: max-age=14400
cf-cache-status: HIT
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/" />
================ https://en.shuijingwanwq.com/2026/07/05/18871/ ================
HTTP/2 200
server: cloudflare
age: 28
cache-control: max-age=14400
cf-cache-status: HIT
<html lang="en-US">
<link rel="canonical" href="https://en.shuijingwanwq.com/2026/07/05/18871/" />
This confirms that:
英文首页仍然 HIT
英文文章页仍然 HIT
lang 仍然是 en-US
canonical 仍然指向 en
没有被后台跳转规则误伤

Final Architecture
At this point, the English subdomain has been fully integrated with Cloudflare.
The final architecture is:
www.shuijingwanwq.com
→ EdgeOne
→ 中文前台 + WordPress 后台入口
en.shuijingwanwq.com
→ Cloudflare
→ 英文前台 + HTML 页面缓存
media.shuijingwanwq.com
→ Cloudflare
→ uploads 媒体资源
The unified WordPress admin entry points are:
https://www.shuijingwanwq.com/wp-admin/
https://www.shuijingwanwq.com/wp-login.php
Admin URLs on non-www domains redirect to www:
https://en.shuijingwanwq.com/wp-admin/
→ https://www.shuijingwanwq.com/wp-admin/
https://en.shuijingwanwq.com/wp-login.php
→ https://www.shuijingwanwq.com/wp-login.php
Cloudflare cache verification results:
普通 en 首页:
cf-cache-status: HIT
普通 en 英文文章页:
cf-cache-status: HIT
带 wordpress_logged_in Cookie:
cf-cache-status: DYNAMIC
/wp-json/:
cf-cache-status: DYNAMIC
/wp-login.php:
cf-cache-status: DYNAMIC
/wp-admin/:
cf-cache-status: DYNAMIC 或 301/302 跳转,不 HIT
Lessons from This Configuration
This configuration reinforced one important lesson: when caching WordPress HTML with Cloudflare, seeing HIT is not enough.
The entire request and caching path must be verified:
DNS 是否已经切到 Cloudflare
响应头是否出现 server: cloudflare
HTML 页面是否从 MISS 到 HIT
html lang 是否正确
canonical 是否正确
hreflang 是否正确
登录 Cookie 是否绕过缓存
REST API 是否绕过缓存
登录页是否绕过缓存
后台入口是否绕过缓存
后台入口是否需要统一收敛到主域名
This is especially important in Polylang’s domain-per-language mode. A cf-cache-status: HIT response alone does not prove that the setup is correct.
The cached page must still return:
<html lang="en-US">
canonical = https://en.shuijingwanwq.com/
Otherwise, Cloudflare may cache HTML for the wrong language, canonical URL, or Host.
The final structure used in this setup is:
中文主站继续走 EdgeOne
英文前台单独走 Cloudflare
媒体资源继续走 Cloudflare
后台入口统一回 www
For my current site, this architecture is clearer than placing everything behind a single CDN, and it makes both cost control and cache-rule management easier.
需要长期技术维护或远程问题排查?
我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。
如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:
- ✅ PHP / Laravel / Yii2 老项目无人维护
- ✅ Go / Gin 后端接口需要排查或优化
- ✅ WordPress 网站访问慢、报错或插件冲突
- ✅ Nginx / MySQL / Redis / Linux 服务器异常
- ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
- ✅ 需要长期远程技术支持或兼职维护
更多介绍请查看:关于我 & 合作
微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

发表回复