实在是受不了cloudflare的慢速,正好阿里云最近出了一个99/年的活动,搞了台服务器,速度啥的都还行,就还是直接从frp穿出去,至少速度啥的还是能保证的。

我的方案是直接是直接将阿里云的80端口和443端口全部转发到我自己的内网服务器上,然后frp再将流量全部转发到内外的nginx上做分发。方案在实施的过程中遇到了一个问题:我没有办法拿到请求者的ip了,会对我们的数据统计产生影响。看了frp是能够支持真实ip转发的,在不同的版本下有不同写法,主要是0.52.0之前的版本有较大差异,0.52.0支持使用toml格式来配置了,本文是基于toml来配置实现的。

环境

软件环境

  • nginx 1.24.0
  • frp 0.52.0
  • 操作系统 ubuntu 22.04

网络环境

公网 -> 阿里云 ----FRP----> 内网网关(nginx) -> 具体应用服务器

nginx需要支持realIp

先通过nginx -V查看当前的nginx是否支持realIp

$ ./nginx -V
nginx version: nginx/1.24.0
built by gcc 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) 
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --prefix=/data/software/nginx --with-http_ssl_module  --with-http_realip_module

如果存在--with-http_realip_module 那么就不需要重新编译,否则就加上这个参数重新编译nginx安装

配置frp支持proxy_protocol

在FRP中需要配置transport.proxyProtocolVersion = "v2",注意:这个是frp0.52.0以后的版本配置。https://gofrp.org/zh-cn/docs/features/common/realip/,这个连接地址有官方说明。

[[proxies]]
name = "443_transfer"
type = "tcp"
localIP = "127.0.0.1"
localPort = 443
remotePort = 443
transport.proxyProtocolVersion = "v2"

配置NGINX支持proxy_protocol

nginx 上的改动有以下几点。 第一是改listen 支持proxy_protocol;

假定原来监听的是443端口,配置如下:

 listen       443 ssl;
 listen       [::]:443 ssl;

调整后应该改为:

 listen       443 ssl  proxy_protocol;
 listen       [::]:443 ssl proxy_protocol;

相比较之下是多了proxy_protocol这个协议标识。

此外还要添加如下参数:

set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
real_ip_recursive on;

注意127.0.0.1是frpc的ip,如果你的frpc安装到了局域网的其他主机,则需要修改为正确的ip。如果此处ip设置不正确,获取到的用户ip将仍为frpc的ip。

配置NGINX获取真实IP

上述配置能让FRP传递真实IP,nginx拿到真实的IP,但是在应用层面还是没有真实IP的,所以需要在nginx的代理配置上再做一些处理。主要是需要添加proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 这两段

location / {
    proxy_ssl_server_name on;
    proxy_ssl_name $host;
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
 }

完整的一个配置

server {
        listen       443 ssl  proxy_protocol;
        listen       [::]:443 ssl proxy_protocol;
        server_name  blog.alvinkwok.cn;
        #charset koi8-r;
        access_log  logs/blog.alvinkwok.cn.log  main;
	#ssl
	ssl_certificate ./cert/blog.alvinkwok.cn.pem;
	ssl_certificate_key  ./cert/blog.alvinkwok.cn.key;
	ssl_session_cache shared:SSL:1m;
	ssl_session_timeout 5m;
    #自定义设置使用的TLS协议的类型以及加密套件(以下为配置示例,请您自行评估是否需要配置)
    #TLS协议版本越高,HTTPS通信的安全性越高,但是相较于低版本TLS协议,高版本TLS协议对浏览器的兼容性较差。
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
#表示优先使用服务端加密套件。默认开启
ssl_prefer_server_ciphers on;

set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; real_ip_recursive on;

location / {
proxy_ssl_server_name on;
proxy_ssl_name $host;
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

}

参考资料

  1. https://www.mmuaa.com/post/e4812c0b2fb1e2c8.html
  2. https://gofrp.org/zh-cn/docs/features/common/realip/
  3. https://www.cnblogs.com/hh2737/p/8951872.html