Haproxy同时在443端口上使用tcp和http协议
Janz Lv4

最近发现同时在443上监听tcp和http协议会有ssl握手的问题,具体表现就是需要握手失败3次才能正确的sni转发。

前情提要

之前写过一篇利用haproxy复用443端口同时使用tcp和http协议,在配置中实现了tcp和http协议利用sni分流同时监听在443的端口,但是这样会造成一定的问题,就是谁先谁后的问题,经常需要握手几次失败之后才能正确的识别到。

故重新配置了一下配置文件,实现了全部由tcp443进站,然后利用sni分流给后端,利用tcp或者sock文件转成http协议。

配置文件

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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的方式,这种方式更加的稳定一些。

现在就可以愉快的玩耍了。

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep