基于子域名的HAproxy数据库TCP代理SSL配置故障排查
需求可行性与解决方案
你的需求完全可以通过HAproxy实现——利用TCP模式下的SNI(Server Name Indication)匹配,根据子域名将请求转发到对应后端数据库端口,无需暴露多个端口。
问题分析
从HAproxy日志的SSL handshake failure和psql连接报错来看,核心问题出在SSL链路的配置冲突:
- 当前HAproxy前端配置了
bind :8888 ssl ...,要求与客户端完成SSL握手,但psql默认可能未主动发起SSL连接,导致握手失败; - 配置存在笔误:frontend中
use_backend db_example if acl-test-second,但实际定义的后端是db_test_second,匹配子域名test.mydomain.dev时会找不到对应后端; - 若PostgreSQL后端强制要求SSL连接,HAproxy当前的SSL终止模式(客户端→HAproxy是SSL,HAproxy→后端是明文)会被后端拒绝。
具体解决方案
根据你的场景,推荐两种配置模式:
模式一:HAproxy SSL终止(客户端→HAproxy加密,HAproxy→后端明文)
这种模式下HAproxy处理SSL证书,后端数据库可以用明文连接(需配置允许):
- 修正配置笔误:
将frontend中的use_backend db_example if acl-test-second改为use_backend db_test_second if acl-test-second - 确保证书覆盖所有子域名:
检查你的Let's Encrypt证书是否为通配符证书(*.mydomain.dev),或已包含devpg.mydomain.dev、test.mydomain.dev等子域名,否则SNI匹配时会因证书不匹配导致握手失败。 - 强制psql使用SSL连接:
连接时添加sslmode=require参数:psql -h devpg.mydomain.dev -p 8888 -d mydb -U myuser -W sslmode=require - 允许HAproxy向后端发起明文连接:
在PostgreSQL的pg_hba.conf中添加HAproxy服务器IP的明文连接规则:
重启PostgreSQL服务生效。host mydb myuser <HAproxy_IP>/32 md5
模式二:HAproxy SSL透传(全程加密,仅解析SNI)
这种模式更简单,HAproxy不终止SSL,仅解析SNI后转发TCP连接,客户端直接与后端数据库完成SSL握手:
- 修改HAproxy前端配置:
移除bind指令中的ssl crt ...参数,保持纯TCP监听:frontend db_frontend bind :8888 mode tcp log global option tcplog tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } timeout client 1m acl acl-test-first req_ssl_sni -i devpg.mydomain.dev use_backend db_test_first if acl-test-first acl acl-test-second req_ssl_sni -i test.mydomain.dev use_backend db_test_second if acl-test-second # 修正笔误 - 后端无需额外配置:
保持PostgreSQL的SSL启用状态即可,psql连接时自动发起SSL握手(也可显式添加sslmode=require确保加密)。
验证步骤
- 重启HAproxy加载新配置:
systemctl reload haproxy - 查看HAproxy日志,确认无
SSL handshake failure报错 - 测试psql连接,验证子域名是否正确转发到对应后端端口
内容的提问来源于stack exchange,提问作者sylvian
相关产品推荐
相关产品推荐

