HAProxy 是一个可靠高性能的负载均衡器、反向代理服务器

安装 HAProxy #

apt update && apt install haproxy -y

## 检查安装
haproxy -v

SSL 直通 #

通过前置监听 443 端口,将客户端流量代理到不同的后端。此配置不处理 SSL 证书,SSL 证书的配置、拆包和解密由后端服务处理。

global
    log stdout format raw daemon notice
    user root
    group root
    daemon

defaults
    log global
    timeout connect 10s
    timeout client 30s
    timeout server 30s

frontend ft_main
    mode tcp
    option tcplog
    bind *:443

    tcp-request inspect-delay 3s
    tcp-request content accept if { req.ssl_hello_type 1 }

    use_backend exp1.com if { req.ssl_sni -i exp1.com }
    use_backend exp2.com if { req.ssl_sni -i exp2.com }

backend exp1.com
    mode tcp
    server s1 127.0.0.1:8000

backend exp2.com
    mode tcp

    ## 多个 server 轮询
    server s1 127.0.0.1:8001
    server s2 127.0.0.1:8002

SSL 直通工作在 tcp 模式下,默认传递给后端的客户端 IP 是127.0.0.1,如果需要传递真实客户端 IP,可以使用 Proxy Protocol,对应参数是send-proxy

backend exp1.com
    mode tcp
    server s1 127.0.0.1:8000 send-proxy ## send-proxy-v2

前端 HAProxy 发送了 Proxy Protocol,你需要在后端配置接收,这里以 Nginx 为例

server {
    listen 8000 ssl proxy_protocol;
    server_name exp1.com;
    
    set_real_ip_from 127.0.0.1;
    real_ip_header proxy_protocol;

    ssl_certificate /path/cert.pem;
    ssl_certificate_key /path/key.pem;

    ...
}

SSL 终止 #

此配置由 HAProxy 处理 SSL 证书,将解密后的流量代理到后端

global
    log stdout format raw daemon notice
    user root
    group root
    daemon

    # https://ssl-config.mozilla.org/
    ssl-default-bind-curves X25519:prime256v1:secp384r1
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options prefer-client-ciphers ssl-min-ver TLSv1.2 no-tls-tickets

    ssl-default-server-curves X25519:prime256v1:secp384r1
    ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
    log global
    timeout connect 10s
    timeout client 30s
    timeout server 30s

frontend ft_main
    mode http
    option httplog
    bind *:443 ssl crt /etc/haproxy/certs/

    use_backend exp1.com if { req.ssl_sni -i exp1.com }
    use_backend exp2.com if { req.ssl_sni -i exp2.com }

backend exp1.com
    mode http
    server s1 127.0.0.1:8001

backend exp2.com
    mode http
    server s1 127.0.0.1:8002

/etc/haproxy/certs/为 SSL 证书存放目录,你可以使用cat命令将证书和私钥保存到一个文件里面,然后放进这个目录,HAProxy 会根据 sni 选择对应的文件名使用证书。

cat cert.pem key.pem > exp.com.pem

在客户端和 HAProxy 之间启用 HTTP2(首选H2)

frontend ft_main
    mode http
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1

    use_backend exp1.com if { req.ssl_sni -i exp1.com }
    use_backend exp2.com if { req.ssl_sni -i exp2.com }

SSL 终止在 http 模式下工作,传递真实客户端 IP 可以使用X-Forwarded-For,对应参数是option forwardfor

backend exp1.com
    mode http
    option forwardfor
    server s1 127.0.0.1:8000

同时使用 SSL 直通和 SSL 终止 #

设想一下,你在 HAProxy 前置监听 443 的情况下,后端一部分服务需要后端自行处理 SSL,一部分需要前置的 HAProxy 处理 SSL,这时候应该怎么做?具体实现做了个流程图

global
    log stdout format raw daemon notice
    user root
    group root
    daemon
    
    # https://ssl-config.mozilla.org/
    ssl-default-bind-curves X25519:prime256v1:secp384r1
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options prefer-client-ciphers ssl-min-ver TLSv1.2 no-tls-tickets

    ssl-default-server-curves X25519:prime256v1:secp384r1
    ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
    log global
    timeout connect 10s
    timeout client 30s
    timeout server 30s

frontend ft_main
    mode tcp
    option tcplog
    bind *:443

    tcp-request inspect-delay 3s
    tcp-request content accept if { req.ssl_hello_type 1 }

    ## SSL 直通
    use_backend exp1.com if { req.ssl_sni -i exp1.com }
    use_backend exp2.com if { req.ssl_sni -i exp2.com }

    ## SSL 终止
    use_backend bk_haproxy_ssl if { req.ssl_sni -i exp3.com }
    use_backend bk_haproxy_ssl if { req.ssl_sni -i exp4.com }

backend bk_haproxy_ssl
    mode tcp
    server s1 127.0.0.1:8443 send-proxy-v2

frontend ft_ssl_termination
    mode http
    option httplog
    bind *:8443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1 accept-proxy
    use_backend exp3.com    if { hdr(host) -i exp3.com }
    use_backend exp4.com    if { hdr(host) -i exp4.com }

backend exp1.com
    mode tcp
    server s1 127.0.0.1:8001 send-proxy

backend exp2.com
    mode tcp
    server s1 127.0.0.1:8002

backend exp3.com
    mode http
    option forwardfor
    server s1 127.0.0.1:8003

backend exp4.com
    mode http
    option forwardfor
    server s1 127.0.0.1:8004

启用 HAProxy 统计页面 #

HAProxy 自带了个信息统计页面,启用方法:

frontend ft_stats
    mode http
    bind *:8005
    stats enable
    stats uri /stats   ## 配置访问网址根目录
    stats refresh 60s
    stats auth user:passwd ## 配置访问密码

其他 #

  • 测试配置文件haproxy -c -V -f /etc/haproxy/haproxy.cfg