2026年11月12日
2026年11月12日
WordPress 设置 Cloudflare 的步骤|切换名称服务器、SSL、还原真实 IP、WAF
本文是日语原文的本地化版本。 阅读日语原文
为 WordPress 接入 Cloudflare,按下面的顺序进行:①把站点添加到 Cloudflare 并切换域名的名称服务器,②把 SSL/TLS 加密模式设为 Full (strict),③在服务器端还原访客的真实 IP,④用 WAF 自定义规则保护登录页。免费套餐也能使用 CDN、SSL、DDoS 防护和自定义规则(最多 5 条)。
本文说明各项设置,以及切换之后需要确认的地方。Cloudflare 界面中的名称和位置可能变动,因此这里依据 2026 年 11 月时的官方文档(developers.cloudflare.com)来写。
动手之前先确定的事项
- 这意味着要把 DNS 的管理交给 Cloudflare。域名的注册商(Registrar)不会变,但 DNS 记录要改在 Cloudflare 的界面中编辑。
- 邮件相关的 DNS 记录(MX 等)不要开启代理。经过 Cloudflare 的只有 Web 通信(HTTP/HTTPS)。
- 确认源站(放置 WordPress 的服务器)上有有效的 SSL 证书。如果已经用 Let's Encrypt 等启用了 HTTPS,保持现状即可。
- 如果在注册商处启用了 DNSSEC,请在切换名称服务器之前先将其关闭。残留旧的 DS 记录会导致域名解析失败。
步骤 1:添加站点并切换名称服务器
- 创建 Cloudflare 账号,在控制台(Dashboard)中添加域名。套餐可以选择 Free。
- Cloudflare 会读取当前的 DNS 记录并列出来,请确认有没有遗漏。有些记录无法被读取,请与现在的 DNS 管理界面对照,缺少的手动补上。
- 网站的
A(或AAAA、CNAME)记录,把代理状态设为开启(橙色云朵)。MX以及邮件服务器用的A记录设为关闭(仅 DNS,灰色云朵)。 - Cloudflare 会显示 2 个名称服务器的名称。名称形如
〇〇.ns.cloudflare.com,每个账号分配到的都不同。请使用你自己界面上显示的这 2 个,而不是其他文章里写的名称。 - 在域名注册商的管理界面中,把名称服务器改为这 2 个。
用下面的命令确认是否已经切换。生效可能需要几个小时。
# 名称服务器是否已变为 Cloudflare 的那 2 个
dig NS example.com +short
# 是否已经过 Cloudflare(会返回 server: cloudflare 和 cf-ray)
curl -sI https://example.com | grep -iE '^(server|cf-ray):'
在 Cloudflare 界面中,域名状态变为有效(Active)后,切换就完成了。
步骤 2:把 SSL/TLS 设为 Full (strict)
Cloudflare 的 SSL/TLS 有多种模式,决定访客与 Cloudflare 之间、Cloudflare 与源站之间如何加密。
| 模式 | Cloudflare 与源站之间 | 在 WordPress 中的处理 |
|---|---|---|
| Off | 不加密 | 不使用 |
| Flexible | HTTP(不加密) | 不使用。会导致重定向循环和混合内容 |
| Full | HTTPS(不验证证书) | 在准备好证书之前的过渡方案 |
| Full (strict) | HTTPS(验证证书) | 选这个 |
设置在 Cloudflare 控制台 SSL/TLS 的概述(Overview)页面中更改。默认的“Automatic SSL/TLS”会在源站支持的范围内自动选择安全的模式。自己选定 Full (strict),就不会以非预期的模式运行。源站的证书可以使用公共证书颁发机构(Let's Encrypt 等)的证书,或 Cloudflare 签发的 Origin CA 证书。
避免使用 Flexible 的原因如下。在 Flexible 下,请求以 HTTP 到达源站,于是 WordPress 或服务器回应“因为是 HTTP 来的,所以转到 HTTPS”,Cloudflare 又以 HTTP 去源站取内容,如此不断重复(浏览器中会显示 ERR_TOO_MANY_REDIRECTS)。使用 Full (strict) 时,请求也是以 HTTPS 到达源站,所以 WordPress 一侧不需要再添加根据 X-Forwarded-Proto 改写 $_SERVER['HTTPS'] 之类的额外代码。
同时请确认 WordPress 的“设置”(Settings)→“常规”(General)中的“WordPress 地址(URL)”和“站点地址(URL)”是 https://。如果图片等仍保留 http://,请参考混合内容的修复方法。
步骤 3:还原访客的真实 IP
经过 Cloudflare 后,到达服务器的连接来源(REMOTE_ADDR)会变成 Cloudflare 的 IP 地址。这样一来,访问日志、评论的 IP、限制登录尝试的插件等,都会把所有访客当作 Cloudflare 的 IP。Cloudflare 通过 CF-Connecting-IP 头传递访客的 IP,因此要设置成只有当连接来源是 Cloudflare 时才信任这个头。
如果不确认连接来源,就直接用头里的值改写 REMOTE_ADDR,那么不经过 Cloudflare、直接访问源站的人,就能通过这个头冒用任意 IP。旧文章里那种“只要有 HTTP_CF_CONNECTING_IP 就赋值给 REMOTE_ADDR”的代码,正是出于这个原因,请不要使用。
Cloudflare 的 IP 地址列表公开在 https://www.cloudflare.com/ips/。列表可能会变动,请定期检查。
Nginx 的情况
使用 ngx_http_realip_module。在 http 块或 server 块中,列出 Cloudflare 的全部网段。
# Cloudflare 的 IP 范围(截至 2026 年 11 月。最新内容请在 cloudflare.com/ips 确认)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
sudo nginx -t && sudo systemctl reload nginx
Apache 的情况(Debian / Ubuntu)
使用 mod_remoteip。创建 /etc/apache2/conf-available/remoteip.conf,把 Cloudflare 的网段列在 RemoteIPTrustedProxy 中。
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22
RemoteIPTrustedProxy 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20
RemoteIPTrustedProxy 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13
RemoteIPTrustedProxy 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22
RemoteIPTrustedProxy 2400:cb00::/32 2606:4700::/32 2803:f800::/32 2405:b500::/32
RemoteIPTrustedProxy 2405:8100::/32 2a06:98c0::/29 2c0f:f248::/32
sudo a2enmod remoteip
sudo a2enconf remoteip
sudo apache2ctl configtest
sudo systemctl restart apache2
要在访问日志中输出真实 IP,请把 /etc/apache2/apache2.conf 中 LogFormat(combined)里的 %h 改为 %a。
无法修改服务器设置的情况(wp-config.php)
在租用的虚拟主机等无法改动 Web 服务器配置的环境中,可以在 wp-config.php 中做同样的判断。把它放在 require_once ABSPATH . 'wp-settings.php'; 这一行之前。只有当连接来源在 Cloudflare 的网段内时,才使用 CF-Connecting-IP 的值(必须是合法的 IP 地址)。
<?php
// 仅在经过 Cloudflare 时,才把 CF-Connecting-IP 当作访客的 IP
$cf_ranges = [
'173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22',
'141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20',
'197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/13',
'104.24.0.0/14', '172.64.0.0/13', '131.0.72.0/22',
'2400:cb00::/32', '2606:4700::/32', '2803:f800::/32', '2405:b500::/32',
'2405:8100::/32', '2a06:98c0::/29', '2c0f:f248::/32',
];
function cf_ip_in_range(string $ip, string $cidr): bool
{
[$net, $bits] = explode('/', $cidr);
$ip_bin = inet_pton($ip);
$net_bin = inet_pton($net);
if ($ip_bin === false || $net_bin === false || strlen($ip_bin) !== strlen($net_bin)) {
return false;
}
$bits = (int) $bits;
$bytes = intdiv($bits, 8);
if ($bytes > 0 && substr($ip_bin, 0, $bytes) !== substr($net_bin, 0, $bytes)) {
return false;
}
$rest = $bits % 8;
if ($rest === 0) {
return true;
}
$mask = (0xFF << (8 - $rest)) & 0xFF;
return (ord($ip_bin[$bytes]) & $mask) === (ord($net_bin[$bytes]) & $mask);
}
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP']) && !empty($_SERVER['REMOTE_ADDR'])) {
foreach ($cf_ranges as $range) {
if (cf_ip_in_range($_SERVER['REMOTE_ADDR'], $range)) {
$visitor = filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP);
if ($visitor !== false) {
$_SERVER['REMOTE_ADDR'] = $visitor;
}
break;
}
}
}
wp-config.php 一开始就有 <?php,所以不要抄写第 1 行的 <?php,从第 2 行开始粘贴。粘贴之前请先备份 wp-config.php。
步骤 4:用 WAF 自定义规则保护登录页
Cloudflare WAF 的自定义规则,在免费套餐中最多可以创建 5 条,并且可以选择 Log 以外的动作(Block、Managed Challenge 等)。创建方法:在控制台的 Security rules 页面点击“Create rule”,选择“Custom rules”,指定条件(Field、Operator、Value)和动作,然后“Deploy”。
示例 1:只对自己的 IP 开放登录页和后台
适用于有家庭或公司固定 IP 的情况。写成表达式如下(请把 203.0.113.10 和 198.51.100.0/24 换成你自己的 IP)。
(http.request.uri.path eq "/wp-login.php" or starts_with(http.request.uri.path, "/wp-admin/"))
and http.request.uri.path ne "/wp-admin/admin-ajax.php"
and not ip.src in {203.0.113.10 198.51.100.0/24}
动作选 Block。/wp-admin/admin-ajax.php 有时会被联系表单、无限滚动等公开页面的功能在未登录状态下调用,所以已从条件中排除。
示例 2:没有固定 IP 时,用国家和 Managed Challenge 来限制
(http.request.uri.path eq "/wp-login.php" or http.request.uri.path eq "/xmlrpc.php")
and not ip.src.country in {"JP"}
国家的判定使用 ip.src.country(ISO 3166-1 的两位字母代码)。旧文章里的 ip.geoip.country 已不推荐使用。动作建议一开始先用 Managed Challenge,在安全事件(Security events)中确认没有拦住正当访问之后,再按需改为 Block。Cloudflare 的文档也推荐这样的做法。xmlrpc.php 在通过 Jetpack 或手机 App 发布文章时会被用到,所以请先确认是否在使用,再把它加入条件。
按国家限制是可以被 VPN 等绕过的辅助措施。请与双重验证和登录次数限制组合使用。在 Nginx 一侧按国家判定的方法,参见 Nginx 用 GeoIP2 按国家限制访问。
步骤 5:缓存的默认行为与发布时的清除
Cloudflare 默认不缓存 HTML。它缓存的是图片、CSS、JavaScript、字体等按扩展名确定的静态文件。另外,包含 Set-Cookie 头的响应也不会被缓存。所以只要不做任何设置,后台和登录页就不会被 Cloudflare 缓存。
如果想连 HTML 也缓存,可以用 Cache Rules 扩大范围,但这时必须把 /wp-admin/、/wp-login.php、预览以及已登录用户看到的页面排除在外。排除方式出错的话,面向管理员的页面可能会显示给其他人,所以没有把握的话,保持默认最稳妥。
替换了 CSS 或图片但显示没有变化时,可以在控制台的缓存设置中清除(Purge)缓存。如果想在每次发布或更新文章时自动清除,可以调用 Cloudflare 的 API。首先在 Cloudflare 中创建一个只具有“Cache Purge”权限的 API 令牌,再与区域 ID(显示在域名的概述页面)一起,用常量写入 wp-config.php。
define( 'CF_ZONE_ID', '你的区域ID' );
define( 'CF_API_TOKEN', '你的API令牌' );
把下面的代码放进子主题的 functions.php,或放进自己写的小插件(用 Code Snippets 等也可以)。
<?php
// 文章发布或更新后,从 Cloudflare 清除该文章和首页的缓存
function cf_purge_urls(array $urls): bool
{
if (!defined('CF_ZONE_ID') || !defined('CF_API_TOKEN')) {
return false;
}
$response = wp_remote_post(
'https://api.cloudflare.com/client/v4/zones/' . CF_ZONE_ID . '/purge_cache',
[
'headers' => [
'Authorization' => 'Bearer ' . CF_API_TOKEN,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode(['files' => array_values($urls)]),
'timeout' => 15,
]
);
if (is_wp_error($response)) {
error_log('Cloudflare purge failed: ' . $response->get_error_message());
return false;
}
$result = json_decode(wp_remote_retrieve_body($response), true);
return !empty($result['success']);
}
add_action('publish_post', function (int $post_id): void {
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
return;
}
cf_purge_urls([get_permalink($post_id), home_url('/')]);
});
publish_post 会在文章发布时,以及已发布的文章被更新时触发。API 的 purge_cache 除了用于指定 URL 的 files 之外,还有清除全部内容的 purge_everything,但清除全部会让静态文件也全部重新获取,所以不要在每次发布文章时使用。
切换之后要确认的事项
curl -sI的结果中有server: cloudflare和cf-ray,并且浏览器中显示了锁形图标- 可以登录后台,能保存文章、上传媒体
- 新的评论和访问日志中记录的是访客的 IP,而不是 Cloudflare 的 IP
- 联系表单的邮件能够收到(
MX记录没有被代理) - 如果创建了 WAF 自定义规则,请用未被允许的线路(如手机的移动网络)打开
wp-login.php,确认出现拦截或质询
常见问题
出现 ERR_TOO_MANY_REDIRECTS
请确认 SSL/TLS 模式是不是 Flexible。在源站安装证书并改为 Full (strict) 即可解决。
进不去后台了
可能是 WAF 自定义规则的条件中没有包含你自己的 IP 或国家。请在 Cloudflare 控制台中暂时停用该规则,在安全事件中确认被哪条规则拦截之后,再修正表达式。
所有访问看起来都来自同一个 IP
说明步骤 3 的真实 IP 还原没有做好。Nginx 请确认 set_real_ip_from 的网段和 real_ip_header,Apache 请确认 remoteip 是否已启用。
总结
- 名称服务器切换为分配给自己账号的 2 个,
MX等邮件用的记录不要开启代理 - SSL/TLS 用 Full (strict)。Flexible 会导致重定向循环和混合内容
- 真实 IP 只在连接来源位于 Cloudflare 网段时,才信任
CF-Connecting-IP来还原 - 登录页用 WAF 自定义规则按 IP 或国家限制,一开始先用 Managed Challenge 观察情况
- HTML 默认不会被缓存。发布时的清除,用只有“Cache Purge”权限的 API 令牌来完成
相关文章
参考:Restoring original visitor IPs(Cloudflare)、Encryption modes(Cloudflare)、Custom rules(Cloudflare WAF)、Default cache behavior(Cloudflare)
关于 WordPress 有疑问?本站运营方位于日本,仅以日语回复。 联系我们(日语)