Janz Blog

Janz Blog

利用haproxy复用443端口同时使用tcp和http协议

80
2024-11-04

最近买了一台aws的新加坡的机器,对三网的网络都很不错,遂想好好的利用一下这台机器的网络,做梯子有点大材小用了,同时可以用这台机器给我的主力机做网络代理。

为什么用Haproxy?

梯子一般用网络协议为tcp,而反代其他网站或者自己的网站是http协议的,而haproxy刚好可以利用sni很好的处理tcp和http协议,这就配置起来简单容易了很多,实际上我的nginx前端也是haproxy的。

什么是Haproxy(AI)?

HAProxy(High Availability Proxy)是一款开源的负载均衡器和代理服务器,常用于提高网络和应用程序的性能与可靠性。它通常部署在客户端与服务器之间,以分发客户端请求到多个后端服务器,从而实现负载均衡、故障转移、SSL 终止等功能。

主要特性:

  1. 负载均衡:HAProxy 可以在多个后端服务器之间分配请求,支持多种负载均衡算法(如轮询、最少连接、源地址哈希等)。
  2. 高可用性:HAProxy 支持对后端服务器的健康检查,可以在检测到某个服务器故障时自动停止向其发送请求。
  3. SSL/TLS 终止:HAProxy 能够处理和终止 SSL/TLS 连接,将加密流量解密后再转发给后端服务器,从而减轻后端服务器的负担。
  4. 内容重写:能够根据请求的内容对请求或响应进行重写,例如修改 URL 或插入 HTTP 头。
  5. HTTP/2 和 WebSocket 支持:支持现代的传输协议和技术,能够处理实时 Web 应用的连接。
  6. 丰富的监控与统计:提供详细的实时监控和日志功能,可以帮助运维人员了解流量情况和系统性能。

使用场景:

  • 网站负载均衡:将来自用户的请求均匀地分配到多台 Web 服务器上。
  • API 网关:在微服务架构中,HAProxy 可以作为 API 网关,管理不同服务之间的流量。
  • 高可用架构:用于确保关键应用和服务的高可用性,防止单点故障。

总结:

HAProxy 是一个灵活、强大且广泛使用的工具,适用于需要高性能、高可靠性的网络架构。其广泛的功能和配置选项,适合从中小型企业到大型互联网公司在内的各种场景。

使用场景

通用配置

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    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

转发tcp流量给后端的Trojan Sever

#配置tcp入站,主要复用443端口
frontend tcp_in
    mode tcp
    bind *:443

    tcp-request inspect-delay 3s
    tcp-request content accept if { req.ssl_hello_type 1 }
   
    # <sni_domin> Trojan sni domain
    acl host_trojan req_ssl_sni -i <sni_domain>

    # 2. tcp 转发后端处理
    use_backend trojan_backend if host_trojan 

# Trojan 后端配置,转发给本地的9000端口
backend trojan_backend
    mode tcp
    server trojan_server 127.0.0.1:9000 check

反代本地web网站并配置https

# http转https
frontend http_in
    mode http
    bind *:80
    http-request redirect scheme https
# 配置http入站
frontend https_in
	## 配置acme.sh申请证书
    # 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

    # 配置日志
    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_domain> Web Sni Doamin
	## hdr(host): 匹配域名
	## hdr_end(host): 匹配子域名
    acl host_web hdr(host) -i <web_domain>
    use_backend nginx_server if host_web

	# 未匹配转发
    default_backend default_backend

# web后端,不传递其他Header信息
backend nginx_server
    mode http
    server nginx_server 127.0.0.1:8443 check

# 默认后端
backend default_backend
    mode http
    http-request deny

利用ssl透传反代其他服务器的web服务

优势在于不用在本机部署ssl证书,会加密转发到后端服务器,劣势是无法修改请求头,各有优势。

# ssl透传需要走tcp协议
frontend tcp_in
    mode tcp
    bind *:443

    tcp-request inspect-delay 3s
    tcp-request content accept if { req.ssl_hello_type 1 }
  
    # 域名匹配规则
    ## 1. ssl透传
	## tcp协议不能用hdr,需要使用req_ssl_sni
	## -i:匹配域名
	## -m sub:匹配子域名和自身
    acl host_app req_ssl_sni -m <backend_web_domain>
  
    # 1. ssl穿透,由后端服务器负责处理ssl,负载均衡服务器只负责加密转发,适合原域名转发的情况
    use_backend forward_backend if host_app

# ssl穿透
backend forward_backend
    mode tcp
    #balance roundrobin
    option ssl-hello-chk
    server blog_server IP:443 weight 1 check inter 2000 rise 2 fall 4

本机终端ssl后转发到后端web服务器

接近cdn的原理,优势和劣势和上面的反过来,需要配置ssl证书,优势在于可以修改请求,并能隐藏后端服务器信息。

# http转https
frontend http_in
    mode http
    bind *:80
    http-request redirect scheme https

# 配置http入站
frontend https_in
	## 配置acme.sh申请证书
    # 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

    # 配置日志
    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_domain> Web Sni Doamin
	## hdr(host): 匹配域名
	## hdr_end(host): 匹配子域名
    acl host_backend_web hdr(host) -i <web_domain>
    use_backend blog_backend if host_backend_web

# 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 <backend_web_domain>
  
    # 转发到远程nginx服务器
    server nginx_server IP:443 ssl check verify none check-sni <backend_web_domain> sni str(<backend_web_domain>) inter 2000 rise 2 fall 4

备忘自己使用的配置

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    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

#配置tcp入站,主要复用443端口
frontend tcp_in
    mode tcp
    bind *:443

    tcp-request inspect-delay 3s
    tcp-request content accept if { req.ssl_hello_type 1 }
  
    # 域名匹配规则
    ## 1. ssl透传
    acl host_app req_ssl_sni -m <backend_web_domain>
    ## 2. 复用443 tcp代理
    acl host_trojan req_ssl_sni -i <trojan_sni_domain>
  
    # 1. ssl穿透,由后端服务器负责处理ssl,负载均衡服务器只负责加密转发,适合原域名转发的情况
    use_backend forward_backend if host_app
    # 2. tcp 转发后端处理
    use_backend trojan_backend if host_trojan 

# 配置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

    # 配置日志
    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 <web_domain>
    use_backend blog_backend if host_blog

    default_backend default_backend

# 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 <backend_web_domain>
  
    # 转发到远程nginx服务器
    server nginx_server IP:443 ssl check verify none check-sni <backend_web_domain> sni str(<backend_web_domain>) inter 2000 rise 2 fall 4

# ssl穿透
backend forward_backend
    mode tcp
    #balance roundrobin
    option ssl-hello-chk
    server blog_server IP:443 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 default_backend
    mode http
    http-request deny

后记

Haproxy做这个事情我觉得比Nginx要好不少,利用SNI分流真好呀。