网页应用

获取访客真实IP

在 NGINX 与 Apache 中获取访客真实 IP
承载 HTTPS 的站点只能用 PROXY protocol:TLS 由 frps 直接透传、不做解析,X-Forwarded-For 不会被追加。

NGINX

Nginx 用 realip 模块把访客 IP 覆盖到 $remote_addr,两种方案的区别只在于 real_ip_header。

HTTP 隧道可读取 X-Forwarded-For,面板不需要任何配置,frpc 会自动把访客 IP 追加到该请求头末尾:

server {
    listen 80;

    # frpc 在本地运行写 127.0.0.0/8,不同机时写 frpc 的内网地址或CIDR段
    set_real_ip_from 127.0.0.0/8;
    real_ip_header X-Forwarded-For;

    # 原有内容不变,此时 $remote_addr 已是访客 IP
}
X-Forwarded-For 的前半部分完全由访客控制。realip 会从右往左取第一个不在 set_real_ip_from 里的地址,所以必须把 set_real_ip_from 限定为 frpc 的地址,否则访客可以直接伪造来源 IP。

HTTPS、TCP、UDP 隧道开启 PROXY protocol:

server {
    listen 80 proxy_protocol;

    set_real_ip_from 127.0.0.0/8;
    real_ip_header proxy_protocol;

    # 原有内容不变
}
listen 上开启 proxy_protocol 后,该端口(包括其它配置文件里的同一端口)的所有连接都会按 PROXY protocol 解析,浏览器无法直接访问该端口。

Apache

要求 Apache >= 2.4.30 并启用 mod_remoteip(Debian/Ubuntu 可执行 a2enmod remoteip)。

HTTP 隧道读取 X-Forwarded-For:

<VirtualHost *:80>
    ServerName example.com

    RemoteIPHeader X-Forwarded-For
    RemoteIPInternalProxy 127.0.0.0/8
</VirtualHost>

HTTPS、TCP、UDP 隧道开启 PROXY protocol:

<VirtualHost *:80>
    ServerName example.com

    RemoteIPProxyProtocol On
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile      /path/to/fullchain.pem
    SSLCertificateKeyFile   /path/to/privkey.pem

    RemoteIPProxyProtocol On
</VirtualHost>
RemoteIPProxyProtocol 按 VirtualHost 生效,80 和 443 要各写一遍,漏写的那个端口仍会把访客地址记成 127.0.0.1。

配置完成后 %a 即为访客 IP。

用 X-Forwarded-For 拿到的还是 127.0.0.1

  1. 确认隧道类型是 HTTP,X-Forwarded-For 对 TCP、UDP、HTTPS隧道无效
  2. 确认 set_real_ip_from(Nginx)或 RemoteIPInternalProxy(Apache)写的是 frpc 的地址
  3. 确认读的是 $remote_addr / %a,而不是自己另外拼的变量