haproxy使用小记
使用haproxy可以做到复用网云穿隧道暴露多个内网服务到公网。具体思路为,
- 如果隧道协议为http
- 根据http请求url前缀区分,转发到不同的http server
- 如果隧道协议为tcp,那么可以复用隧道进行ssh协议,http协议传输,二者本质都是tcp协议,在流量层面有所区分。
- 通过匹配流量特征,转发到ssh server或http server
# file: /etc/haproxy/haproxy.cfg
global
maxconn 20000
log 127.0.0.1 local0
user haproxy
chroot /usr/share/haproxy
pidfile /run/haproxy.pid
daemon
defaults
log global
errorfile 400 /etc/haproxy/errorfiles/400.http
errorfile 403 /etc/haproxy/errorfiles/403.http
...
frontend main
bind :5000
mode http
log global
option httplog
option dontlognull
option forwardfor except 127.0.0.0/8
maxconn 8000
timeout client 30s
# see: https://www.haproxy.com/blog/path-based-routing-with-haproxy
acl app-miniserve path -i /miniserve
acl app-miniserve path_beg -i /miniserve/
use_backend miniserv if app-miniserve
default_backend alist
# Proxy for l4-protocol (tcp)
frontend tcp_main
bind :5001 name *:5001
mode tcp
tcp-request inspect-delay 1s
tcp-request content accept if { req_len gt 0 }
log /dev/log local0
option tcplog
timeout client 1h
# 匹配ssh流量
acl is_ssh payload(0,3) -m bin 535348
# 规则1:匹配HTTP/1.0或HTTP/1.1的核心标识(兼容所有请求方法)
# acl is_http_core payload(0,200) -m reg -i ^[a-z]+ .+ HTTP/1\.[01]\r?\n
acl is_http_core payload(0,200) -m reg -i ^[a-z]+ [^\\x0d\\x0a]+ HTTP/1\.[01][\\x0d]?[\\x0a]
# 规则2:兼容HTTP/2(可选,若需支持)
acl is_http2 payload(0,3) -m bin 505249 # PRI 字符的16进制(HTTP/2 初始帧)
# 根据流量转发到不同的后台服务,默认sshd
use_backend ssh if is_ssh
use_backend miniserv-tcp if is_http_core or is_http2
default_backend ssh
# Http service (miniserve)
backend miniserv
#http-request replace-path ^/miniserve(/)?(.*) /\2
mode http
balance roundrobin
timeout connect 5s
timeout server 5s
server static 127.0.0.1:8080 check maxconn 30
# Http service (alist)
backend alist
mode http
balance roundrobin
timeout connect 5s
timeout server 30s
timeout queue 30s
server app1 127.0.0.1:5244 check maxconn 30
### TCP BACKENDS ###
# Tcp service (sshd)
backend ssh
mode tcp
balance roundrobin
option tcp-check
timeout connect 3s
timeout server 1h
server ssh1 127.0.0.1:22 check maxconn 30
# Tcp service (miniserve)
backend miniserv-tcp
mode tcp
balance roundrobin
option tcp-check
timeout server 60s
timeout connect 5s
server miniserv1 127.0.0.1:8080 check maxconn 30
# Tcp service (alist)
backend alist-tcp
mode tcp
balance roundrobin
option tcp-check
timeout server 60s
timeout connect 5s
server alist1 127.0.0.1:5244 check maxconn 30
# Tcp blackhole (reject anything)
backend _deny
mode tcp
tcp-request content reject必须知道的技巧
haproxy -c -f /etc/haproxy/haproxy/cfg:用于快速检验配置文件是否合法haproxy -f haproxy.cfg -Wd:手动运行
日志
haproxy的日志比较特殊,由于安全原因haproxy会在chroot模式下运行,这就导致进程不能直接将日志输出到外部目录。需要一些额外配置,例如将日志输出到rsyslog/systemd-journald.
这里提供一个简单的方法,调整haproxy.service,将日志输出到stdout,
# /usr/lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=network-online.target
Wants=network-online.target
[Service]
EnvironmentFile=-/etc/default/haproxy
EnvironmentFile=-/etc/sysconfig/haproxy
Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" "EXTRAOPTS=-S /run/haproxy-master.sock"
ExecStart=/usr/bin/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS
ExecReload=/usr/bin/haproxy -Ws -f $CONFIG -c $EXTRAOPTS
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
Restart=always
SuccessExitStatus=143
#
Type=notify
#User=haproxy
#Group=haproxy
NoNewPrivileges=true
LimitNOFILE=65535
Restart=on-failure
RestartSec=5s
PrivateTmp=true
#ProtectSystem=strict
#ReadWritePaths=/run/haproxy.pid /run/haproxy-master.sock
#
StandardOutput=journal+console
StandardError=journal+console
SyslogIdentifier=haproxy
# The following lines leverage SystemD's sandboxing options to provide
# defense in depth protection at the expense of restricting some flexibility
# in your setup (e.g. placement of your configuration files) or possibly
# reduced performance. See systemd.service(5) and systemd.exec(5) for further
# information.
# NoNewPrivileges=true
# ProtectHome=true
# If you want to use 'ProtectSystem=strict' you should whitelist the PIDFILE,
# any state files and any other files written using 'ReadWritePaths' or
# 'RuntimeDirectory'.
# ProtectSystem=true
# ProtectKernelTunables=true
# ProtectKernelModules=true
# ProtectControlGroups=true
# If your SystemD version supports them, you can add: @reboot, @swap, @sync
# SystemCallFilter=~@cpu-emulation @keyring @module @obsolete @raw-io
[Install]
WantedBy=multi-user.target配置haproxy.cfg中的日志项,
global
maxconn 20000
log stdout format raw local0 info
user haproxy
chroot /usr/share/haproxy
pidfile /run/haproxy.pid
defaults
log global
option log-separate-errors
frontend main
bind :5000
mode http
log global
option httplog
option dontlognull
option forwardfor except 127.0.0.0/8
frontend tcp_main
bind :5022 name *:5022
mode tcp
tcp-request inspect-delay 1s
tcp-request content accept if { req_len gt 0 }
option tcplog如此一来,就可通过journalctl -fu haproxy查看haproxy的日志。