场景:
用户访问-----haproxy(docker部署)-----Nginx前端(docker部署)-----K8S后端
使用K8S部署的后端需要获取用户访问的IP地址(用户使用终端的IP)。
解决方案
用户访问时,在Haproxy处添加添加一个自定义的X-Real-IP
请求头,后端通过这个请求头获取用户真实IP。
HTTP
只需要配置Haproxy即可,不用修改Nginx配置,Haproxy配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| global log 127.0.0.1 local0 daemon defaults log global mode tcp option abortonclose option redispatch option forwardfor except 127.0.0.0/8 retries 3 maxconn 2000 timeout connect 5000 timeout client 50000 timeout server 50000 frontend admin_stats bind :8033 mode http stats enable option httplog maxconn 10 stats refresh 30s stats uri /admin stats auth admin:123123 stats hide-version stats admin if TRUE frontend header_front bind *:32297 mode http option forwardfor acl android-browser hdr_reg(User-Agent) -i Android use_backend app_backend if android-browser default_backend pc_backend backend app_backend mode http server mom 172.16.30.52:32298 check http-request set-header X-Real-IP %[src] backend pc_backend mode http server mom-app 172.16.30.52:32298 http-request set-header X-Real-IP %[src]
|
在 haproxy
配置中添加 option forwardfor
及http-request set-header X-Real-IP %[src]
。
HTTPS
如果使用HTTPS访问,那么需要同时修改Haproxy配置及Nginx配置。
Haproxy配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| global log 127.0.0.1 local0 daemon defaults log global mode tcp option abortonclose option redispatch #option forwardfor except 127.0.0.0/8 retries 3 maxconn 2000 timeout connect 5000 timeout client 50000 timeout server 50000 frontend admin_stats bind :8033 mode http stats enable option httplog maxconn 10 stats refresh 30s stats uri /admin stats auth admin:123123 stats hide-version stats admin if TRUE frontend header_front bind *:32295 mode http option forwardfor acl android-browser hdr_reg(User-Agent) -i Android use_backend app_backend if android-browser default_backend pc_backend frontend https_frontend bind *:32297 mode tcp acl tls req.ssl_hello_type 1 tcp-request inspect-delay 5s tcp-request content accept if tls default_backend pc_https_backend backend app_backend mode http server mom 172.16.30.52:32298 check http-request set-header X-Real-IP %[src] backend pc_backend mode http server mom-app 172.16.30.52:32298 http-request set-header X-Real-IP %[src] backend pc_https_backend mode tcp server mom-https-app 172.16.30.52:32296 send-proxy-v2
|
使用mode tcp
以及send-proxy-v2
进行透传。
Nginx配置示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
worker_processes 1; error_log /var/log/nginx/error.log;
events { worker_connections 1024; }
http { include mime.types; default_type application/octet-stream; log_format main '$proxy_protocol_addr - $remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/logs/nginx/access.log main; sendfile on; keepalive_timeout 65; server { listen 443 ssl proxy_protocol; server_name webServer; ssl_certificate /home/cert/6030147_wx.xxx.com.pem; ssl_certificate_key /home/cert/6030147_wx.xxx.com.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!NULL:!aNULL:!ADH:!3DES:!RC4; ssl_prefer_server_ciphers on; autoindex_localtime on; client_max_body_size 1200M; add_header X-Content-Type-Options nosniff; add_header Strict-Transport-Security "max-age=315360; includeSubdomains;"; add_header X-XSS-Protection "1; mode=block"; location / { root html; index index.html index.htm; } location ^~/api/ { proxy_read_timeout 300s; proxy_pass http://172.16.30.52:32299/api/; proxy_set_header X-Real-IP $proxy_protocol_addr; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
|
在 nginx.conf
中添加 proxy_protocol
以及proxy_set_header X-Real-IP $proxy_protocol_addr;
。
后端代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RestController @RequestMapping("/api") public class IpController { @GetMapping("/getRealIp") public String getRealIp(HttpServletRequest request) { String realIp = request.getHeader("X-Real-IP"); System.out.println("X-Real-IP: " + realIp); return "X-Real-IP: " + realIp; } }
|