在搭建个人网站、媒体服务或其他 Web 服务时,有时需要通过自己的服务器反向代理一个已经启用 Cloudflare 代理的 HTTPS 域名。

本文记录如何使用 Nginx、Caddy 和 Nginx Proxy Manager(NPM)实现这一需求,并重点说明 HTTPS 上游连接中的 Host 请求头、TLS SNI 以及常见故障的处理方法。

一、适用场景与工作原理

本文所说的「套了 CF」,是指目标域名已接入 Cloudflare,并启用了代理功能(DNS 记录显示为橙色云朵)。

假设有以下两个域名:

项目示例域名作用
代理入口proxy.example.net用户访问的域名
上游地址origin.example.com实际被反向代理的 HTTPS 域名

以上域名均为示例,请替换为自己的实际地址。

访问流程如下:

客户端
  │
  ▼
proxy.example.net
  │
  ▼
自己的反向代理服务器
  │
  │ HTTPS 请求
  ▼
origin.example.com
  │
  ▼
Cloudflare 网络
  │
  ▼
目标网站源站

反向代理服务器负责接收客户端请求,再将请求转发给上游域名,并将上游响应返回给客户端。

这里需要注意几个概念:

  • 反向代理入口域名:客户端访问的域名。
  • 上游域名:反向代理服务器实际连接的目标域名。
  • Host 请求头:HTTP 层用于标识目标主机的请求头。
  • TLS SNI:TLS 握手时客户端发送的服务器名称,用于上游选择对应的证书和站点。

当上游使用 HTTPS 时,TLS SNI 和 HTTP Host 都可能影响连接是否成功。如果二者与上游站点的配置不匹配,就可能出现证书错误、访问到错误站点或 HTTP 403 等问题。

二、Nginx 配置

1. 基础反向代理配置

假设上游域名为 origin.example.com,可以在对应的 server 配置块中加入以下内容:

location / {
    # 将请求转发至上游 HTTPS 域名
    proxy_pass https://origin.example.com;

    # 使用上游域名作为 HTTP Host
    proxy_set_header Host origin.example.com;

    # 传递客户端地址及原始访问信息
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 启用上游 TLS SNI
    proxy_ssl_server_name on;
    proxy_ssl_name origin.example.com;
}

配置说明:

  • proxy_pass:指定上游 HTTPS 地址。
  • proxy_set_header Host:将上游需要的主机名传递给目标站点。
  • proxy_ssl_server_name on:启用上游 TLS SNI。
  • proxy_ssl_name:明确指定 TLS 握手时使用的服务器名称。

如果上游使用标准 HTTPS 端口 443,可以省略端口号;如果上游使用其他端口,则应在 proxy_pass 中明确指定。

2. 检查并重载 Nginx

修改配置后,先检查语法:

nginx -t

确认检查通过后再重载:

systemctl reload nginx

如果配置文件存在语法错误,不要直接重启服务,应先修复问题。

3. 关于客户端真实 IP

上面的配置通过 X-Real-IP 和 X-Forwarded-For 传递客户端地址信息,但它们并不意味着上游一定能够获得客户端的真实公网 IP。

如果请求经过了其他 CDN 或代理层,$remote_addr 可能是前一层代理服务器的地址。只有在正确配置可信代理及真实 IP 解析规则后,才能可靠地获取客户端地址。

此外,X-Forwarded-For 可能包含多级代理的地址。上游应用应根据实际代理链和可信代理配置解析,而不应无条件信任客户端自行提交的请求头。

三、Caddy 配置

Caddy 的配置相对简洁。对于 HTTPS 上游,可以在 Caddyfile 中写入:

proxy.example.net {
    reverse_proxy https://origin.example.com {
        header_up Host {upstream_hostport}
    }
}

其中:

  • proxy.example.net 是客户端访问的入口域名。
  • https://origin.example.com 是上游 HTTPS 地址。
  • header_up Host {upstream_hostport} 将上游主机地址设置为 HTTP Host。

对于 Caddy v2.11.0 及更新版本,HTTPS 上游的 Host 处理已经有相应的默认行为,通常不必再手动覆盖。保留上述写法可以明确表达配置意图,但如果希望保留原始请求的 Host,则需要根据目标站点的要求另行配置。

保存配置后,可以检查并重新加载 Caddy:

caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy

请根据实际安装方式确认 Caddyfile 的路径。如果使用 Docker 部署,应在对应容器和挂载配置中执行检查及重载操作。

官方文档:Caddy reverse_proxy

四、Nginx Proxy Manager(NPM)配置

如果使用 Nginx Proxy Manager,通常可以先通过网页管理界面创建 Proxy Host,再在 Advanced 中添加必要的上游 HTTPS 配置。

1. 创建 Proxy Host

进入 NPM 管理界面,添加对应的 Proxy Host:

  • Domain Names:填写代理入口域名,例如 proxy.example.net。
  • Scheme:选择 https。
  • Forward Hostname / IP:填写 origin.example.com。
  • Forward Port:填写 443。
  • 根据需要配置 SSL 证书、强制 HTTPS 等选项。

请确保 NPM 所在服务器可以解析并访问上游域名。

2. 配置 Advanced

如果上游要求明确的 TLS SNI,可以在 Advanced 中添加:

proxy_ssl_server_name on;
proxy_ssl_name origin.example.com;

如果上游还要求 HTTP Host 与上游域名一致,可以根据当前 NPM 版本生成的 Nginx 配置,确认 Host 请求头的实际取值。必要时设置:

proxy_set_header Host origin.example.com;

注意: NPM 会自动生成 location、proxy_pass 和请求头等配置。Advanced 内容会被插入生成的配置中,因此不要直接照搬一个完整的 location / { ... } 块,以免与 NPM 自动生成的 location 重复或发生嵌套错误。

不同版本的 NPM 生成配置可能有所不同。若修改后仍然出现 502 或访问到错误站点,可以检查最终生成的 Nginx 配置,确认 proxy_pass、Host 和 TLS SNI 的实际值。

官方文档:Nginx Proxy Manager Advanced Configuration

五、常见问题排查

1. 出现 502 Bad Gateway

可能原因:

  • 上游域名无法解析。
  • 上游 HTTPS 端口无法访问。
  • 代理服务器无法连接 Cloudflare 网络。
  • 上游 TLS 握手失败。
  • Nginx 或 Caddy 配置错误。

可以在反向代理服务器上测试上游连接:

curl -I https://origin.example.com

如果需要指定连接地址但保留正确的域名与 TLS SNI,可以使用:

curl -Iv \
  --resolve origin.example.com:443:上游IP地址 \
  https://origin.example.com/

将 上游IP地址 替换为实际测试地址。注意,直接指定 IP 只适用于你确实需要测试某个特定连接地址的情况;如果上游域名使用 Cloudflare 代理,通常应优先测试正常的域名解析和连接链路。

2. 出现 403 Forbidden

403 不一定是反向代理配置错误。可能原因包括:

  • 上游站点设置了访问限制。
  • 目标站点要求特定的 Host。
  • Cloudflare 安全规则拦截了请求。
  • 上游站点限制了来源 IP 或访问方式。

建议先确认站点是否允许此类代理访问,再检查请求头和上游响应。不要通过伪造身份、绕过访问控制或规避目标站点的安全限制来解决问题。

3. 出现证书或 TLS 错误

如果上游使用 HTTPS,应确认:

  • 上游域名解析正常。
  • proxy_ssl_server_name 已启用。
  • proxy_ssl_name 与上游证书对应的主机名匹配。
  • 上游证书链有效且未过期。

不要为了消除错误而直接关闭 TLS 证书验证。正确做法是修复域名、SNI 或证书配置,确保上游连接仍然经过有效的 TLS 身份验证。

4. 页面可以打开,但部分资源加载失败

有些网站会在 HTML、CSS、JavaScript 或 API 请求中写入原始域名,也可能使用 WebSocket、重定向、绝对 URL 或 Cookie 域属性。

如果首页能够打开,但登录、图片、视频或其他功能异常,需要进一步检查:

  • 浏览器开发者工具中的请求失败情况。
  • 上游返回的 Location 重定向地址。
  • Cookie 的 Domain、Path 和 Secure 属性。
  • WebSocket 是否需要单独配置。
  • 应用是否要求使用原始域名访问。

这类问题通常不是单纯增加 proxy_pass 或调整 SNI 就能完全解决的,需要根据目标应用的实际行为逐项排查。

六、安全与使用注意事项

  1. 确认拥有代理权限。 使用反向代理前,应确认目标站点允许相应访问方式,并遵守站点条款。
  2. 不要将反向代理当作绕过安全策略的工具。 Cloudflare 的访问控制、源站限制和安全规则仍可能生效。
  3. 保持 TLS 验证。 不要使用关闭证书验证的方式掩盖证书或 SNI 配置错误。
  4. 合理配置真实 IP。 仅信任明确配置的代理来源,不要无条件信任客户端传入的转发头。
  5. 注意上游服务的兼容性。 如果应用依赖原始域名、Cookie、WebSocket 或重定向,需要单独验证。

七、总结

通过 Nginx、Caddy 或 Nginx Proxy Manager,都可以将请求转发到启用了 Cloudflare 代理的 HTTPS 域名。

无论使用哪种工具,核心都是正确配置上游地址、HTTP Host 和 TLS SNI,并确保代理服务器能够正常连接上游。

如果只需要简单的 HTTPS 反向代理,可以优先选择自己熟悉的工具;如果使用 NPM,则建议先通过管理界面完成基础配置,再根据实际生成的 Nginx 配置补充必要参数。


完结,撒花。