侧边栏壁纸
  • 累计撰写 9 篇文章
  • 累计创建 3 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

记一次 Cloudflare + frp + OpenResty 网站无法访问的完整排查过程

Administrator
2026-04-23 / 0 评论 / 0 点赞 / 2 阅读 / 0 字

记一次 Cloudflare + frp + OpenResty 网站无法访问的完整排查过程

本文记录了一次从 "Cloudflare 525 错误" 到最终定位根因并修复的完整排查过程,涉及 Cloudflare、frp 内网穿透、OpenResty(Docker 部署)的联动问题,希望对有类似架构的同学有所帮助。


一、架构背景

在介绍问题之前,先说明一下整体架构:

用户浏览器
    ↓ HTTPS
Cloudflare CDN(域名托管于 CF,开启代理)
    ↓ HTTPS (Full 模式)
公网云服务器(运行 frps)
    ↓ frp TCP 隧道
本地内网服务器(运行 frpc + OpenResty Docker 容器)
    ↓ 反向代理
本地应用服务(某端口)
  • 本地服务器:家用/自建物理服务器,无公网 IP,通过 frp 内网穿透暴露服务
  • 公网服务器:云服务器,运行 frps,作为中转节点
  • OpenResty:以 Docker 容器方式运行在本地服务器,监听 80/443 端口
  • frpc:以 Docker 容器方式运行在本地服务器,host 网络模式,将本地 80/443 穿透到公网服务器对应端口
  • Cloudflare:SSL 模式为 Full,域名解析到公网服务器 IP

二、问题现象

访问网站时,浏览器显示 Cloudflare 错误页面,提示:

Your Browser  Working
Cloudflare    Working  
Host          Error

初步判断是源站(本地服务器)出现了问题。


三、排查过程

第一步:确认基础组件状态

首先在本地服务器上确认端口监听情况:

ss -tlnp | grep -E ':80|:443'

输出显示 OpenResty 正在监听 80 和 443 端口,进程存在,看起来服务是正常的。

ps aux | grep -E 'nginx|openresty'

进程也在,无明显异常。

第二步:查看 frpc 日志

查看 frpc 容器日志,发现大量报错:

[web-reverse-proxy2] connect to local service [x.x.x.x:443] error: 
  dial tcp x.x.x.x:443: connect: connection refused
[web-reverse-proxy1] connect to local service [x.x.x.x:80] error:  
  dial tcp x.x.x.x:80: connect: connection refused

connection refused 说明:frp 隧道本身是通的,但 frpc 去连接本地的 80/443 时被拒绝了。

第三步:查看 OpenResty 日志

查看 OpenResty 容器日志,发现有请求进来,但全部返回 403,且响应体大小达到 16KB+(说明这是 WAF/默认 server 的拦截页,而非正常业务响应)。这说明在某段时间内,OpenResty 的 lyc1466.cn 站点配置没有生效,请求落到了默认 server。

后来发现这是因为 OpenResty 曾经短暂宕机,之后被重新拉起后,1Panel 触发了两次配置 reload(SIGHUP),配置重新生效。

第四步:模拟本地访问验证

在本地服务器上,分别用回环地址和内网 IP 测试:

# 用回环地址测试
curl -Ik https://127.0.0.1 -H "Host: yourdomain.com"
# 结果:HTTP/1.1 200 OK ✅

# 用内网 IP 测试
curl -Ik https://192.168.x.x -H "Host: yourdomain.com"
# 结果:curl: (7) Failed connect to 192.168.x.x:443; 拒绝连接 ❌

关键差异浮现:OpenResty 响应 127.0.0.1,但不响应内网 IP!

而 frpc 配置中,localIP 写的是内网 IP,导致 frpc 一直连接失败:

# frpc 配置(问题所在)
[[proxies]]
name = "web-reverse-proxy2"
type = "tcp"
localIP = "192.168.x.x"   # ← 用的是内网 IP
localPort = 443
remotePort = 443

第五步:公网服务器侧验证

在公网服务器上用 openssl s_client 直接测试 SSL 握手:

openssl s_client -connect <公网IP>:443 -servername yourdomain.com 2>&1 | head -20

输出结果:

CONNECTED(00000003)
SSL handshake has read 0 bytes and written 308 bytes  ← 致命
no peer certificate available
Cipher is (NONE)
  • TCP 连接建立成功(CONNECTED
  • 客户端发出了 ClientHello(written 308 bytes)
  • 服务端完全没有回应(read 0 bytes)
  • 无证书返回

这与 frpc 无法连接本地 443 的问题完全对应:frps 把流量转发给 frpc,frpc 连不上 OpenResty,frps 只能关闭连接,Cloudflare 收到握手失败,报告 525 错误。


四、根本原因

OpenResty Docker 容器(host 网络模式)在某次 reload 后,实际只响应 127.0.0.1 的连接,不响应内网 IP 的连接。

在 Linux 网络中,127.0.0.1 和内网 IP(如 192.168.x.x)虽然是同一台机器,但走的是不同的网络接口:

访问地址网络接口是否受 firewalld 限制
127.0.0.1lo(回环)❌ 不经过,完全绕过
192.168.x.xeth0✅ 经过 firewalld/iptables 完整规则链

frpc 用内网 IP 去连接 OpenResty,但 OpenResty 在该接口上的连接被拒绝,导致整条链路断裂。


五、修复方案

修改 frpc 配置,将所有本机服务localIP 从内网 IP 改为 127.0.0.1

# 修复前
[[proxies]]
name = "web-reverse-proxy1"
type = "tcp"
localIP = "192.168.x.x"   # ❌
localPort = 80
remotePort = 80

[[proxies]]
name = "web-reverse-proxy2"
type = "tcp"
localIP = "192.168.x.x"   # ❌
localPort = 443
remotePort = 443

# 修复后
[[proxies]]
name = "web-reverse-proxy1"
type = "tcp"
localIP = "127.0.0.1"     # ✅
localPort = 80
remotePort = 80

[[proxies]]
name = "web-reverse-proxy2"
type = "tcp"
localIP = "127.0.0.1"     # ✅
localPort = 443
remotePort = 443

重启 frpc:

docker restart frpc

验证修复:

curl -I https://yourdomain.com
# HTTP/2 200 ✅

六、完整的错误链路 vs 修复后链路

修复前(故障链路)

Cloudflare
  ↓ HTTPS
frps:443(公网服务器)
  ↓ 转发
frpc → 连接 192.168.x.x:443 → ❌ connection refused
  ↓
frps 无数据返回
  ↓
Cloudflare 收到握手失败 → 报 525 Error

修复后(正常链路)

Cloudflare
  ↓ HTTPS
frps:443(公网服务器)
  ↓ 转发
frpc → 连接 127.0.0.1:443 → ✅ 连接成功
  ↓
OpenResty(Docker, host 网络)
  ↓ 反向代理
本地应用服务
  ↓
HTTP 200 原路返回

七、经验总结

1. frpc 中本机服务应优先使用 127.0.0.1

# ✅ 推荐:本机服务用回环地址,绕过防火墙,更稳定
localIP = "127.0.0.1"

# ⚠️ 仅在目标是其他局域网设备时才用局域网 IP
localIP = "192.168.x.x"   # 目标是局域网内其他机器

2. Cloudflare 525 排查思路

遇到 525 错误,按以下顺序排查:

1. 先检查源站 443 端口是否在监听
   ss -tlnp | grep :443

2. 用 openssl 测试 SSL 握手
   openssl s_client -connect <源站IP>:443 -servername <域名>

3. 检查证书有效期
   openssl x509 -in /path/to/fullchain.pem -noout -enddate

4. 检查 Cloudflare SSL 模式(不能是 Flexible)

5. 分别用 127.0.0.1 和内网 IP 测试,排查防火墙问题

3. 遇到 connection refusedconnection timeout 的区别

错误类型含义排查方向
connection refused端口有监听但主动拒绝,或根本无进程监听检查服务是否运行、防火墙规则
connection timeout包被丢弃,无响应检查防火墙 DROP 规则、安全组
no route to host路由不可达检查网络配置、路由表

4. Docker host 网络模式下的注意事项

Docker 容器使用 host 网络模式时,容器与宿主机共享网络栈,但以下情况需要注意:

  • 容器内的服务如果只绑定了 127.0.0.1,从其他网卡(如 eth0)发来的请求无法访问
  • 其他容器(bridge 模式)访问宿主机服务时,需要用 Docker 网关 IP(通常是 172.17.0.1),而不是 127.0.0.1

八、附:frp 内网穿透最佳实践配置参考

# frpc.toml 配置建议

# 本机服务 → 用 127.0.0.1
[[proxies]]
name = "local-web-http"
type = "tcp"
localIP = "127.0.0.1"
localPort = 80
remotePort = 80

[[proxies]]
name = "local-web-https"
type = "tcp"
localIP = "127.0.0.1"
localPort = 443
remotePort = 443

# 其他局域网设备 → 用对应设备的局域网 IP
[[proxies]]
name = "nas-http"
type = "tcp"
localIP = "192.168.x.x"   # NAS 的局域网 IP
localPort = 80
remotePort = 48080

写在最后: 这次问题的本质是对 Linux 网络接口的理解不够深入——127.0.0.1192.168.x.x 虽然都是本机,但走的网络路径完全不同,防火墙的处理结果也不同。在 Docker + frp + 防火墙的组合场景下,这类细节很容易被忽略,希望本文能帮助遇到类似问题的同学少走弯路。

博主关闭了所有页面的评论