NGINX IMAP代理无法获取客户端真实IP的问题求助
我编译了带有--with-http_realip_module的nginx/1.24.0作为IMAP代理,但遇到两个问题:
- 无法在nginx的
80_access.log日志中获取客户端真实IP; - 无法在index.php的
$_SERVER["REMOTE_ADDR"]变量中获取客户端真实IP。
日志中始终显示服务器自身的内网或外网IP:
- 当设置
server_name为imap.example.com、auth_http为imap.example.com/index.php时,日志显示服务器外网IP; - 当设置
server_name为imap、auth_http为imap/index.php时,日志显示服务器内网IP。
我尝试过配置real_ip_header X-Forwarded-For; set_real_ip_from 0.0.0.0/0;但无效果,附上当前配置:
user www; worker_processes auto; pid /var/run/nginx.pid; worker_rlimit_nofile 20480; events { use kqueue; worker_connections 10240; multi_accept on; } http { include /usr/local/etc/nginx/mime.types; default_type application/octet-stream; server_tokens off; log_format main '$remote_addr - $remote_user [$time_local] $status "$request" $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/nginx-access.log main; error_log /var/log/nginx/nginx-error.log warn; keepalive_timeout 30; keepalive_requests 200; server { listen 80; server_name imap.example.com; server_name_in_redirect on; access_log /var/log/nginx/gatewaymail.net/imap/80_access.log common; error_log /var/log/nginx/gatewaymail.net/imap/80_errors.log warn; root /usr/local/www/nginx/imap; index index.php; location / { } location = /favicon.ico { log_not_found off; } location ~ \.php$ { try_files $uri = 404; fastcgi_pass unix:/var/run/imap-php8.3-fpm.sock; fastcgi_send_timeout 300; fastcgi_read_timeout 300; include fastcgi_params; fastcgi_split_path_info ^(.+?\.php)(/.*)?$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name; fastcgi_buffer_size 1024k; fastcgi_buffers 4 1024k; fastcgi_busy_buffers_size 1024k; fastcgi_temp_file_write_size 1024k; set $path_info $fastcgi_path_info; fastcgi_param PATH_INFO $path_info; fastcgi_param SERVER_ADMIN support@gatewaymail.net; fastcgi_param SERVER_SIGNATURE nginx/$nginx_version; fastcgi_index index.php; } } } mail { proxy_pass_error_message on; server { auth_http imap.example.com/index.php; listen 143; protocol imap; error_log /var/log/nginx/gatewaymail.net/imap/imap_proxy_errors.log warn; } }
核心问题是:Nginx的mail模块调用auth_http接口时,是作为客户端向自身http模块发起请求的,默认不会传递IMAP客户端的真实IP,导致http模块拿到的请求来源是服务器自身IP。需从以下几处调整:
1. 在mail模块中传递客户端真实IP到auth_http
修改mail块内的server配置,添加auth_http_header指令,将IMAP客户端IP通过自定义Header传给后端:
mail { proxy_pass_error_message on; server { auth_http imap.example.com/index.php; # 新增:传递客户端真实IP到auth_http接口 auth_http_header X-Client-IP $remote_addr; listen 143; protocol imap; error_log /var/log/nginx/gatewaymail.net/imap/imap_proxy_errors.log warn; } }
2. 在http模块中配置real_ip识别真实IP
在http块中添加real_ip相关配置,指定从自定义Header获取真实IP,并信任服务器自身IP的请求:
http { # 原有配置... # 新增real_ip配置 set_real_ip_from 127.0.0.1; # 服务器内网IP,可补充实际内网段 set_real_ip_from 你的服务器外网IP; # 替换为实际外网IP real_ip_header X-Client-IP; real_ip_recursive off; # 无多层代理时保持off即可 # 原有server配置... }
注意:
set_real_ip_from必须填写Nginx发起auth_http请求时使用的源IP(即服务器自身的内网/外网IP),否则Nginx不会信任该来源的Header。
3. 确保PHP能获取真实IP
检查PHP的location块,确保fastcgi_params包含REMOTE_ADDR参数(默认配置通常已包含):
fastcgi_param REMOTE_ADDR $remote_addr;
因为real_ip模块已将$remote_addr替换为客户端真实IP,只要传递该参数,PHP的$_SERVER["REMOTE_ADDR"]就能拿到真实IP。
4. 优化日志格式(可选)
若需同时记录原始请求IP和真实IP,可修改日志格式:
log_format main '$remote_addr - $remote_user [$time_local] $status "$request" $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_client_ip" "$realip_remote_addr"';
其中$realip_remote_addr是原始请求IP(服务器自身IP),$remote_addr是替换后的客户端真实IP。
内容的提问来源于stack exchange,提问作者scazy0rg

