Haproxy同时在443端口上使用tcp和http协议
编辑
93
2024-11-26
最近发现同时在443上监听tcp和http协议会有ssl握手的问题,具体表现就是需要握手失败3次才能正确的sni转发。
前情提要
之前写过一篇利用haproxy复用443端口同时使用tcp和http协议,在配置中实现了tcp和http协议利用sni分流同时监听在443的端口,但是这样会造成一定的问题,就是谁先谁后的问题,经常需要握手几次失败之后才能正确的识别到。
故重新配置了一下配置文件,实现了全部由tcp443进站,然后利用sni分流给后端,利用tcp或者sock文件转成http协议。
配置文件
global
log /dev/log local0
log /dev/log local1 notice
user haproxy
group haproxy
unix-bind user haproxy
unix-bind group haproxy
unix-bind mode 660
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
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
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
mode tcp
option tcplog
option dontlognull
timeout connect 24h
timeout client 24h
timeout server 24h
# http转https
frontend http_in
mode http
bind *:80
http-request redirect scheme https
# 配置http入站
frontend https_in
# export DEPLOY_HAPROXY_PEM_PATH=/usr/local/etc/haproxy/cert/
# export DEPLOY_HAPROXY_RELOAD="/bin/systemctl restart haproxy"
# acme.sh --deploy -d <domain> --deploy-hook haproxy
mode http
# bind *:443 ssl crt /usr/local/etc/haproxy/cert alpn h2,http/1.1
bind 127.0.0.1:9443 ssl crt /usr/local/etc/haproxy/cert alpn h2,http/1.1 accept-proxy
# 配置日志
option httplog
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
# 捕获更多请求信息
capture request header Host len 40
capture request header User-Agent len 100
capture request header X-Forwarded-For len 15
# 处理web流量转发给后端
acl host_blog hdr(host) -i xx.xx.xx
acl host_webdav hdr(host) -i xx.xx.xx
acl host_s3 hdr(host) -i xx.xx.xx
use_backend webdav_backend if host_webdav
use_backend s3_backend if host_s3
use_backend blog_backend if host_blog
default_backend default_backend
#配置tcp入站,主要复用443端口
frontend tcp_in
mode tcp
bind *:443
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
# 域名匹配规则
## 1. ssl透传
acl host_app req_ssl_sni -m sub zxxx
## 2. 复用443 tcp代理
acl host_trojan req_ssl_sni -i xxx
acl host_vless req_ssl_sni -i xxxx
# 1. ssl穿透,由后端服务器负责处理ssl,负载均衡服务器只负责加密转发,适合原域名转发的情况
use_backend forward_backend if host_app
# 2. tcp 转发后端处理
use_backend trojan_backend if host_trojan
use_backend vless_backend if host_vless
default_backend tcp_to_https
# TCP 后端解密 HTTPS
backend tcp_to_https
mode tcp
server local-https 127.0.0.1:9443 send-proxy-v2
timeout connect 5s
timeout server 30s
backend webdav_backend
mode http
server filen_webdav 127.0.0.1:8190 check
backend s3_backend
mode http
server filen_s3 127.0.0.1:8191 check
# web后端,sni转发到其他服务器
backend blog_backend
mode http
option forwardfor
option http-server-close
# 保持客户端真实IP
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Real-IP %[src]
http-request set-header Host xxxx
# 转发到远程nginx服务器
server nginx_server xxxxxx ssl check verify none check-sni blog.zdawn.net sni str(blog.zdawn.net) inter 2000 rise 2 fall 4
# ssl穿透
backend forward_backend
mode tcp
#balance roundrobin
option ssl-hello-chk
server blog_server 2xxxxx weight 1 check inter 2000 rise 2 fall 4
# Trojan 后端配置
backend trojan_backend
mode tcp
server trojan_server 127.0.0.1:9000 check
backend vless_backend
mode tcp
server vless_server 127.0.0.1:9010 check
# 默认后端
backend default_backend
mode http
http-request den
后记
利用sock的方式我一直有权限的问题,故更换了tcp的方式,这种方式更加的稳定一些。
现在就可以愉快的玩耍了。
- 0
- 0
-
分享