因历史原因,手上有几个站一直在国外飘着,众所周知,网络颠簸,更别说还跨了个太平洋了,大多数回国线路晚高峰爆炸是经常的事,趁着促销正好入了台搬瓦工的CN2 GIA线路VPS,但是问题是CN2 GIA回国线路是很好,但是配置太低,配置好Nginx+PHP-FPM+MySQL之后再跑WordPress稍微有点流量就很吃力,于是这么久依赖我那几个站都是放在一台配置更高的后端服务器上,这台线路好的CN2 GIA VPS只是用来承担国内过去的前端流量,这就导致了一个问题,后端服务器拿不到真实的用户IP,这么久一来后端服务器拿到的都是前端服务器也就是搬瓦工的CN2 GIA线路的VPS的IP,而不是真实的用户IP,今天花了点时间终于解决了IP不一致的问题。
准备工作
首先,配置LNMP以及前端服务器反向代理前端用户请求到后端服务器是不用说了,这里直接贴一个前端服务器的配置文件:
server
{
listen 80;
server_name cloudbool.com www.cloudbool.com;
location / {
proxy_pass http://cloudbool.com/;
}
access_log /var/log/nginx/cloudbool.log;
error_log /var/log/nginx/cloudbool-error.log;
}
这么几行就能配置一个Nginx反向代理服务器了,简单是很简单,但是这么做用户的访问IP只能在前端也就是配置反向代理的这台Nginx所在服务器才能获取到,后端服务器得到的只是这台前端服务器的IP,比如说这台前端服务器的IP是1.2.3.4,哪后端服务器的用户访问日志全部都是1.2.3.4,对于我们分析访问日志及配置网站就有点不便,我们需要的是在后端也能拿到用户的真实IP。
前端Nginx服务器配置
既然要在后端服务器拿到用户的真实IP,那就需要在前端Nginx服务器请求后端Nginx的时候一并将用户真实IP带上,这就需要用到Nginx的ngx_http_realip_module模块,一般来说,如果用的是Nginx官方源安装的Nginx,默认就是编译了这个模块,如果没有编译这个模块,可能需要手动编译,已经配置好的Nginx可以通过这个命令查看Nginx的编译情况:nginx -t。ngx_http_realip_module模块相关的文档地址:https://nginx.org/en/docs/http/ngx_http_realip_module.html
准备好ngx_http_realip_module模块之后,接着就是配置前端Nginx服务器了。
在前端Nginx服务器的需要代理的网站配置文件中加入或者更改如下代码:
location / {
proxy_set_header Accept-Encoding "";
proxy_pass https://cloudbool.com/archive/;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
也就是加上4、5、6、7行,将相应的真实IP传递到后端服务器。更改完之后,重启前端Nginx即可。
后端Nginx服务器配置
默认情况下,Nginx的日志格式是这样的:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
如果是通过包管理器安装Nginx,默认的Nginx主配置文件是在/etc/nginx/nginx.conf。
我们如果要接收前端Nginx传来的用户真实IP信息就需要更改下,将日志格式开头的$remote_addr更改成$http_x_forwarded_for,并在后面加上下面几行,相关部分配置如下:
log_format main '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
set_real_ip_from 1.2.3.4;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
上面的1.2.3.4需要替换成真实的前端Nginx服务器地址。除了单独的IPv4地址外,Nginx还支持CIDR格式及IPv6的地址格式。
配置完之后,需要重启Nginx,重启之后应该就能获取到真实的用户IP信息了,如图:
实际中使用发现,ngx_http_realip_module模块可能和Nginx自带的allow/deny有冲突,如果后端服务器默认开启了allow/deny指令再使用ngx_http_realip_module模块,会导致前端访问返回403的问题,暂时没有找到合适的方法,搜索了一波发现有人遇到了这个问题但是几年了也没有人解决。
附带一个前端Nginx的完整配置文件:
server{
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cloudbool.com www.cloudbool.com;
ssl on;
ssl_certificate /path/to/ssl/cloudbool-rsa.crt;
ssl_certificate_key /path/to/ssl/cloudbool-rsa.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_dhparam /path/to/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers [TLS13+AESGCM+AES128|TLS13+AESGCM+AES256|TLS13+CHACHA20]:[EECDH+ECDSA+AESGCM+AES128|EECDH+ECDSA+CHACHA20]:EECDH+ECDSA+AESGCM+AES256:EECDH+ECDSA+AES128+SHA:EECDH+ECDSA+AES256+SHA:[EECDH+aRSA+AESGCM+AES128|EECDH+aRSA+CHACHA20]:EECDH+aRSA+AESGCM+AES256:EECDH+aRSA+AES128+SHA:EECDH+aRSA+AES256+SHA;
ssl_stapling on;
ssl_stapling_verify on;
location / {
proxy_set_header Accept-Encoding "";
proxy_pass https://cloudbool.com/archive/;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
access_log /var/log/nginx/cloudbool.log;
error_log /var/log/nginx/cloudbool-error.log;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server
{
listen 80;
server_name cloudbool.com www.cloudbool.com;
location / {
rewrite ^/(.*)$ https://cloudbool.com/archive/$1 permanent;
}
}