我怎样才能将 HAproxy 与 SSL 结合使用并获取 X-Forwarded-For 标头并告诉 PHP SSL 正在使用中?

我怎样才能将 HAproxy 与 SSL 结合使用并获取 X-Forwarded-For 标头并告诉 PHP SSL 正在使用中?

我有以下设置:

(internet) ---> [  pfSense Box  ]    /-> [ Apache / PHP server ]
                [running HAproxy] --+--> [ Apache / PHP server ]
                                    +--> [ Apache / PHP server ]
                                     \-> [ Apache / PHP server ]

对于 HTTP 请求,这是有效的伟大的,请求可以顺利分发到我的 Apache 服务器。对于 SSL 请求,我让 HAproxy 使用 TCP 负载平衡分发请求,并且它可以正常工作,但是由于 HAproxy 不充当代理,因此它没有添加X-Forwarded-ForHTTP 标头,并且 Apache / PHP 服务器不知道客户端的真实 IP 地址。

因此,我stunnel在 HAproxy 前面添加了一个,显示 stunnel 可以添加X-Forwarded-ForHTTP 标头。但是,我可以安装到 pfSense 中的软件包没有添加此标头……此外,这显然使我无法使用 KeepAlive 请求,我真的很想保留它。但最大的问题是,stunnel 将 HTTPS 请求转换为纯 HTTP 请求,因此 PHP 不知道 SSL 已启用并尝试重定向到 SSL 站点,从而扼杀了这个想法。

如何使用 HAproxy 在多个 SSL 服务器之间进行负载平衡,让这些服务器都知道客户端的 IP 地址知道 SSL 正在使用中吗?如果可能的话,我该如何在 pfSense 服务器上执行此操作?

或者我应该放弃这一切,只使用 nginx?

答案1

您不需要放弃一切,您只需在 haproxy 前面使用 nginx 即可获得 SSL 支持,同时保留所有负载平衡配置。如果您不想,您甚至不需要将 nginx 用于 HTTP。Nginx 可以传递 X-Forwarded-For 和指示正在使用 SSL 的自定义标头(以及客户端证书信息(如果您需要))。发送所需信息的 Nginx 配置片段:

proxy_set_header SCHEME $scheme;      # http/https
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header CLIENT_CERT $ssl_client_raw_cert;

答案2

仅供参考,由于此线程经常涉及 HAProxy + SSL,因此自 1.5-dev12 以来,HAProxy 确实支持两端的本机 SSL。因此,拥有 X-Forwarded-For、HTTP keep-alive 以及告诉服务器连接是通过 SSL 建立的标头非常简单,如下所示:

listen front
    bind :80
    bind :443 ssl crt /etc/haproxy/haproxy.pem
    mode http
    option http-server-close
    option forwardfor
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    server srv1 1.1.1.1:80 check ...
    ...

我确信到那时你想出了一些不同的东西,但至少新访客现在可以得到简单的解决方案:-)

答案3

对于其他遇到此问题的人,我遵循了 Ochoto 的建议并使用了 nginx。以下是我用来实现此目的的具体步骤在我的 pfSense 路由器上

  1. 使用 pfSense Web 界面,我安装了 pfSensePfJailctl 包以及“jail_template”包系统 > 软件包所以我可以创建一个 FreeBSD jail,在其下在 pfSense 系统上编译和安装 nginx。

  2. 我为我的 nginx 服务器配置了一个 jail,如下所示:服务 > 监狱,为新 jail 赋予与我运行 HAproxy 的虚拟 IP 别名相同的主机名和 IP 地址。我将 jail 绑定到 WAN 接口。我使用了默认 jail 模板并启用了 unionfs 而不是 nullfs。

  3. 一旦 jail 启动,我就通过 SSH 进入 pfSense 框并运行jls以查找 jail 的号码。然后我运行jexec 1 sh以在 jail 内获取 shell。从那里我设置了 BSD 端口并使用以下命令安装了 nginx:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. 然后,我将 nginx 配置为监听端口 443,并将所有请求传递到端口 80 上的 HAproxy,包括真实 IP 和 HTTP 标头内的 SSL 状态。我usr/local/etc/nginx/nginx.conf看起来像这样:

    worker_processes  1;
    
    events {
        worker_connections  2048;
    }
    
    http {
        upstream haproxy {
            server 209.59.186.35:80;
        }
    
        server {
            listen       443;
            server_name  my.host.name default_server;
            ssl                  on;
            ssl_certificate      my.crt;
            ssl_certificate_key  my.key;
            ssl_session_timeout  5m;
    
            ssl_protocols  SSLv3 TLSv1;
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers   on;
    
            location / {
                proxy_pass http://haproxy;
    
                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_set_header X-Forwarded-Proto https;
            }
        }
    
    }
    
  5. 然后我修改了我的 PHP 应用程序来检测X-Forwarded-ProtoHTTP 标头:

    function usingSSL()
    {
        return (
           (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' )
            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
                   && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' ));
    }
    

所以最终的设置是:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
                [    (pfSense server)  ]

答案4

HAProxy 无法在不使用原始 TCP 模式的情况下访问 SSL 后端,从而丢失数据X-Forwarded-For,但是,您可以使用后端传输的监听通道重新加密流量。不过,效果很差。

我更喜欢 Ochoto 的方法,但有一个警告:nginx 是一款功能齐全的负载均衡器;如果你正在使用它,我会建议你把它用于一切。将传入的 HTTPS 代理到负载平衡的 HTTPS 后端 - 这样,就不需要自定义标头来获取 SSL 信息(除非你确实需要客户端证书)。

相关内容