如何将HAproxy与SSL结合使用并获取X-Forwarded-For标头,并告诉PHP正在使用SSL?


20

我有以下设置:

(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前面添加了内容,阅读了tunnel可以添加X-Forwarded-ForHTTP标头的信息。但是,我可以安装到pfSense中的软件包不会添加此标头...而且,这显然使我无法使用KeepAlive请求,而我确实希望保留该请求。但是,使该想法无效的最大问题是隧道将HTTPS请求转换为纯HTTP请求,因此PHP不知道启用了SSL并试图将其重定向到SSL站点。

如何使用HAproxy在多个SSL服务器上实现负载平衡,从而使这些服务器既知道客户端的IP地址知道正在使用SSL?如果可能的话,如何在pfSense服务器上做到这一点?

还是应该放弃所有这些,而仅使用nginx?


3
回复:stunnel和X-Forwarded-For在这里看到。
Shane Madden

@Shane:谢谢。那就是我读到的丢失了KeepAlive的地方:-)
乔什(Josh)

2
+1可实现出色的ASCII图表。:-)
KyleFarris 2013年

@AlanHamlett,您的链接
404。– luckydonald

@luckydonald谢谢,这是更新的链接。您可以通过将send-proxy关键字添加到haproxy配置中来使用代理协议。我在此处写了一个带有示例的博客文章:wakatime.com/blog/23-how-to-scale-ssl-with-haproxy-and-nginx
艾伦·

Answers:


17

您无需删除所有内容,只需在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;

37

仅作记录,由于该线程通常涉及HAProxy + SSL,因此HAProxy从1.5-dev12开始在两侧均支持本机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 ...
    ...

我敢肯定,当您提出不同的建议时,但是至少新的访问者现在会获得简便的解决方法:-)


谢谢,这是个很好的一般信息...我的问题是关于在pfSense上运行 HAproxy的问题,所以现在我仍然需要在HAproxy之前使用nginx,因为pfSense不支持此版本的HAProxy(但)
Josh

抱歉,乔什,我对pfSense并不了解,无法知道是否可以更新它的组件,并且由于您是在谈论安装软件包,所以我相信情况确实如此。我上次尝试的时间大约是5年前,所以我不记得所有的细节了。
威利·塔罗

1
我目前对haproxy配置了解不多,但是对于最新版本,我不得不添加acl:acl is-ssl dst_port 443并重写一行:reqadd X-Forwarded-Proto:\ https if is-sslNginx似乎能够很好地处理此标头
greg0ire 2013年

这就像一个魅力。无需nginx。
杰伊·泰勒

1
@ greg0ire是因为使用最新的haproxy,没有is_ssl而是ssl_fc
josch 2014年

12

对于发现此问题的其他人,我遵循了Ochoto的建议并使用了Nginx。这是我在pfSense路由器上执行此操作的具体步骤:

  1. 使用pfsense Web界面,我在系统>软件包下安装了pfsense PfJailctl软件包和“ jail_template”软件包,因此可以创建一个FreeBSD监狱,在该监狱下编译并在pfsense系统上安装nginx。

  2. 我在“ 服务”>“ Jails”下为我的Nginx服务器配置了一个监狱,为新监狱提供了运行HAproxy的虚拟IP别名的主机名和IP地址。我将监狱绑定到WAN接口。我使用默认的jail模板并启用了unionfs而不是nullfs。

  3. 监狱启动后,我通过SSH进入pfsense框并运行jls以查找监狱的号码。然后我跑去jexec 1 sh在监狱里弄个贝壳。从那里,我设置BSD端口并使用以下命令安装nginx:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. 然后,我将nginx配置为侦听端口443,并将所有请求传递给端口80上的HAproxy,包括HTTP头中的真实IP和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)  ]

2
除非确实需要,否则应禁用SSLv2。gnu.org/software/gnutls/manual/html_node / ...我不知道Nginx为什么仍在其默认配置中支持它。
奥乔托2011年

还应意识到,使用1024个辅助连接,您最多支持512个并发客户端。
奥乔托2011年

@Ochoto:感谢您提供这两个提示!我是HAproxy的新手,但对nignx则不甚了解
Josh

7

我针对haproxy的1.5-dev-17版本的配置:

global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        #log loghost    local0 info
        maxconn 4096
        #chroot /usr/share/haproxy
        user haproxy
        group haproxy
        daemon
        #debug
        #quiet

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option  http-server-close
        retries 3
        option redispatch
        fullconn 1000        
        maxconn 1000
        timeout queue 600s
        timeout connect 5s
        timeout client 600s
        timeout server 600s

frontend http-in
        bind *:80
        bind *:443 ssl crt /usr/local/etc/ssl/certs
        reqadd X-Forwarded-Proto:\ https if { ssl_fc }
        default_backend varnish-ha
        option forwardfor
backend varnish-ha
  server hafront1 10.1.69.1:6081  minconn 100 maxqueue 10000

它使用ssl_fcACL。请注意,该option http-server-close部分非常重要。


谢谢!我正在运行HAProxy v1.4,所以我认为我无法做到这一点,但这可能会对其他人有所帮助。
乔什(Josh)

是的,并且1.5应该很快就会推出。
greg0ire 2013年

5

如果不使用原始TCP模式,HAProxy无法访问SSL后端,这会丢失X-Forwarded-For,但是您可能会使用侦听隧道对后端传输重新加密流量。不过很丑。

需要警告的是,我更喜欢Ochoto的方法:nginx是功能非常强大的负载平衡器;如果您正在使用它,我会说所有都使用它。代理传入的HTTPS以加载平衡的HTTPS后端-这样,就不需要SSL信息的自定义标头(除非您确实需要客户端证书)。


我不确定为什么要坚持使用HAproxy。我认为这是因为pfSense有一个程序包,而SOIS会使用它。都不是一个很好的理由。:-)
乔什(Josh)

我摆脱了nginx蜂拥而至的功能,除非您使用非标准模块streaming_fair,否则它将执行简单的循环(或客户端ip哈希),而不考虑目标后端是否已经忙于请求并因此在该后端增加队列还有其他免费的后端,正在等待工作。HAProxy还可以很好地监视后端并显示有关它们的统计信息。
奥乔托2011年

如果只有以下一种情况可以实现a)Nginx获得体面的状态跟踪和公平的负载平衡b)HAProxy获得体面的SSL支持一个人只能希望
Yavor Shahpasov 2011年

我刚刚使用nginx-> haproxy-> nginx->后端为SSL部署了安装程序,这是由于haproxy中缺少HTTPS支持(如此处所述),也是因为nginx不支持http运行状况检查脚本。
杰弗里2012年

2

去年,我实现了一个解决方案,以利用HAProxy的所有功能并与pfSense保持良好隔离的方式将HAProxy与pfSense集成。因此,它是生产环境中可行的选择。SSL在HAProxy上终止。我使用ezjail和Ports Collection在pfSense的一个监狱安装了HAProxy 。这样,很容易独立维护两个组件。您可以安装所需的任何版本。我从1.5-dev13开始。从那时起,它对我来说是完美的。我已经在这里记录了整个过程。

在pfSense上安装HAProxy

顺便说一句,Willy,非常感谢您提供了如此出色的产品。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.