HAProxy / Keepalived / SSH 运维管理
概述
本文档系统性地介绍 HAProxy 负载均衡、Keepalived 高可用以及 SSH 安全运维管理的核心概念与实战配置,涵盖从基础原理到生产级架构设计的完整内容。
一、HAProxy 核心概念
1.1 HAProxy 简介
HAProxy(High Availability Proxy)是一款开源的 TCP/HTTP 负载均衡器,以其高性能、稳定性和丰富的功能特性被广泛应用于生产环境。它支持四层(TCP)和七层(HTTP)负载均衡,具备连接调度、健康检查、ACL 路由、SSL 终止等能力,单进程即可处理数十万并发连接。
1.2 配置结构
HAProxy 的配置文件通常位于 /etc/haproxy/haproxy.cfg,采用标准化的三段式结构。
global
# 全局配置:进程、日志、性能调优
defaults
# 默认配置:frontend/backend/listen 的默认值
frontend
# 前端:定义监听套接字和请求路由规则
backend
# 后端:定义服务器池和负载均衡策略
listen
# 监听:合并 frontend + backend 的快捷方式配置文件层级:
/etc/haproxy/haproxy.cfg
├── global 层
│ ├── daemon / master-worker # 运行模式
│ ├── maxconn # 最大连接数
│ ├── log / log-send-hostname # 日志配置
│ └── ssl-engine / tune.* # SSL 与调优
├── defaults 层
│ ├── mode # tcp / http / health
│ ├── option # 通用选项(httplog / dontlognull 等)
│ ├── timeout # 各类超时设置
│ └── retries / maxconn # 重试与连接限制
├── frontend 层
│ ├── bind # 监听地址与端口
│ ├── acl # 访问控制列表
│ ├── use_backend / default_backend # 路由规则
│ └── option # 前端特有选项
└── backend 层
├── balance # 负载均衡算法
├── server # 后端服务器定义
└── option # 健康检查等后端选项1.3 ACL(访问控制列表)
ACL 是 HAProxy 七层路由的核心机制,用于根据请求特征匹配规则并执行相应动作。
# ACL 语法:acl <名称> <判据> [-i] <匹配模式> [参数]
# 基于域名的 ACL
acl is_api hdr_dom(host) -i api.example.com
acl is_www hdr_dom(host) -i www.example.com
# 基于路径的 ACL
acl is_rest path_beg /api/v1
acl is_static path_end .jpg .png .css .js
# 基于请求方法的 ACL
acl is_post method POST
acl is_get method GET
# 基于源 IP 的 ACL
acl is_internal src 10.0.0.0/8 172.16.0.0/12
# ACL 条件组合
use_backend bk_api if is_api is_post
use_backend bk_web if is_www
use_backend bk_static if is_static
default_backend bk_defaultACL 判据类型:
| 判据 | 说明 | 示例 |
|---|---|---|
hdr_dom(host) | 匹配 Host 头域名 | hdr_dom(host) -i example.com |
path_beg | 路径前缀匹配 | path_beg /api |
path_end | 路径后缀匹配 | path_end .php .do |
path_reg | 路径正则匹配 | path_reg ^/user/[0-9]+ |
method | HTTP 方法 | method POST |
src | 源 IP 地址 | src 10.0.0.0/8 |
ssl_fc_sni | SSL SNI 值 | ssl_fc_sni -i example.com |
1.4 frontend / backend / server 配置
frontend 配置示例:
frontend fe_web
bind :80
bind :443 ssl crt /etc/haproxy/certs/example.pem
mode http
option httplog
option forwardfor
# 请求速率限制
stick-table type ip size 100k expire 30s store http_req_rate(10s)
acl abuse src_http_req_rate(10s) ge 100
http-request deny if abuse
# ACL 路由
acl is_api path_beg /api
acl is_ws path_beg /ws
use_backend bk_api if is_api
use_backend bk_ws if is_ws
default_backend bk_webbackend 配置示例:
backend bk_web
mode http
balance roundrobin
option httpchk GET /health
http-check expect status 200
timeout connect 5s
timeout server 30s
server web01 10.0.1.10:8080 check weight 10 inter 3s fall 3 rise 2
server web02 10.0.1.11:8080 check weight 10 inter 3s fall 3 rise 2
server web03 10.0.1.12:8080 check backupserver 指令参数说明:
| 参数 | 含义 | 示例 |
|---|---|---|
check | 启用健康检查 | server s1 10.0.1.1:80 check |
weight | 权重(默认 1) | weight 10 |
inter | 健康检查间隔 | inter 3s |
fall | 连续失败次数判定宕机 | fall 3 |
rise | 连续成功次数判定恢复 | rise 2 |
backup | 标记为备用服务器 | check backup |
maxconn | 最大连接数限制 | maxconn 100 |
slowstart | 启动后缓慢增加权重 | slowstart 30s |
cookie | 会话保持 cookie | cookie web01 |
1.5 负载均衡算法
HAProxy 支持多种负载均衡算法,适用于不同的业务场景。
roundrobin(轮询)
默认算法,将请求依次分配给每个服务器,支持权重调节。适合服务器性能相近的场景。
backend bk_roundrobin
balance roundrobin
server s1 10.0.1.1:80 weight 10
server s2 10.0.1.2:80 weight 20 # 获得双倍流量
server s3 10.0.1.3:80 weight 10leastconn(最少连接)
将请求分配给当前活跃连接数最少的服务器,适合长连接场景(如 WebSocket、数据库连接池)。
backend bk_leastconn
balance leastconn
option tcpka
server db1 10.0.1.1:3306 check
server db2 10.0.1.2:3306 checksource(源地址哈希)
对客户端 IP 进行哈希运算,确保同一客户端始终被路由到同一台服务器。适用于需要会话保持且无法使用 cookie 的场景。
backend bk_source
balance source
hash-type consistent # 一致性哈希,减少服务器增减时的 rehash
server cache1 10.0.1.1:8080 check
server cache2 10.0.1.2:8080 checkuri(URI 哈希)
对请求 URI 进行哈希运算,确保同一 URI 始终被路由到同一台服务器,适用于缓存服务器场景。
backend bk_uri
balance uri
hash-type consistent
hash-length 32 # 哈希长度,值越大越均匀
server cache1 10.0.1.1:8080 check
server cache2 10.0.1.2:8080 check算法对比:
| 算法 | 适用场景 | 会话保持 | 特点 |
|---|---|---|---|
| roundrobin | 短连接、HTTP 请求 | 不支持 | 均衡性最好,默认算法 |
| leastconn | 长连接、数据库 | 不支持 | 避免请求堆积 |
| source | 需要 IP 会话保持 | 支持 | 简单会话粘性 |
| uri | 缓存服务器 | 支持(URI 级别) | 提高缓存命中率 |
| first | 按顺序填满服务器 | 不支持 | 适用于少量服务器 |
二、HAProxy 配置详解
2.1 TCP / HTTP 模式配置
TCP 模式(四层代理)
TCP 模式工作在传输层,基于 IP 和端口转发流量,不解析 HTTP 协议。适用于数据库、Redis、MQ 等非 HTTP 协议的负载均衡。
global
daemon
maxconn 50000
defaults
mode tcp
timeout connect 5s
timeout client 60s
timeout server 60s
log global
frontend fe_mysql
bind 0.0.0.0:3306
default_backend bk_mysql
backend bk_mysql
balance leastconn
option tcpka # TCP keepalive
option srvtcpka # 后端 keepalive
server mysql1 10.0.1.10:3306 check inter 5s fall 3 rise 2
server mysql2 10.0.1.11:3306 check inter 5s fall 3 rise 2
frontend fe_redis
bind 0.0.0.0:6379
default_backend bk_redis
backend bk_redis
balance first # Redis 场景适合 first
option tcpka
server redis1 10.0.1.20:6379 check inter 3s
server redis2 10.0.1.21:6379 check inter 3sHTTP 模式(七层代理)
HTTP 模式工作在应用层,可以解析 HTTP 请求头、Cookie、URI 等,实现精细化的流量调度。
frontend fe_http
bind :80
bind :443 ssl crt /etc/haproxy/certs/example.com.pem
mode http
option httplog
option forwardfor header X-Real-IP
option http-keep-alive
# HTTP 请求头重写
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-Forwarded-Port %[dst_port]
# 安全头部
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains"
http-response set-header X-Content-Type-Options nosniff
http-response set-header X-Frame-Options DENY
http-response set-header X-XSS-Protection "1; mode=block"
default_backend bk_http2.2 健康检查
HAProxy 通过健康检查自动检测后端服务器的可用性,剔除故障节点并在恢复后重新加入。
TCP 健康检查(默认)
backend bk_tcp_check
# 默认 TCP 连接检查
server s1 10.0.1.1:80 check
# 自定义检查参数
server s2 10.0.1.2:80 check inter 2s fall 4 rise 3HTTP 健康检查
backend bk_http_check
mode http
balance roundrobin
# 基础 HTTP 健康检查
option httpchk GET /health
# 高级 HTTP 健康检查
option httpchk GET /health HTTP/1.1\r\nHost:\ example.com
http-check expect status 200
http-check expect string "OK"
http-check expect rstring ^(UP|OK)$
server web1 10.0.1.1:80 check inter 3s fall 3 rise 2
server web2 10.0.1.2:80 check inter 3s fall 3 rise 2健康检查参数详解:
server web01 10.0.1.10:8080 check \
inter 3s # 检查间隔(默认 2s)
fastinter 1s # 故障状态下的快速检查间隔
downinter 5s # 确认宕机后的检查间隔
fall 3 # 连续失败次数判定宕机(默认 3)
rise 2 # 连续成功次数判定恢复(默认 2)
addr 10.0.0.10 # 检查使用的源地址
port 8080 # 检查使用的端口2.3 SSL 终止
HAProxy 可以直接处理 SSL/TLS 加密和卸载,将解密后的明文流量转发给后端服务器。
SSL 证书配置:
global
# SSL 相关配置
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-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11
tune.ssl.default-dh-param 2048
frontend fe_ssl
bind :443 ssl crt /etc/haproxy/certs/example.com.pem
bind :443 ssl crt /etc/haproxy/certs/ # 多证书目录
mode http
# 根据 SNI 选择证书
acl is_www ssl_fc_sni -i www.example.com
acl is_api ssl_fc_sni -i api.example.com
use_backend bk_www if is_www
use_backend bk_api if is_api
# HTTP 重定向到 HTTPS
http-request redirect scheme https code 301 if !{ ssl_fc }
backend bk_ssl_backend
mode http
# 后端是否使用 SSL(HAProxy 到后端也加密)
server app1 10.0.1.10:443 ssl verify none check inter 3s
server app2 10.0.1.11:443 ssl verify required ca-file /etc/haproxy/certs/ca.pem check inter 3s证书管理:
# 创建 PEM 格式证书(HAProxy 要求证书和私钥在同一个 PEM 文件中)
cat example.com.crt example.com.key > /etc/haproxy/certs/example.com.pem
# 验证证书配置
haproxy -c -f /etc/haproxy/haproxy.cfg2.4 统计页面
HAProxy 内置的统计页面提供了实时的运行状态监控能力。
frontend fe_stats
bind :8404
mode http
stats enable
stats uri /haproxy-stats
stats refresh 10s
stats admin if LOCALHOST
# 认证保护
stats auth admin:StrongPassword123
stats realm "HAProxy Statistics"
# 隐藏版本信息
stats hide-version
# 仅允许内网访问
acl trusted_net src 10.0.0.0/8 172.16.0.0/12
http-request deny unless trusted_net统计页面关键指标说明:
| 指标 | 含义 |
|---|---|
Session Rate | 每秒新建会话数 |
Sessions Total | 累计总会话数 |
Sessions Current | 当前活跃会话数 |
Bytes In/Out | 流量统计 |
Denied | 被拒绝的请求数 |
Errors | 错误请求数 |
Server Status | UP/DOWN/NOLB/MAINT |
Last Health Check | 最后一次健康检查结果 |
2.5 日志配置
HAProxy 的日志功能提供了丰富的连接和请求信息,对故障排查至关重要。
global
# syslog 配置(将日志发送到本地或远程 syslog 服务器)
log 127.0.0.1:514 local0 info
log 10.0.0.100:514 local1 warning
log-send-hostname
defaults
log global
option httplog # HTTP 模式日志(推荐)
option tcplog # TCP 模式日志
option dontlognull # 不记录无数据连接
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"
frontend fe_web
mode http
option httplog
# 自定义日志格式
capture request header Host len 32
capture request header User-Agent len 128
capture response header Content-Type len 32日志格式说明(httplog):
示例行:
10.0.1.5:54321 [09/Jul/2026:10:30:25.123] fe_web bk_web/srv01 10/0/5/12/27 2048 200 - - --VN 1/1/0/0/0 0/0 "GET /api/health HTTP/1.1"
字段解析:
- 10.0.1.5:54321 客户端 IP 和端口
- [09/Jul/2026...] 请求时间
- fe_web 前端名称
- bk_web/srv01 后端名称/服务器名称
- 10/0/5/12/27 各项耗时(ms):Tq/Tw/Tc/Tr/Tt
- 2048 响应体大小(bytes)
- 200 HTTP 状态码
- --VN 各类标志位
- "GET /api/health" 请求行2.6 完整反向代理示例
以下是一个面向生产环境的完整 HAProxy 反向代理配置。
global
daemon
master-worker
maxconn 100000
stats socket /var/run/haproxy.sock mode 600 level admin
stats timeout 30s
user haproxy
group haproxy
# 日志
log /dev/log local0 info
log /dev/log local1 warning
# SSL 全局设置
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-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
tune.ssl.default-dh-param 2048
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.1
option redispatch
retries 3
timeout http-request 10s
timeout queue 30s
timeout connect 5s
timeout client 30s
timeout server 30s
timeout http-keep-alive 10s
timeout check 5s
maxconn 50000
# ---- 统计页面 ----
frontend fe_stats
bind 127.0.0.1:8404
mode http
stats enable
stats uri /stats
stats refresh 5s
stats auth admin:changeme
# ---- Web 服务 ----
frontend fe_web
bind :80
bind :443 ssl crt /etc/haproxy/certs/example.com.pem
redirect scheme https code 301 if !{ ssl_fc }
# 安全头部
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains"
http-response set-header X-Content-Type-Options nosniff
http-response set-header X-Frame-Options SAMEORIGIN
# ACL 路由
acl is_api path_beg /api
acl is_ws path_beg /ws
acl is_static path_end .jpg .png .css .js .ico .svg
acl is_admin path_beg /admin
use_backend bk_api if is_api
use_backend bk_ws if is_ws
use_backend bk_static if is_static
use_backend bk_admin if is_admin
default_backend bk_web
backend bk_web
balance roundrobin
option httpchk GET /health
http-check expect status 200
cookie SERVERID insert indirect nocache
server web01 10.0.1.10:8080 check cookie w1 inter 3s fall 3 rise 2
server web02 10.0.1.11:8080 check cookie w2 inter 3s fall 3 rise 2
server web03 10.0.1.12:8080 check cookie w3 inter 3s fall 3 rise 2
backend bk_api
balance leastconn
option httpchk GET /api/health
http-check expect string "OK"
timeout server 60s
server api01 10.0.1.20:8080 check inter 3s fall 3 rise 2
server api02 10.0.1.21:8080 check inter 3s fall 3 rise 2
backend bk_ws
balance leastconn
option http-server-close
timeout server 3600s
timeout tunnel 3600s
server ws01 10.0.1.30:8080 check
server ws02 10.0.1.31:8080 check
backend bk_static
balance source
option httpchk GET /health
server static01 10.0.1.40:80 check
server static02 10.0.1.41:80 check
backend bk_admin
balance roundrobin
option httpchk GET /admin/health
acl trusted_ip src 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
http-request deny if !trusted_ip
server admin01 10.0.1.50:8080 check
server admin01 10.0.1.51:8080 check
# ---- TCP 代理(MySQL) ----
listen mysql_proxy
bind 10.0.0.10:3306
mode tcp
balance leastconn
option tcpka
timeout client 86400s
timeout server 86400s
server db1 10.0.1.100:3306 check inter 5s fall 3 rise 2
server db2 10.0.1.101:3306 check inter 5s fall 3 rise 2三、Keepalived
3.1 VRRP 协议原理
VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)是一种用于实现网关高可用的标准协议。Keepalived 是基于 VRRP 实现的高可用解决方案。
VRRP 核心概念:
- Virtual Router(虚拟路由器):由一组物理路由器组成的逻辑路由器,拥有唯一的 Virtual Router ID(VRID)和 Virtual IP(VIP)。
- Master(主节点):负责转发数据包的路由器,主动发送 VRRP 通告报文(Advertisement)。
- Backup(备节点):监控 Master 状态,在 Master 故障时接管 VIP。
- Priority(优先级):决定选举结果的数值(0-255,数值越大优先级越高)。
- VRID:同一虚拟路由器的标识符,范围 1-255。
VRRP 工作原理:
1. 选举阶段:
- 启动时,路由器根据优先级选举 Master
- 优先级最高的路由器成为 Master
- Master 定期发送 VRRP 通告(默认 1 秒间隔)
2. 故障检测阶段:
- Backup 监听 Master 的通告报文
- 若连续 3 个通告周期未收到 Master 报文(Master_Down_Interval = 3 × Advertisement_Interval)
- Backup 认为 Master 故障,触发重新选举
3. 切换阶段:
- 剩余 Backup 中优先级最高的切换为新的 Master
- 新 Master 通过免费 ARP(Gratuitous ARP)通告 VIP 的 MAC 地址
- 网络交换机更新 MAC 表,流量切换到新节点优先级抢占:
# 默认开启抢占模式(preempt)
# Master 恢复后重新抢占 VIP
vrrp_instance VI_1 {
state BACKUP
priority 100
preempt # 开启抢占(默认)
# nopreempt # 禁止抢占,防止频繁切换
}3.2 VRRP 实例配置
基本 VRRP 实例:
global_defs {
router_id LVS_MASTER # 路由器标识
enable_script_security # 脚本安全模式
}
vrrp_instance VI_1 {
state MASTER # 初始状态(MASTER / BACKUP)
interface eth0 # 绑定的物理网卡
virtual_router_id 51 # VRID(同一组必须一致)
priority 100 # 优先级(MASTER 通常高于 BACKUP)
advert_int 1 # 通告间隔(秒)
# 认证(可选,同一组必须一致)
authentication {
auth_type PASS
auth_pass 8characters # 密码长度不超过 8 位
}
# 虚拟 IP 地址(VIP)
virtual_ipaddress {
10.0.0.100/24 dev eth0 label eth0:vip
192.168.1.100/24 dev eth1
}
# 非抢占模式
nopreempt
# 通告延迟
delay_loop 5
# 追踪脚本
track_script {
chk_haproxy
}
}多实例配置:
# 同一台机器可以运行多个 VRRP 实例
# 实例 1:内网 VIP
vrrp_instance VI_INTERNAL {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
virtual_ipaddress {
10.0.0.100/24
}
}
# 实例 2:外网 VIP
vrrp_instance VI_EXTERNAL {
state BACKUP
interface eth1
virtual_router_id 52
priority 90
advert_int 1
virtual_ipaddress {
203.0.113.100/24
}
}3.3 VRRP Script(健康检查脚本)
vrrp_script 用于监控进程状态,根据监控结果动态调整优先级,实现故障自动切换。
# 定义监控脚本
vrrp_script chk_haproxy {
script "/usr/local/bin/check_haproxy.sh"
interval 2 # 执行间隔(秒)
timeout 5 # 超时时间
weight -20 # 脚本失败时优先级减 20
rise 2 # 连续成功 2 次标记为正常
fall 3 # 连续失败 3 次标记为异常
}
# 在实例中引用
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
virtual_ipaddress {
10.0.0.100/24
}
track_script {
chk_haproxy
}
}HAProxy 健康检查脚本示例:
#!/bin/bash
# /usr/local/bin/check_haproxy.sh
# 方案一:检查进程是否存在
if pgrep -x haproxy > /dev/null 2>&1; then
exit 0
fi
# 方案二:通过 socket 检查状态
# if echo "show info" | socat stdio /var/run/haproxy.sock | grep -q "Process name: haproxy"; then
# exit 0
# fi
# 方案三:HTTP 探测本地统计页面
# if curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8404/stats | grep -q 200; then
# exit 0
# fi
exit 13.4 Keepalived + HAProxy 高可用配置
以两台节点为例,实现 HAProxy 的高可用。
节点 1(haproxy01,初始 Master):
! /etc/keepalived/keepalived.conf
global_defs {
router_id haproxy01
enable_script_security
}
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
timeout 5
weight -20
rise 2
fall 3
}
vrrp_instance VI_WEB {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass haproxyVIP
}
virtual_ipaddress {
10.0.0.100/24
}
track_script {
chk_haproxy
}
}节点 2(haproxy02,初始 Backup):
! /etc/keepalived/keepalived.conf
global_defs {
router_id haproxy02
enable_script_security
}
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
timeout 5
weight -20
rise 2
fall 3
}
vrrp_instance VI_WEB {
state BACKUP
interface eth0
virtual_router_id 51
priority 90 # 优先级低于 Master
advert_int 1
authentication {
auth_type PASS
auth_pass haproxyVIP
}
virtual_ipaddress {
10.0.0.100/24
}
track_script {
chk_haproxy
}
}主备切换流程:
正常状态:
VIP: 10.0.0.100 -> haproxy01 (Master)
|
+-----+------+
| |
haproxy01 haproxy02
(Master) (Backup)
Priority:100 Priority:90
故障场景 1:haproxy01 HAProxy 进程宕机
1. vrrp_script 检测到 HAProxy 异常,priority 降为 80
2. haproxy02 优先级(90)高于 haproxy01(80)
3. haproxy02 接管 VIP,切换为 Master
4. 发送免费 ARP 更新交换机 MAC 表
恢复场景:
1. haproxy01 HAProxy 进程恢复
2. vrrp_script 检测正常,priority 恢复为 100
3. 抢占模式下,haproxy01 重新夺回 VIP
4. 再次发送免费 ARP 更新交换机 MAC 表四、SSH 运维管理
4.1 SSH 基础配置
SSH 客户端配置文件 ~/.ssh/config 支持灵活的主机别名和参数配置,大幅提升日常运维效率。
# 基础配置
Host *
ServerAliveInterval 60 # 心跳间隔(秒)
ServerAliveCountMax 5 # 心跳超时次数
StrictHostKeyChecking ask # 主机密钥检查策略
UserKnownHostsFile ~/.ssh/known_hosts
Compression yes # 启用压缩
# 运维跳板机
Host bastion
HostName jump.example.com
User opsadmin
Port 2222
IdentityFile ~/.ssh/id_ed25519-bastion
ForwardAgent yes
# 内网服务器(通过跳板机访问)
Host web-*
ProxyJump bastion
User deploy
IdentityFile ~/.ssh/id_ed25519-internal
StrictHostKeyChecking accept-new
# 生产环境服务器
Host prod-web-*
HostName %h.internal.example.com
ProxyCommand ssh -W %h:%p bastion
User produser
IdentityFile ~/.ssh/id_ed25519-prod
LogLevel ERROR4.2 跳板机配置
跳板机(Bastion / Jump Server)是 SSH 运维的基础安全架构,所有对内网的访问必须经过跳板机。
ProxyJump(推荐,OpenSSH 7.3+):
# 命令行使用
ssh -J opsadmin@jump.example.com:2222 deploy@10.0.1.10
# 在 ~/.ssh/config 中配置(见上)
ssh web-01 # 自动使用跳板机连接到内网 web-01ProxyCommand(兼容旧版本):
# 通过跳板机建立 SSH 连接
ssh -o ProxyCommand="ssh -W %h:%p -p 2222 opsadmin@jump.example.com" deploy@10.0.1.10
# 多级跳板机(链式代理)
ssh -o ProxyCommand="ssh -W %h:%p bastion1" -o ProxyCommand="ssh -W %h:%p bastion2" target-host
# ~/.ssh/config 配置方式
Host 10.0.*.*
ProxyCommand ssh -W %h:%p jump.example.com跳板机安全加固:
# 跳板机 /etc/ssh/sshd_config 关键配置
# 仅允许密钥登录
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
# 限制来源 IP
AllowUsers opsadmin@10.0.0.0/8 opsadmin@203.0.113.0/24
# 启用审计日志
LogLevel VERBOSE
# 限制 SSH 转发
AllowAgentForwarding yes # 代理转发需用于跳板场景
AllowTcpForwarding yes # TCP 转发
GatewayPorts no # 不允许远程绑定
# 空闲超时断开
ClientAliveInterval 300
ClientAliveCountMax 24.3 SSH 端口转发
SSH 端口转发(隧道)技术是穿透防火墙、安全访问内网服务的核心手段。
本地端口转发(Local Forwarding):
将本地端口流量通过 SSH 隧道转发到远程目标服务器。
# 将本地 3306 端口转发到远程内网数据库 10.0.1.100:3306
ssh -L 3306:10.0.1.100:3306 opsadmin@jump.example.com
# 多端口转发
ssh -L 3306:db.internal:3306 \
-L 6379:redis.internal:6379 \
-L 8080:web.internal:8080 \
opsadmin@jump.example.com
# 绑定到特定本地地址(允许局域网其他机器使用)
ssh -L 0.0.0.0:3306:10.0.1.100:3306 opsadmin@jump.example.com远程端口转发(Remote Forwarding):
将远程服务器端口转发到本地,适用于内网服务对外暴露或反向连接场景。
# 将远程服务器的 8080 端口映射到本地 80 端口
ssh -R 8080:localhost:80 opsadmin@public-server.com
# 多远程端口转发
ssh -R 9090:localhost:9090 \
-R 9091:localhost:9091 \
opsadmin@public-server.com动态端口转发(Dynamic Forwarding / SOCKS 代理):
创建 SOCKS5 代理,通过 SSH 隧道转发任意端口的流量。
# 在本地启动 SOCKS5 代理(默认 1080 端口)
ssh -D 1080 opsadmin@jump.example.com
# 指定监听地址和端口
ssh -D 0.0.0.0:9090 opsadmin@jump.example.com
# 使用 SOCKS 代理(curl 或浏览器配置)
curl -x socks5://127.0.0.1:1080 http://internal-service端口转发对比:
| 类型 | SSH 参数 | 方向 | 典型场景 |
|---|---|---|---|
| 本地转发 | -L | 本地 -> 远端 | 访问内网数据库 |
| 远程转发 | -R | 远端 -> 本地 | 暴露内网服务 |
| 动态转发 | -D | SOCKS 代理 | 浏览器代理访问内网 |
4.4 SSH 隧道实现数据库连接
通过 SSH 隧道安全连接内网数据库,避免直接暴露数据库端口。
方法一:命令行建立隧道
# 建立 SSH 隧道,将本地 3307 端口映射到内网 MySQL 3306
ssh -N -L 3307:10.0.1.100:3306 opsadmin@jump.example.com &
# 本地连接数据库(通过隧道)
mysql -h 127.0.0.1 -P 3307 -u appuser -p
# -N 参数表示不执行远程命令,仅建立隧道
# -f 参数表示后台运行
ssh -f -N -L 3307:10.0.1.100:3306 opsadmin@jump.example.com方法二:使用 autossh 保持隧道稳定
# autossh 自动重连断开的 SSH 隧道
autossh -M 0 -f -N \
-o "ServerAliveInterval=30" \
-o "ServerAliveCountMax=3" \
-L 3307:10.0.1.100:3306 \
opsadmin@jump.example.com方法三:systemd 管理隧道
# /etc/systemd/system/mysql-tunnel.service
[Unit]
Description=SSH tunnel for MySQL
After=network.target
[Service]
Type=simple
User=tunnel
ExecStart=/usr/bin/ssh -N -L 3307:10.0.1.100:3306 opsadmin@jump.example.com
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target# 启用并启动隧道服务
systemctl enable mysql-tunnel.service
systemctl start mysql-tunnel.service
systemctl status mysql-tunnel.service多数据库隧道示例:
# 连接多个数据库实例
ssh -f -N \
-L 3307:db-master.internal:3306 \
-L 3308:db-slave-01.internal:3306 \
-L 3309:db-slave-02.internal:3306 \
opsadmin@jump.example.com
# 连接多种数据服务
ssh -f -N \
-L 3307:mysql.internal:3306 \
-L 6379:redis.internal:6379 \
-L 5432:pgsql.internal:5432 \
opsadmin@jump.example.com4.5 SSH 安全加固完整清单
以下清单覆盖服务器端和客户端的安全配置最佳实践。
服务器端配置(/etc/ssh/sshd_config):
# 1. 协议版本
Protocol 2 # 仅允许 SSHv2
# 2. 端口修改(减少扫描攻击)
Port 2222 # 不使用默认 22 端口
# 3. 认证控制
PasswordAuthentication no # 禁止密码登录
PubkeyAuthentication yes # 启用密钥登录
AuthenticationMethods publickey # 仅允许密钥认证
ChallengeResponseAuthentication no # 关闭挑战响应认证
KerberosAuthentication no # 关闭 Kerberos
GSSAPIAuthentication no # 关闭 GSSAPI
UsePAM no # 关闭 PAM(若不需要)
# 4. 密钥类型限制
PubkeyAcceptedKeyTypes +ssh-ed25519,ssh-rsa
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# 5. 用户访问控制
PermitRootLogin prohibit-password # 禁止 root 密码登录
AllowUsers opsadmin deploy # 仅允许特定用户
DenyUsers root # 拒绝 root 直接登录
AllowGroups ssh-users # 仅允许特定组
# 6. 连接控制
MaxAuthTries 3 # 最大认证尝试次数
MaxSessions 10 # 最大会话数
MaxStartups 10:30:60 # 并发连接限制
LoginGraceTime 60 # 登录超时(秒)
# 7. 空闲超时
ClientAliveInterval 300 # 心跳间隔(秒)
ClientAliveCountMax 3 # 超时次数
# 8. 转发控制
AllowAgentForwarding yes # 按需开启
AllowTcpForwarding yes # 按需开启
GatewayPorts no # 禁止远程绑定
# 9. 日志审计
LogLevel VERBOSE # 详细日志
SyslogFacility AUTH # 日志设备
# 10. TCP 转发
X11Forwarding no # 禁止 X11 转发
PermitTunnel no # 禁止隧道设备
# 11. 加密算法限制(仅允许强加密)
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
KexAlgorithms curve25519-sha256,diffie-hellman-group-exchange-sha256
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com客户端配置(~/.ssh/config):
Host *
Protocol 2
ServerAliveInterval 60
ServerAliveCountMax 5
StrictHostKeyChecking ask
UserKnownHostsFile ~/.ssh/known_hosts
HashKnownHosts yes
Compression yes
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
KexAlgorithms curve25519-sha256,diffie-hellman-group-exchange-sha256
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes # 仅使用指定的密钥日常安全检查命令:
# 查看 SSH 登录日志
journalctl -u sshd -n 50 --no-pager
tail -f /var/log/auth.log | grep sshd
# 检查当前 SSH 连接
ss -tnp | grep :2222
lsof -i :2222
# 审计失败的登录尝试
grep "Failed password" /var/log/auth.log | wc -l
grep "Invalid user" /var/log/auth.log | awk '{print $8}' | sort | uniq -c | sort -rn
# 测试 SSH 配置正确性
sshd -t五、HAProxy + Keepalived 双主高可用架构
5.1 架构设计
双主高可用架构在两台 HAProxy 节点上分别运行独立的 VRRP 实例,各自拥有一个 VIP。流量被智能 DNS 或上游负载均衡器分发到两个 VIP,实现负载分担和冗余容灾。
架构拓扑:
Internet / 外部流量
|
+----------+----------+
| |
VIP1: 10.0.0.100 VIP2: 10.0.0.101
| |
+----+----+ +----+----+
| haproxy01 | | haproxy02 |
| Master | | Master |
| (VI_WEB1) | | (VI_WEB2) |
+----+----+ +----+----+
| \ / |
| \ / |
+-----+------+----+------+-----+
| | | | | |
web01 web02 api01 api02 db1 db2
10.0.1.10 10.0.1.11 10.0.1.20 10.0.1.21 10.0.1.100 10.0.1.101设计要点:
- haproxy01 对 VI_WEB1(VIP1)是 Master,对 VI_WEB2(VIP2)是 Backup
- haproxy02 对 VI_WEB1(VIP1)是 Backup,对 VI_WEB2(VIP2)是 Master
- 正常情况下两台节点各承担一半流量
- 任意一台节点故障,VIP 全部转移到健康节点
5.2 配置实现
节点 haproxy01 配置:
! /etc/keepalived/keepalived.conf
global_defs {
router_id haproxy01
enable_script_security
}
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
timeout 5
weight -30
rise 2
fall 3
}
# VIP1:haproxy01 是 Master
vrrp_instance VI_WEB1 {
state MASTER
interface eth0
virtual_router_id 51
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass haproxyVIP
}
virtual_ipaddress {
10.0.0.100/24 dev eth0 label eth0:vip1
}
track_script {
chk_haproxy
}
}
# VIP2:haproxy01 是 Backup
vrrp_instance VI_WEB2 {
state BACKUP
interface eth0
virtual_router_id 52
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass haproxyVIP
}
virtual_ipaddress {
10.0.0.101/24 dev eth0 label eth0:vip2
}
track_script {
chk_haproxy
}
}节点 haproxy02 配置:
! /etc/keepalived/keepalived.conf
global_defs {
router_id haproxy02
enable_script_security
}
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
timeout 5
weight -30
rise 2
fall 3
}
# VIP1:haproxy02 是 Backup
vrrp_instance VI_WEB1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass haproxyVIP
}
virtual_ipaddress {
10.0.0.100/24 dev eth0 label eth0:vip1
}
track_script {
chk_haproxy
}
}
# VIP2:haproxy02 是 Master
vrrp_instance VI_WEB2 {
state MASTER
interface eth0
virtual_router_id 52
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass haproxyVIP
}
virtual_ipaddress {
10.0.0.101/24 dev eth0 label eth0:vip2
}
track_script {
chk_haproxy
}
}HAProxy 配置(两台节点相同):
global
daemon
master-worker
maxconn 100000
stats socket /var/run/haproxy.sock mode 600 level admin
user haproxy
group haproxy
log /dev/log local0 info
log /dev/log local1 warning
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.1
option redispatch
retries 3
timeout http-request 10s
timeout queue 30s
timeout connect 5s
timeout client 30s
timeout server 30s
timeout http-keep-alive 10s
timeout check 5s
frontend fe_web
bind :80
bind :443 ssl crt /etc/haproxy/certs/example.com.pem
mode http
option httplog
# HTTP -> HTTPS 重定向
http-request redirect scheme https code 301 if !{ ssl_fc }
# ACL 路由
acl is_api path_beg /api
acl is_ws path_beg /ws
acl is_static path_end .jpg .png .css .js .ico .svg
use_backend bk_api if is_api
use_backend bk_ws if is_ws
use_backend bk_static if is_static
default_backend bk_web
# 响应安全头
http-response set-header Strict-Transport-Security "max-age=31536000"
http-response set-header X-Content-Type-Options nosniff
http-response set-header X-Frame-Options SAMEORIGIN
# 连接数限制
stick-table type ip size 100k expire 30s store conn_cur,conn_rate(3s)
acl conn_limit src_conn_cur ge 200
acl conn_rate src_conn_rate(3s) ge 500
http-request deny if conn_limit
http-request deny if conn_rate
# 统计页面
stats enable
stats uri /haproxy-stats
stats auth admin:changeme
stats refresh 5s
backend bk_web
balance roundrobin
option httpchk GET /health
http-check expect status 200
cookie SERVERID insert indirect nocache
server web01 10.0.1.10:8080 check cookie w1 inter 3s fall 3 rise 2
server web02 10.0.1.11:8080 check cookie w2 inter 3s fall 3 rise 2
server web03 10.0.1.12:8080 check cookie w3 inter 3s fall 3 rise 2
backend bk_api
balance leastconn
option httpchk GET /api/health
http-check expect string "OK"
timeout server 60s
server api01 10.0.1.20:8080 check inter 3s fall 3 rise 2
server api02 10.0.1.21:8080 check inter 3s fall 3 rise 2
backend bk_ws
balance leastconn
timeout server 3600s
timeout tunnel 3600s
server ws01 10.0.1.30:8080 check
server ws02 10.0.1.31:8080 check
backend bk_static
balance source
hash-type consistent
server static01 10.0.1.40:80 check
server static02 10.0.1.41:80 check5.3 故障切换与恢复
正常状态(双主运行):
haproxy01 (Master for VIP1, Backup for VIP2):
- 持有 VIP1: 10.0.0.100
- 处理约 50% 流量
haproxy02 (Master for VIP2, Backup for VIP1):
- 持有 VIP2: 10.0.0.101
- 处理约 50% 流量故障状态(haproxy01 HAProxy 宕机):
haproxy01 forward:
1. chk_haproxy 检测失败
2. VI_WEB1 priority: 110 -> 80
3. VI_WEB2 priority: 90 -> 60
4. 释放 VIP1
haproxy02 forward:
1. VI_WEB1 Master 选举:haproxy02(90) > haproxy01(80)
2. VI_WEB2 保持:haproxy02(110) > haproxy01(60)
3. haproxy02 接管 VIP1 和 VIP2
4. 两台节点全部流量由 haproxy02 承担恢复状态(haproxy01 HAProxy 恢复):
haproxy01 forward:
1. chk_haproxy 检测正常
2. VI_WEB1 priority: 80 -> 110
3. VI_WEB2 priority: 60 -> 90
4. haproxy01 重新夺回 VIP1
5. haproxy02 释放 VIP1,仅持有 VIP2
6. 恢复双主均衡状态5.4 部署与验证
安装步骤:
# 两台节点都执行
# 安装 HAProxy
apt-get install -y haproxy # Debian/Ubuntu
# yum install -y haproxy # CentOS/RHEL
# 安装 Keepalived
apt-get install -y keepalived # Debian/Ubuntu
# yum install -y keepalived # CentOS/RHEL
# 安装 socat(用于 HAProxy socket 管理)
apt-get install -y socat
# 创建配置目录
mkdir -p /etc/haproxy/certs
mkdir -p /etc/keepalived启用 IP 转发:
# 开启内核 IP 转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
# 允许非本地 IP 绑定(Keepalived VIP 需要)
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
sysctl -p启动服务:
# 启动 HAProxy
systemctl enable haproxy
systemctl start haproxy
systemctl status haproxy
# 验证 HAProxy 配置
haproxy -c -f /etc/haproxy/haproxy.cfg
# 启动 Keepalived
systemctl enable keepalived
systemctl start keepalived
systemctl status keepalived验证高可用:
# 1. 验证 VIP 是否正常绑定
ip addr show eth0 | grep "10.0.0."
# 预期:haproxy01 应显示 10.0.0.100,haproxy02 应显示 10.0.0.101
# 2. 验证 VRRP 状态
journalctl -u keepalived -n 20 --no-pager
# 预期应看到 "VI_WEB1: Entering MASTER/BACKUP state"
# 3. 验证 HAProxy 统计页面
curl -u admin:changeme http://10.0.0.100/haproxy-stats
# 4. 验证健康检查
# 查看后端服务器状态
echo "show stat" | socat stdio /var/run/haproxy.sock | cut -d, -f1,2,18,19
# 5. 故障切换测试(在 haproxy01 执行)
systemctl stop haproxy
# 验证 VIP 是否转移到 haproxy02
# 在 haproxy02 执行:
ip addr show eth0 | grep "10.0.0." # 应看到两个 VIP
# 6. 恢复测试(在 haproxy01 执行)
systemctl start haproxy
# 验证 VIP 是否回到 haproxy01
ip addr show eth0 | grep "10.0.0." # 应看到 10.0.0.1005.5 运维管理常用命令
HAProxy 管理:
# 配置检查
haproxy -c -f /etc/haproxy/haproxy.cfg
# 平滑重载(不影响现有连接)
haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
# 或使用 systemd
systemctl reload haproxy
# 通过 socket 动态管理
echo "show info" | socat stdio /var/run/haproxy.sock
echo "show stat" | socat stdio /var/run/haproxy.sock
echo "show servers state" | socat stdio /var/run/haproxy.sock
# 动态禁用/启用服务器
echo "disable server bk_web/web01" | socat stdio /var/run/haproxy.sock
echo "enable server bk_web/web01" | socat stdio /var/run/haproxy.sock
# 设置服务器权重(动态调整流量)
echo "set weight bk_web/web01 5" | socat stdio /var/run/haproxy.sock
echo "set weight bk_web/web02 15" | socat stdio /var/run/haproxy.sock
# 查看连接数
echo "show sess rate" | socat stdio /var/run/haproxy.sockKeepalived 管理:
# 查看 Keepalived 进程状态
systemctl status keepalived
# 查看 VRRP 日志
journalctl -u keepalived -f
# 查看 VIP 状态
ip addr show | grep "vip"
# 强制切换主备(降低本机优先级)
# 方法一:暂停健康检查脚本
mv /etc/keepalived/check_haproxy.sh /etc/keepalived/check_haproxy.sh.bak
# 等待 2 个检查周期后 VIP 会切换到另一个节点
# 方法二:停止 Keepalived 服务
systemctl stop keepalived
# 查看 VRRP 报文统计
tcpdump -i eth0 vrrp -n -c 10