Hugo博客公告弹窗

haproxy反向代理教程

为什么是使用haproxy作为反代,而不是nginx,或者iptables,就不细说了,因为haproxy更高效简洁,性能更优秀!这是我几个月来的使用和验证。

注意:下面的配置是针对80端口(源站,可以开启cf cdn),但是没有针对https(443),如果有需要可以问ai怎么修改配置文件。

安装haproxy

一键脚本

curl -sS -O https://raw.githubusercontent.com/woniu336/open_shell/main/haproxy-k.sh && chmod +x haproxy-k.sh && ./haproxy-k.sh

安装

apt install haproxy -y
systemctl start haproxy
systemctl enable haproxy

编辑haproxy

nano /etc/haproxy/haproxy.cfg

内容如下

参考:https://github.com/woniu336/open_shell/blob/main/haproxy.cfg

global
    log /dev/log local0 warning
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon
    maxconn 10000
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s

defaults
    log global
    mode http                    # 改为 http 模式
    option dontlognull
    option httplog              # 启用 HTTP 日志
    option http-keep-alive
    option forwardfor           # 传递客户端真实IP
    timeout connect 5s          # 连接超时增加
    timeout client  30s         # 客户端超时增加
    timeout server  30s         # 服务器超时增加
    timeout http-keep-alive 15s
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

frontend http-in
    bind *:80
    # 如果要添加更多域名到 backend1,继续在同一行添加
    acl domain1 hdr(host) -i 123.com 789.com
    acl domain2 hdr(host) -i 456.com
    use_backend backend1 if domain1
    use_backend backend2 if domain2
    # 默认后端
    default_backend backend1

backend backend1
    server server1 8.8.8.8:80 check

backend backend2
    server server2 3.3.3.3:80 check

路由规则

如果要添加更多域名到 backend1,继续在同一行添加:

acl domain1 hdr(host) -i 123.com 789.com example.com

example.com 替换成你实际要添加的域名即可。

根据配置:

123.com (domain1) → backend1 → 8.8.8.8:80

456.com (domain2) → backend2 → 3.3.3.3:80

配置中的对应关系:

acl domain1 hdr(host) -i 123.com

acl domain2 hdr(host) -i 456.com

use_backend backend1 if domain1

use_backend backend2 if domain2

所以:

访问 123.com 的请求会被路由到 backend1(服务器 8.8.8.8:80

访问 456.com 的请求会被路由到 backend2(服务器 3.3.3.3:80

其他未配置的域名或直接IP访问会走默认后端 backend1

启动服务

修改完成后,为了避免格式报错,执行以下命令

echo "" >> /etc/haproxy/haproxy.cfg

验证

haproxy -c -f /etc/haproxy/haproxy.cfg

显示Configuration file is valid 即正确

如果没有错误,重启服务

systemctl restart haproxy

检查状态

systemctl status haproxy

获取客户端ip

既然是路由源站的80端口,那么必然要开启cdn,当然是开启大善人的cdn,

如果不做如下设置会获取不到客户端ip,没法看站点日志,

如果是宝塔面板,建议放在以下位置

mkdir -p /www/server/panel/vhost/nginx/cf_real_ip
nano /www/server/panel/vhost/nginx/cf_real_ip/cloudflare.conf

如果是 amh

mkdir -p /home/wwwroot/lnmp01/vhost/cf_real_ip
nano /home/wwwroot/lnmp01/vhost/cf_real_ip/cloudflare.conf

在 cloudflare.conf 中添加所有 Cloudflare IP

注意:需要额外添加你的 HAProxy 服务器 IP

# Cloudflare IP ranges
# HAProxy IP
set_real_ip_from 你的HAProxy服务器IP;

# Cloudflare IPv4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# Cloudflare IPv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

然后在你的网站配置文件中引用,例如宝塔面板

server
{
    listen 80;
    server_name 123.com;
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/123.com;
    
    
    include /www/server/panel/vhost/nginx/cf_real_ip/cloudflare.conf;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    
    ...

仅添加如下内容

    include /www/server/panel/vhost/nginx/cf_real_ip/cloudflare.conf;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

记得重载nginx

amh面板站点配置

    include /home/wwwroot/lnmp01/vhost/cf_real_ip/cloudflare.conf;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

记得重载nginx

到此就完工了,然后域名解析到反代服务器ip(haproxy),开启cf cdn (灵活模式)

还能正常查看网站日志(在源站查看)

https配置

我建议既然是443端口,那么我们使用另外一台服务器,

对国内用户友好的线路服务器,不和上面的80配置混合在一起,避免混乱。

301可以在源站设置

新建证书目录

mkdir -p /etc/haproxy/certs

重点(源站不需要配置证书)

把域名证书的fullchain.pem和privkey.pem(不一定是这两个名称的证书),合并成一个以域名为名称的.pem文件,例如 123.com.pem

申请证书的方式很多,就不一一细说了。

意思就是把这两个文件里面的内容拷贝到一个文件中,以.pem结尾,把pem证书传到/etc/haproxy/certs目录,

如果有多个域名依次类推,HAProxy会根据客户端的SNI(Server Name Indication)自动选择对应的证书:

  • 访问 123.com → 使用 123.com.pem
  • 访问 456.com → 使用 456.com.pem

配置如下

参考:https://github.com/woniu336/open_shell/blob/main/443_haproxy.cfg

优化版参考(不推荐):https://github.com/woniu336/open_shell/blob/main/443_haproxys.cfg

推荐以下配置

global
    log /dev/log local0 warning
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon
    maxconn 10000
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s

defaults
    log global
    mode http                    # 改为 http 模式
    option dontlognull
    option httplog              # 启用 HTTP 日志
    option http-keep-alive
    option forwardfor           # 传递客户端真实IP
    timeout connect 5s          # 连接超时增加
    timeout client  30s         # 客户端超时增加
    timeout server  30s         # 服务器超时增加
    timeout http-keep-alive 15s
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http


frontend http-in
    bind *:80
    redirect scheme https code 301 # 所有HTTP流量强制跳转HTTPS

frontend https-in
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
	
    # 安全头
    http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
   #http-response set-header X-Frame-Options "SAMEORIGIN"
   #http-response set-header Content-Security-Policy "frame-ancestors 'self'"
    http-response set-header X-Content-Type-Options "nosniff"
    http-response set-header X-XSS-Protection "1; mode=block"
    http-response set-header Referrer-Policy "strict-origin-when-cross-origin"

    # 路由逻辑,如果要添加更多域名到 backend1,继续在同一行添加
	
    acl domain1_https hdr(host) -i 123.com 456.com
	
    use_backend backend1 if domain1_https
	
    # 默认后端
    #default_backend backend1

backend backend1
    server server1 8.8.8.8:80 check inter 10s rise 3 fall 3
	

注意:如果站点有播放器,注释掉以下两项安全头

    http-response set-header X-Frame-Options "SAMEORIGIN"
    http-response set-header Content-Security-Policy "frame-ancestors 'self'"

验证

haproxy -c -f /etc/haproxy/haproxy.cfg

重载服务

systemctl restart haproxy

检查状态

systemctl status haproxy

测试证书是否匹配

for domain in 123.com 456.com; do
    echo "Testing $domain:"
    echo | openssl s_client -connect $domain:443 -servername $domain 2>/dev/null | openssl x509 -noout -subject
    echo "---"
done

获取真实客户端ip,在源站点配置文件添加如下内容

set_real_ip_from 你的反代ip;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

如果是两台服务器做负载均衡,默认轮询模式

frontend https-in
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
    # 安全头配置
    http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    #http-response set-header X-Frame-Options "SAMEORIGIN"
    #http-response set-header Content-Security-Policy "frame-ancestors 'self'"
    http-response set-header X-Content-Type-Options "nosniff"
    http-response set-header X-XSS-Protection "1; mode=block"
    http-response set-header Referrer-Policy "strict-origin-when-cross-origin"
    # 路由规则
    acl domain1_https hdr(host) -i 123.com 456.com 789.com   # 修改,添加了789.com
    use_backend backend1 if domain1_https
    # 默认后端
    default_backend backend1

backend backend1
    server server1 8.8.8.8:80 check inter 10s rise 3 fall 3
    server server2 3.3.3.3:80 check inter 10s rise 3 fall 3   # 将原backend2中的server2移过来

检测

安装socat

sudo apt update
sudo apt install socat

检测

echo "show info" | sudo socat unix-connect:/run/haproxy/admin.sock - | grep -iE 'conn|session'

或者

echo "show info" | socat unix-connect:/run/haproxy/admin.sock stdio

检测ssl会话重用

echo "show info" | socat stdio /run/haproxy/admin.sock | grep -E "(SslFrontendSessionReuse|SslCache|SslFrontendKey)"

根据提供的信息,HAProxy 的状态如下:

  1. Maxconn 和 Hard_maxconn:都是10000,表示配置的最大并发连接数和系统支持的最大连接数上限为10000。
  2. CurrConns:当前活跃连接数为148,远低于最大连接数10000(使用率仅为1.48%)。
  3. CumConns:累计连接数已经达到11850550(约1185万),说明服务已经处理了大量连接。
  4. ConnRate:当前新建连接速率是19个/秒,处于较低水平。
  5. MaxConnRate:历史最大新建连接速率是150个/秒。

分析:

  • 并发连接情况:当前活跃连接数(148)远低于最大连接数(10000),所以没有超出并发限制。
  • 性能状况:系统压力很小,连接率也不高(19/秒),历史最大连接率150/秒也远未达到系统瓶颈(因为最大连接数是10000,即使每个连接持续1秒,理论上也可以支持10000/秒的连接率,但实际上连接持续时间和并发模型会影响实际能力)。

其他设置

通过以下方式来更好地处理默认后端,禁止IP访问和未配置域名的连接

参考:https://github.com/woniu336/open_shell/blob/main/haproxy_config.txt

配置地址:

  1. IP访问检测和拒绝
    • 使用正则表达式检测Host头是否为IP地址格式
    • 直接拒绝IP访问请求
  2. 无Host头检测
    • 检测没有Host头的请求并拒绝
  3. 未配置域名拒绝
    • 创建包含所有允许域名的ACL
    • 拒绝所有不在允许列表中的域名访问
CC BY-NC-SA 4.0 转载请注明
最后更新于 2025-06-04 15:20
clarity统计