• haproxy + nginx + proxy protocol 获得客户真实IP方法


    公司网站架构为:

    前面2台HA负载均衡,后面3台Nginx负载均衡反向代理,然后后面有N台WEB服务器

    由于要统计IP,需要在WEB服务器日志里体现客户端真实IP

    那么问题来了,通过HA代理的HTTP协议是没有问题的,后端的WEB服务器可以正常获取到客户端真实IP

    但是通过HA代理的HTTPS协议就不行了,为什么呢,因为我们HA设置的是代理模式就是TCP模式,TCP代理SSL协议跳转到后面的NG上

    由于4层协议是不能转发heder的,那后端https自然获取不到客户端真实IP了,怎么办呢,网上找了些资料,做了些测试有2种方案

    第一:HA的https不再使用HA代理,直接使用nginx来做负载均衡,这样问题就解决了,方法和配置参照我上篇随笔。

    第二:是最近2天测试出来的新方案,就是用proxy protocol 协议,也就是代理协议。

    什么是代理协议?解释如下,不是我自己写的,网上COPY的

    1.代理协议即 PROXY protocol,是haproxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取客户IP时非常有用。

    • 多层NAT网络
    • TCP代理(四层)或多层tcp代理
    • https反向代理http(某些情况下由于Keep-alive导致不是每次请求都传递x-forword-for)

    代理协议分为v1和v2两个版本,v1人类易读,v2是二进制格式,方便程序处理。Proxy protocol是比较新的协议,但目前已经有很多软件支持,如haproxy、nginx、apache、squid、mysql等等,要使用proxy protocol需要两个角色sender和receiver,sender在与receiver之间建立连接后,会先发送一个带有客户信息的tcp header,因为更改了tcp协议,需receiver也支持proxy protocol,否则不能识别tcp包头,导致无法成功建立连接。

    以上就是解释,haproxy和Nginx都支持这个协议,nginx需要1.5版本以上,有了这个协议就好办了,haproxy依然使用tcp代理ssl(https),只需要加一点点配置就行,示例配置如下:

    global
            maxconn 64000
            chroot  /usr/share/haproxy
            uid 99
            gid 99
            daemon
            nbproc  5
            tune.ssl.default-dh-param 2048
            stats bind-process 1
            stats socket /var/run/haproxy.stats level admin
    defaults
            log     global
            log 127.0.0.1 local0
            mode    http
            option  dontlognull
            retries 3
            option  redispatch
            option  httpclose
            balance roundrobin
            #balance leastconn
            #option  forwardfor
            #option  forwardfor if-none
    
            maxconn 64000
            timeout http-request 5s
            timeout connect 5000
            timeout client  10000
            timeout server  30000
    listen  monitor_stat :8088
            stats   uri /ihaproxy-stats
            stats   realm Haproxy Statistics
            stats   auth ha_house:ZW5dmKRTObmOuA1nnS5U
            stats   hide-version
            bind-process    1
    
    frontend yidonghttps-in
            mode tcp
            bind *:443
            default_backend yidongclient_server_https
    
    frontend http-in
            bind *:80
            log global
            option httplog
            option forwardfor
    backend yidongclient_server_http
            server yidonghttp_41 172.17.2.110:80 weight 1 check inter 5000 rise 2 fall 5
    backend yidongclient_server_https
            mode tcp
            server yidonghttps_37   172.17.2.110:443 send-proxy

    上面配置其实没添加什么,只是在最后的backend  yidongclient_server_https的server里的最后面添加上了 send-proxy 参数,这样HA就把proxy protocol协议发送到后端Nginx上了。

    配置完ha后,后面的nginx也需要配置,由于80端口自然能获取客户端IP地址,我们主要来配置443端口

    配置文件如下

    upstream ihouse443{
      server 172.17.3.108:443 max_fails=3 fail_timeout=60 weight=1;
    
    }
    
    server {
      listen 443 proxy_protocol;
      server_name ihouse.ifeng.com;
      access_log /data/logs/nginx/ihouse_access.log access;
      error_log  /data/logs/nginx/ihouse_error.log ;
      ssl on;
      ssl_certificate /data/ifengsite/htdocs/ihouse.ifeng.com.crt;
      ssl_certificate_key /data/ifengsite/htdocs/ihouse.ifeng.com.key;
    
      ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDH:AES:HIGH:!aNULL:!MD5:!ADH:!DH;
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
       location / {
        proxy_pass https://ihouse443;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Real-IP $proxy_protocol_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-For $http_x_forwarded_for;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_max_temp_file_size 0;
        proxy_connect_timeout 90;
        proxy_send_timeout 90;
        proxy_read_timeout 90;
        proxy_buffer_size 4k;
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k;
        proxy_temp_file_write_size 64k;
      }
    }

    主要添加以上红色粗体内容,server段里添加 proxy_protocol 使之支持代理协议

    location 里添加红色粗体内容,定义新的headr信息,并且发送到后端WEB上

    最后需要定义下日志文件,重新定义下,这个日志文件指的是负载均衡的nginx的日志文件,至于后端的WEB则不需要

    #user  www www;
    worker_processes 1;
    
    #error_log  /data/logs/nginx/error.log;
    #pid        /var/run/nginx.pid;
    
    #Specifies the value for maximum file descriptors that can be opened by this process.
    worker_rlimit_nofile 1024;
    
    events {
            use epoll;
            worker_connections 51200;
    }
    
    http
    {
            include       mime.types;
            #include       proxy.conf;
            default_type  application/octet-stream;
    
            server_names_hash_bucket_size 128;
            client_header_buffer_size 32k;
            large_client_header_buffers 4 32k;
            client_max_body_size    300m;
            #client_max_body_size    32m;
    
            #limit_req_zone $baidu_spider zone=baidu_spider:10m rate=15r/m;
            sendfile on;
            tcp_nopush     on;
    
            keepalive_timeout 30;
    
            tcp_nodelay on;
            #ssi on;
            #ssi_silent_errors on;
            fastcgi_connect_timeout 180;
            fastcgi_send_timeout 180;
            fastcgi_read_timeout 180;
            fastcgi_buffer_size 128k;
            fastcgi_buffers 8 128k;
            fastcgi_busy_buffers_size 128k;
            fastcgi_temp_file_write_size 128k;
            proxy_headers_hash_max_size 51200;
            proxy_headers_hash_bucket_size 6400;
            gzip on;
            gzip_min_length         2k;
            gzip_buffers            4 16k;
            gzip_http_version       1.0;
            gzip_comp_level 6;
            gzip_types              text/plain application/x-javascript text/css application/xml;
            gzip_vary               on;
            #log_format  access     '$proxy_protocol_addr-,$remote_addr--,$proxy_add_x_forwarded_for---,$http_x_forwarded_for----,$remote_user,$time_local,$host,$request,$status,$http_referer,$HTTP_X_UP_CALLING_LINE_ID,$request_time,$http_user_agent  $upstream_addr  $upstream_response_time  $upstream_cache_status';        
            log_format  access     '-$proxy_protocol_addr-,--$remote_addr--,---$http_x_forwarded_for---,----$proxy_add_x_forwarded_for----,$remote_user,$time_local,$host,$request,$status,$http_referer,$HTTP_X_UP_CALLING_LINE_ID,$request_time,$http_user_agent  $upstream_addr  $upstream_response_time  $upstream_cache_status';
            #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
            #              '$status $body_bytes_sent "$http_referer" '
            #              '"$http_x_forwarded_for" "$http_user_agent"';
    
            #upstream backend {
            #       server 127.0.0.1:9000 weight=5  max_fails=3  fail_timeout=30s;
            #}
    
        include conf.d/*;
    
    }

    主要添加上以上红色粗体日志参数,这样在负载均衡的nginx上就可以看到https过来的客户端真实IP了,后端的WEB的https也可以获取真实IP了

    另外如果是HA后面不再通过NG做反向代理转发的话,那么NG的主机文件配置需要如下配置

        server {
            listen       443 ssl proxy_protocol;
            server_name  ihouse.ifeng.com;
            ssl_certificate      /data/ifengsite/htdocs/ihouse.ifeng.com.crt;
            ssl_certificate_key  /data/ifengsite/htdocs/ihouse.ifeng.com.key;
    
            ssl_session_cache    shared:SSL:1m;
            ssl_session_timeout  5m;
    
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers  on;
            set_real_ip_from 172.17.3.0/24;
            real_ip_header   proxy_protocol;
    
            location / {
                root   html;
                index  index.html index.htm;
            }
        }

    依然需要设置 proxy_protocol

    设置real_ip的前端代理主机IP或者IP段

    设置real_ip 的header

    参考文献

    https://www.52os.net/articles/PROXY_protocol_pass_client_ip.html

    https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/

  • 相关阅读:
    JSP简单练习-数组应用实例
    Android中的动画具体解释系列【4】——Activity之间切换动画
    php学习之道:WSDL具体解释(三)
    破解电信光猫(个人真实经验)
    POj 1879 Tempus et mobilius Time and motion (模拟+群)
    使用mysql-mmm实现MySQL高可用集群
    德克萨斯扑克_百度百科
    姜饼屋_百度百科
    阿根廷探戈----中英文对照
    波尔卡舞_百度百科
  • 原文地址:https://www.cnblogs.com/hh2737/p/8951872.html
Copyright © 2020-2023  润新知