使用 Caddy 和 CF 时获取访客真实 IP

获取 Cloudflare CDN 背后访问用户的真实 IP。

背景

在 Cloudflare 的官方网站上,提供了使用各种 Web 服务器时恢复原始访问 IP 的方法,但恰好缺少了 Caddy,而我本人在个人服务器上又常用 Caddy 作为 Web 服务器。

通常,X-Forwarded-For 标头用于记录代理服务器和访问者的原始 IP,CF 会将代理 IP 添加到 X-Forwarded-For 标头中,在文档中详细描述了这一过程。但是 X-Forwarded-For 采用的是附加策略,如果在到达 CF 之前,访问者已经存在且伪造了 X-Forwarded-For 记录,就会导致获取到不受信任的代理地址。因此,Cloudflare 建议我们使用 CF-Connecting-IP 或 True-Client-IP 这两个标头,作为原始访问者的 IP,详见文档

另外,也可以在 CF 中进行配置,移除到达 CF 前所存在的 X-Forwarded-For Header(或仅保留可信代理 IP),这部分的配置方法可以参考 Authelia - Forwarded Headers

Caddy 配置

在 Caddy 中,如果后端服务或程序支持设置从 Cf-Connecting-Ip 获取真实 IP,那么就只需要在 Caddyfile 的 reverse_proxy 中 添加该标头:

1
header_up CF-Connecting-IP {http.request.header.CF-Connecting-IP}

更加通用的做法,是类似于 nginx 的 real_ip 模块,为 Caddy 配置可信代理,将 Cloudflare 的 IP 添加到其中。CF 的 IP 列表可以在其网站的 IP-Ranges 页面中获取,IPV4 和 IPV6 的地址列表分别是:https://www.cloudflare.com/ips-v4 和 https://www.cloudflare.com/ips-v6

在 Caddy 的 reverse_proxy 文档 中提到,配置可信代理的方式是 trusted_proxies [private_ranges] <ranges...>,且X-Forwarded-For已经由 Caddy 默认添加,那么,Caddyfile 最终可以写作:

1
2
3
4
5
6
example.com {
    reverse_proxy http://127.0.0.1:8080 {
        trusted_proxies 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
        header_up CF-Connecting-IP {http.request.header.CF-Connecting-IP}
    }
}

也可以根据 Caddy 官方文档的建议,将 trusted_proxies 配置到 Global 选项中。

或者,根据 一行代码快速配置 Caddy 站点日志——复用 Caddy 配置段 中的方法,将其封装为配置段:

1
2
3
4
5
6
(reverse_proxy_cf) {
    reverse_proxy {args.0} {
        trusted_proxies 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
        header_up CF-Connecting-IP {http.request.header.CF-Connecting-IP}
    }
}

在配置反代时,使用如下方式引用。

1
import reverse_proxy_cf http://localhost:8080
0%