HAProxy 是一个可靠高性能的负载均衡器、反向代理服务器
安装 HAProxy
Debian 11 安装 HAProxy 2.8 版本。点击查看其他版本安装方法
1 2 3 4 5 6 7 8 9 10 11 12 apt update && apt install curl gnupg2 ca-certificates -y curl https://haproxy.debian.net/bernat.debian.org.gpg | gpg --dearmor > /usr/share/keyrings/haproxy.debian.net.gpg echo deb "[signed-by=/usr/share/keyrings/haproxy.debian.net.gpg]" http://haproxy.debian.net bullseye-backports-2.8 main > /etc/apt/sources.list.d/haproxy.listapt-get update && apt-get install haproxy=2.8.\* haproxy -v
SSL 直通
通过前置监听 443 端口,将客户端流量代理到不同的后端。此配置不处理 SSL 证书,SSL 证书的配置、拆包和解密由后端服务处理。
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 global log /dev/log local0 warning user root group root daemon defaults log global timeout connect 10 s timeout client 30 s timeout server 30 s frontend ft_main mode tcp bind *:443 tcp -request inspect-delay 3 s 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 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
1 2 3 backend exp1.com mode tcp server s1 127.0.0.1:8000 send-proxy ## send-proxy-v2
前端 HAProxy 发送了 Proxy Protocol,你需要在后端配置接收,这里以 Nginx 为例
1 2 3 4 5 6 7 8 9 10 11 12 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 证书,将解密后的流量代理到后端
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 global log /dev/log local0 warning user root group root daemon 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 ssl -default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl -default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets defaults log global timeout connect 10 s timeout client 30 s timeout server 30 s frontend ft_main mode http 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 选择对应的文件名使用证书。
1 cat cert.pem key.pem > exp.com.pem
在客户端和 HAProxy 之间启用 HTTP2(首选H2)
1 2 3 4 5 6 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
1 2 3 4 backend exp1.com mode http option forwardfor server s1 127.0.0.1:8000
同时使用 SSL 直通和 SSL 终止
设想一下,你在 HAProxy 前置监听 443 的情况下,后端一部分服务需要后端自行处理 SSL,一部分需要前置的 HAProxy 处理 SSL,这时候应该怎么做?具体实现做了个流程图
flowchart LR
1(HTTPS流量) --> 2(HAProxy 443 端口)
2 --> 3(SSL直通)
2 --> 4(SSL终止)
3 --> 5(exp1.com)
3 --> 6(exp2.com)
5 --> 7(后端8001端口)
6 --> 8(后端8002端口)
4 --> 9(exp3.com)
4 --> 10(exp4.com)
9 --> 11(HAProxy 8443 端口)
10 --> 11(HAProxy 8443 端口)
11 --- 12(SSL处理和分流)
12 --> 13(后端8003端口)
12 --> 14(后端8004端口)
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 55 56 57 58 59 global log /dev/log local0 warning user root group root daemon 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 ssl -default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl -default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets defaults log global timeout connect 10 s timeout client 30 s timeout server 30 s frontend ft_main mode tcp bind *:443 tcp -request inspect-delay 3 s 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 } 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 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 自带了个信息统计页面,启用方法:
1 2 3 4 5 6 7 frontend ft_stats mode http bind *:8005 stats enable stats uri /stats ## 配置访问网址根目录 stats refresh 60 s stats auth user:passwd ## 配置访问密码
其他
测试配置文件haproxy -c -V -f /etc/haproxy/haproxy.cfg