← 返回首页

Cloudflare Tunnel零端口方案,WordPress安全,踩坑复盘

CloudflareTunnelWordPress安全零信任网站安全

---

背景:为什么公网开放22端口的WordPress是个定时炸弹

很多站长把WordPress直接暴漏在公网:80/443开放、后台路径/wp-admin/谁都看得见。这不是"裸奔"两个字能形容的——是"裸奔且在脸上写着快来打我"。

Cloudflare Tunnel(也叫cloudflared)的核心思路很简单:你的服务器主动连Cloudflare边缘,而不是让外面的流量主动连你。这样 22/3306/wp-admin 这些端口在公网上完全不可见,黑客想打也打不到。

但这个方案配置链条很长,涉及 cloudflared 安装、WordPress IP 检测、Zero Trust Access 策略、SSL 证书、WAF 规则 5 个环节,每个环节都有真实踩坑。我在这篇文章里全部复盘一遍。

---

架构图:Cloudflare Tunnel怎么做零端口暴露

互联网用户 → Cloudflare全球边缘(443端口)→ cloudflared隧道 → 你的VPS(仅本地端口)

关键点:你的 VPS 的 80/443 端口只允许本地的 cloudflared 连接,公网完全无法直接访问你的 WordPress

---

踩坑一:cloudflared 安装后重启失效

问题现象

按官方文档装了 cloudflared,创建了 tunnel,配好了路由,一切正常。然后 VPS 重启了——systemctl status cloudflared 显示 failed,隧道断了。

排查过程

# 检查服务状态
systemctl status cloudflared

# 查看日志
journalctl -u cloudflared -n 50

日志里经常看到:

error="failed to create quic connection: tls: first flight did not contain a TLS certificate"

根因

cloudflared 默认会自动更新,更新后二进制文件的 hash 变了,但 systemd service 用的还是旧的启动参数,导致 binary 不兼容。

解决方案

固定版本安装(不用最新滚动版):

# 方法1:下载指定版本(推荐 2024年稳定版)
wget https://github.com/cloudflare/cloudflared/releases/download/2024.8.0/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64
sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared

# 方法2:禁用自动更新
# 在 /etc/cloudflared/config.yml 中加:
autoupdate: false

# 方法3:用 docker 运行(重启不丢配置)
docker run -d \
  --name cloudflared \
  --restart unless-stopped \
  -v /etc/cloudflared:/etc/cloudflared \
  cloudflare/cloudflared:2024.8.0 \
  tunnel run --token ${TUNNEL_TOKEN}

---

踩坑二:WordPress 评论 IP 全部显示为 127.0.0.1

问题现象

评论者的 IP 地址在 WordPress 后台全部显示为 127.0.0.1Cloudflare 边缘节点 IP(如 172.71.134.x),Akismet、Wordfence 的 IP 判断全部失效。

排查过程

登录 WordPress 后台 → 评论列表 → IP 列,全是 127.0.0.1。查看单个评论详情,IP 仍然是 127.0.0.1。

检查 nginx 日志:

tail -f /var/log/nginx/access.log | grep wp-comments-post.php

所有请求的 remote_addr 都是 127.0.0.1(因为请求是 cloudflared 本地转发过来的)。

根因

cloudflared 以**反向代理**身份连接你的 origin(VPS 上的 nginx):它替你服务器连 Cloudflare 边缘,但转发给 nginx 时,remote_addr 自然就是 cloudflared 自己(127.0.0.1)。WordPress 默认读取 REMOTE_ADDR,所以拿到的是本地地址。

解决方案

方法 1:nginx 在 location 里设置 X-Real-IP(推荐)

# /etc/nginx/conf.d/cloudflare-real-ip.conf
# 必须放在 wp-admin 和 wp-login.php 的 location 之前

set_real_ip_from 172.71.128.0/20;
set_real_ip_from 172.70.80.0/20;
set_real_ip_from 172.69.0.0/20;
set_real_ip_from 172.64.0.0/20;
set_real_ip_from 172.68.0.0/20;
set_real_ip_from 172.67.0.0/20;
real_ip_header X-Forwarded-For;
real_ip_header CF-Connecting-IP;  # Cloudflare 专用头
real_ip_recursive on;

方法 2:WordPress 强制信任 Cloudflare(在 wp-config.php 顶部加)

// 在 wp-config.php 最顶部加(必须加在最前面)
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
}

方法 3:用 Nginx Real IP 模块(生产环境推荐)

nginx 需要编译时带了 with-http_realip_module(大多数发行版默认带):

# 验证模块存在
nginx -V 2>&1 | grep -o http_realip_module

# 然后在 /etc/nginx/sites-available/your-site.conf 的 server 块里加:
real_ip_header CF-Connecting-IP;
set_real_ip_from 0.0.0.0/0;  # Cloudflare 所有 IP 都信任

加完之后,WordPress 评论 IP 恢复正常,Akismet 和 Wordfence 的 IP 判断也正常了。

---

踩坑三:SSL 模式不匹配导致 526 错误

问题现象

访问网站时 CloudflareError 526: Invalid SSL certificate,网站完全打不开。

排查过程

Cloudflare Dashboard → TLS → Overview 里查看 SSL 模式设置:

根因

常见踩坑有两个:

踩坑 A:Origin 用的是自签名证书,但 SSL 模式选了 Full (Strict)

# 很多人为了省事直接用自签名:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/ssl/private/nginx-selfsigned.key \
  -out /etc/ssl/certs/nginx-selfsigned.crt

然后 Cloudflare SSL 模式选了 Full (Strict) → 526。

踩坑 B:SSL 模式选 Flexible,但 cloudflared tunnel 里配置了 HTTPS 端点

Flexible 模式下 Cloudflare 到 origin 走 HTTP,不是 HTTPS。如果你 nginx 只配了 HTTPS(强制跳转),就会导致重定向循环。

解决方案

方案 A:使用 Cloudflare Origin Certificate(免费且自动续期)

# 在 Cloudflare Dashboard → TLS → Origin Server 点"创建证书"
# 下载 origin certificate(.pem)和 private key(.key)

# 把证书放到 VPS
sudo cp origin.pem /etc/ssl/certs/cloudflare-origin.pem
sudo cp private.key /etc/ssl/private/cloudflare-origin.key

# nginx 配置使用这个证书
ssl_certificate /etc/ssl/certs/cloudflare-origin.pem;
ssl_certificate_key /etc/ssl/private/cloudflare-origin.key;

# Cloudflare SSL 模式设为 Full(不是 Full Strict)

Cloudflare Origin Certificate 由 Cloudflare 自己签发,只在 Cloudflare 边缘节点连接你 origin 时有效,完全免费且自动续期。

方案 B:如果必须用自签名证书

Cloudflare SSL 模式选 Full(不是 Full Strict),然后:

# nginx 配置里加(跳过自签名证书验证,仅适用于 tunnel 场景)
proxy_ssl_verify off;  # 如果用 nginx 做反向代理

---

踩坑四:Zero Trust Access 策略覆盖了整个域名

问题现象

设置了 Zero Trust Access 保护 WordPress,结果整个网站所有页面都要登录,任何访客都看到 Cloudflare Access 的登录页。

排查过程

Cloudflare Zero Trust → Access → Applications 里查看 Application 配置:

# 错误的配置示例:Policy 覆盖了根路径 /
SessionDuration: 24h
PolicyName: "Block all"
Match: example.com/*

这导致所有路径(静态资源、文章页面)都触发了 Access 验证。

根因

Access 策略默认按域名匹配,如果你创建 Application 时用 example.com/*,**整个域名下所有路径都需要身份验证**,包括图片/CSS/JS 等静态文件,以及已登录用户访问文章页面的正常行为。

解决方案

只保护 wp-admin 和 wp-login.php 这两个入口点

# 正确的 Access Application 配置
ApplicationName: "WordPress Admin Protection"
SessionDuration: 8h
Policy:
  - Name: "WordPress Admin Access"
    Include:
      - emails: ["your-email@example.com"]  # 或用 IdP 集成
    Action: "allow"
    ForbidOtherIdentityProviders: false

# 在 "Policy" 下方设置 "App domain" 和 "Path"
AppDomain: "example.com"
Path: "/wp-admin/*"

# 再单独创建一个 Application 保护 wp-login.php
AppDomain: "example.com"
Path: "/wp-login.php*"

同时,在 nginx 配置里对这两个路径做特殊处理(仅允许 Cloudflare IP 访问):

location ~ ^/(wp-admin|wp-login\.php) {
    # 只允许 Cloudflare IP 访问
    allow 172.71.0.0/20;
    allow 172.70.0.0/20;
    allow 172.69.0.0/20;
    allow 172.68.0.0/20;
    allow 172.67.0.0/20;
    allow 172.64.0.0/20;
    deny all;

    # 正常代理
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

这样公开文章页面完全不受影响,只有管理员访问 /wp-admin/ 时才需要通过 Cloudflare Access 认证。

---

踩坑五:WAF 规则把 Cloudflare 隧道流量当攻击拦截

问题现象

安装了 ModSecurity + OWASP CRS 后,WordPress 后台完全打不开(504/403 错误),但关掉 WAF 就正常。Cloudflare 的 ModSecurity 日志里大量 Rule 920350(Protocol compliance check)误报。

排查过程

查看 ModSecurity 审计日志:

tail -f /var/log/modsec_audit.log | grep "920350"

发现触发的是这条规则:

[file "/etc/modsecurity.d/owasp-crs/rules/RESPONSE-951-DATA-LEAKAGES.conf"]
[id "951200"] [msg "Cross-site Scripting (XSS) Attack"]

Cloudflare 隧道过来的 HTTP 请求头里包含了一些 WAF 认为可疑的字符(如 URL 里的 Base64 编码参数),被误判为 XSS 攻击。

根因

OWASP CRS 的误报问题在隧道场景下特别明显,因为:

1. Cloudflare 边缘在转发请求时可能会修改/添加一些 header(如 CF-RAYCF-Cache-Status

2. 隧道流量的 TLS 握手信息与普通直连流量不同

3. 某些 ModSecurity 规则对 URL 编码字符过于敏感

解决方案

方法 1:在 ModSecurity 配置里白名单 Cloudflare IP(推荐)

# /etc/modsecurity.d/modsecurity.conf 或在 crs-setup.conf 里加

# 白名单 Cloudflare 所有 IP 段(最新 IP 范围见 https://www.cloudflare.com/ips/)
SecRule REMOTE_ADDR "@ipMatch 172.71.0.0/20" \
    "id:90001,phase:1,pass,nolog,ctl:ruleRemoveById=920350-921100"

SecRule REMOTE_ADDR "@ipMatch 172.70.0.0/20" \
    "id:90002,phase:1,pass,nolog,ctl:ruleRemoveById=920350-921100"

SecRule REMOTE_ADDR "@ipMatch 172.69.0.0/20" \
    "id:90003,phase:1,pass,nolog,ctl:ruleRemoveById=920350-921100"

方法 2:降低 Paranoia Level(如果不想逐条白名单)

# 在 /etc/modsecurity.d/crs/crs-setup.conf 里改:
SecAction \
    "id:900004,\
    phase:1,\
    pass,\
    t:none,\
    setvar:tx.paranoia_level=1"

PL1(低偏执级别)比 PL3 少了很多高误报规则,适合内部服务或 IP 已知的场景。

方法 3:用 Cloudflare 自己的 WAF 替代 ModSecurity(最省事)

Cloudflare 本身就有 WAF 功能(免费版就够用),不需要在 VPS 上再装一层。如果用了 Cloudflare Tunnel,可以把 ModSecurity 完全关掉:

# 关掉 ModSecurity
sudo systemctl stop modsecurity
sudo systemctl disable modsecurity

# 在 Cloudflare Dashboard → Security → WAF → Managed rules
# 开启 "Cloudflare Managed Ruleset"
# 对 WordPress 路径添加自定义规则:
# IF (URI contains "wp-admin") THEN → 启动 "Cloudflare WordPress ruleset"

---

验证方案:配置完成后怎么测试

1. 检查端口是否真的不可达

# 从外部 VPS 测试(用手机热点或其他网络)
nc -zv yourdomain.com 22
nc -zv yourdomain.com 3306

# 应该显示 "Connection refused" 或超时
# 如果显示 "Open",说明端口仍然暴露

2. 测试 WordPress IP 检测是否正常

# 在 WordPress 目录下创建一个测试脚本
cat > /var/www/html/test-ip.php << 'EOF'

3. 验证 Zero Trust Access 策略

# 用隐私模式访问 wp-admin,应该被重定向到 Cloudflare Access 登录页
curl -I https://yourdomain.com/wp-admin/

# 应该看到 302 重定向到 Cloudflare Access 页面

---

相关配置快速命令清单

# 1. 安装 cloudflared
wget https://github.com/cloudflare/cloudflared/releases/download/2024.8.0/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64 && sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared

# 2. 创建 tunnel
cloudflared tunnel create wordpress-tunnel
cloudflared tunnel route dns wordpress-tunnel yourdomain.com

# 3. 配置 nginx real IP(加在 /etc/nginx/conf.d/cloudflare-real-ip.conf)
# 见踩坑二详细配置

# 4. WordPress wp-config.php 顶部加 IP 修复
# 见踩坑二详细代码

# 5. Cloudflare Origin Certificate(免费)
# 在 Cloudflare Dashboard → TLS → Origin Server 创建

# 6. Zero Trust Access 只保护 wp-admin 和 wp-login.php
# 见踩坑四详细配置

---

总结

Cloudflare Tunnel 是 WordPress 零端口暴露的最佳方案,但配置链条长,每个环节都有真实踩坑:

1. cloudflared 自动更新导致重启失效 → 固定版本或用 Docker

2. WordPress IP 判断失效(评论全是127) → nginx real_ip 模块 + wp-config.php 修复

3. SSL 526错误 → 用 Cloudflare Origin Certificate,SSL 模式选 Full

4. Zero Trust Access 覆盖整个域名 → 只保护 wp-admin 和 wp-login.php 两个入口

5. ModSecurity WAF 误拦隧道流量 → 白名单 Cloudflare IP 或直接用 Cloudflare WAF

---

👉 立即参与:https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link

---

关联阅读

📌 本文由 AI 辅助生成并经人工审核发布 | TechPassive — AI 驱动的内容测试站点,专注于效率工具与 SaaS 真实评测

🔗 精选推荐工具

使用以下链接支持我们持续产出高质量内容(点击可直接前往购买):

☁️ DigitalOcean 云服务器 ⚡ Vultr 高性能 VPS 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books ⭐ MiniMax Token Plan 🔍 云盘搜索
← 返回首页