05 - 反向代理
第五章:反向代理
5.1 反向代理概述
反向代理(Reverse Proxy)代表后端服务器接收客户端请求,提供缓存加速、负载均衡和安全防护等功能。客户端无感知代理的存在。
┌─────────────────────┐
[互联网用户] ──────→│ Squid 反向代理 │
│ • 缓存静态内容 │
[搜索引擎爬虫] ────→│ • SSL 卸载 │
│ • 负载均衡 │────→ [Web Server 1]
[移动端用户] ──────→│ • 安全过滤 │────→ [Web Server 2]
│ • 压缩传输 │────→ [Web Server 3]
└─────────────────────┘
5.2 基础反向代理配置
5.2.1 单后端服务器
# Squid 反向代理 — 单后端
http_port 80
https_port 443 cert=/etc/squid/ssl/site.pem key=/etc/squid/ssl/site.key
# 定义后端服务器
cache_peer webserver.local parent 80 0 \
no-query originserver \
name=backend
# 访问控制
acl all src all
http_access allow all
# 反向代理头
request_header_add X-Real-IP "%>a" all
request_header_add X-Forwarded-For "%>a" all
request_header_add X-Forwarded-Proto "%>PROTO" all
# 缓存策略
cache_dir ufs /var/spool/squid 5000 16 256
# 隐藏后端信息
via off
forwarded_for delete
5.2.2 多后端服务器(同域名)
http_port 80
# 轮询负载均衡
cache_peer web1.example.com parent 80 0 \
no-query originserver round-robin \
weight=3 name=web1
cache_peer web2.example.com parent 80 0 \
no-query originserver round-robin \
weight=2 name=web2
cache_peer web3.example.com parent 80 0 \
no-query originserver round-robin \
weight=1 name=web3
# 优先使用后端,不使用对等体
prefer_direct off
never_direct allow all
5.2.3 多虚拟主机
http_port 80
# 站点 A
cache_peer web1.example.com parent 80 0 \
no-query originserver \
name=site_a
# 站点 B
cache_peer web2.example.com parent 80 0 \
no-query originserver \
name=site_b
# 基于域名路由
acl site_a_req dstdomain www.example.com api.example.com
acl site_b_req dstdomain blog.example.com shop.example.com
cache_peer_access site_a allow site_a_req
cache_peer_access site_b allow site_b_req
# 拒绝未匹配的请求
cache_peer_access site_a deny all
cache_peer_access site_b deny all
http_access allow all
5.3 SSL 卸载 (SSL Offloading)
5.3.1 基础 SSL 配置
# HTTP 端口
http_port 80
# HTTPS 端口 — SSL 卸载
https_port 443 \
cert=/etc/squid/ssl/site.crt \
key=/etc/squid/ssl/site.key \
cafile=/etc/squid/ssl/ca-bundle.crt \
options=NO_SSLv3,NO_TLSv1,NO_TLSv1_1 \
cipher=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
# 后端使用 HTTP 通信
cache_peer webserver.local parent 80 0 \
no-query originserver name=backend
5.3.2 生成自签名证书(测试用)
# 创建 SSL 目录
sudo mkdir -p /etc/squid/ssl
cd /etc/squid/ssl
# 生成自签名证书
sudo openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com" \
-keyout site.key -out site.crt
# 设置权限
sudo chmod 600 site.key
sudo chown proxy:proxy site.key site.crt
5.3.3 Let’s Encrypt 证书
# 安装 certbot
sudo apt install -y certbot
# 获取证书
sudo certbot certonly --standalone -d www.example.com
# 合并证书供 Squid 使用
sudo cat /etc/letsencrypt/live/www.example.com/fullchain.pem \
/etc/letsencrypt/live/www.example.com/privkey.pem \
> /etc/squid/ssl/site.pem
# Squid 配置
# https_port 443 cert=/etc/squid/ssl/site.pem
# 设置证书续期钩子
sudo tee /etc/letsencrypt/renewal-hooks/post/squid-reload.sh <<'EOF'
#!/bin/bash
cat /etc/letsencrypt/live/www.example.com/fullchain.pem \
/etc/letsencrypt/live/www.example.com/privkey.pem \
> /etc/squid/ssl/site.pem
systemctl reload squid
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/squid-reload.sh
5.3.4 SNI 多证书支持
# 基于 SNI 的多域名 SSL
# 方法一:多证书文件
https_port 443 \
cert=/etc/squid/ssl/default.pem \
tls-cert=/etc/squid/ssl/site_a.pem \
tls-cert=/etc/squid/ssl/site_b.pem
# 方法二:使用 ssl_crtd 动态证书(需编译 --enable-ssl-crtd)
# 适合大量域名的场景
5.3.5 SSL/TLS 安全配置
# 禁用不安全的协议
https_port 443 \
cert=/etc/squid/ssl/site.pem \
options=NO_SSLv2,NO_SSLv3,NO_TLSv1,NO_TLSv1_1 \
cipher=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
# SSL 会话缓存
ssl_session_cache shared:SSL:50MB
ssl_session_timeout 4 hours
# OCSP Stapling(Squid 6.x)
# https_port 443 ... options=OCSP Stapling
5.4 负载均衡策略
5.4.1 轮询 (Round Robin)
# 默认的负载均衡方式
cache_peer web1.local parent 80 0 no-query originserver round-robin
cache_peer web2.local parent 80 0 no-query originserver round-robin
cache_peer web3.local parent 80 0 no-query originserver round-robin
5.4.2 加权轮询 (Weighted Round Robin)
# weight 参数控制流量分配比例
cache_peer web1.local parent 80 0 no-query originserver round-robin weight=5
cache_peer web2.local parent 80 0 no-query originserver round-robin weight=3
cache_peer web3.local parent 80 0 no-query originserver round-robin weight=2
# web1 处理 50%,web2 处理 30%,web3 处理 20%
5.4.3 基于 URL 哈希的负载均衡
# 相同 URL 始终路由到同一后端(缓存友好)
cache_peer web1.local parent 80 0 no-query originserver sourcehash
cache_peer web2.local parent 80 0 no-query originserver sourcehash
cache_peer web3.local parent 80 0 no-query originserver sourcehash
# 基于客户端 IP 哈希(会话保持)
cache_peer web1.local parent 80 0 no-query originserver userhash
cache_peer web2.local parent 80 0 no-query originserver userhash
5.4.4 健康检查与故障转移
# 健康检查配置
cache_peer web1.local parent 80 0 \
no-query originserver round-robin \
connect-timeout=5 \
read-timeout=30 \
retry=3
# 仅当后端宕机时才查询其他节点
# Squid 默认不会主动健康检查,但会在连接失败时切换
# 定义备用服务器(权重低)
cache_peer backup.local parent 80 0 \
no-query originserver round-robin weight=1
5.4.5 负载均衡对比
| 策略 | Squid 选项 | 适用场景 | 缓存友好 |
|---|---|---|---|
| 轮询 | round-robin | 通用 | ★★★ |
| 加权轮询 | round-robin weight=N | 异构服务器 | ★★★ |
| URL 哈希 | sourcehash | CDN、缓存优化 | ★★★★★ |
| IP 哈希 | userhash | 会话保持 | ★★★ |
| 最少连接 | 不原生支持 | — | — |
注意:Squid 的负载均衡能力相对简单。如需高级负载均衡(最少连接、健康检查、灰度发布),建议在 Squid 前使用 Nginx 或 HAProxy,Squid 专注缓存加速。
5.5 缓存加速配置
5.5.1 反向代理缓存策略
# 缓存目录
cache_dir ufs /var/spool/squid 20000 256 4096
cache_mem 2048 MB
# 缓存对象大小限制
maximum_object_size 256 MB
minimum_object_size 1 KB
# 缓存替换策略
cache_replacement_policy heap GDSF
# 忽略后端的 Cache-Control: no-cache
# (不推荐在生产环境使用)
# ignore_ims_on_miss on
# 强制缓存(覆盖后端的 no-store)
# (谨慎使用)
# cache_store_log stdio:/var/log/squid/store.log
5.5.2 针对不同内容的缓存策略
# 静态资源 — 长期缓存
acl static_url url_regex -i \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg|mp4)$
cache allow static_url
# API 请求 — 不缓存
acl api_url url_regex -i ^https?://api\.
cache deny api_url
# 动态页面 — 短期缓存
acl dynamic_url url_regex -i \.(php|asp|jsp)$
cache allow dynamic_url
# 通用缓存规则
cache allow all
# 通过 refresh_pattern 控制缓存时间
refresh_pattern -i \.(jpg|jpeg|png|gif|ico)$ 1440 90% 43200 override-expire
refresh_pattern -i \.(css|js|woff2|svg)$ 1440 90% 43200 override-expire
refresh_pattern -i \.(mp4|webm|ogg)$ 10080 90% 43200 override-expire
refresh_pattern ^https?://api\. 0 0% 0
refresh_pattern . 60 20% 1440
5.6 HTTP 头部处理
5.6.1 添加代理头
# 添加标准代理头
request_header_add X-Real-IP "%>a" all
request_header_add X-Forwarded-For "%>a" all
request_header_add X-Forwarded-Host "%>h" all
request_header_add X-Forwarded-Proto "%>PROTO" all
request_header_add X-Request-ID "%>ha" all
# 删除 Via 和 X-Forwarded-For 中的代理信息
via off
forwarded_for delete
5.6.2 安全响应头
# 添加安全头
reply_header_add X-Content-Type-Options "nosniff" all
reply_header_add X-Frame-Options "SAMEORIGIN" all
reply_header_add X-XSS-Protection "1; mode=block" all
reply_header_add Referrer-Policy "strict-origin-when-cross-origin" all
reply_header_add Strict-Transport-Security "max-age=31536000; includeSubDomains" all
# 删除敏感响应头
reply_header_access X-Powered-By deny all
reply_header_access Server deny all
5.6.3 响应压缩
# Squid 不直接支持 gzip 压缩
# 但可以透传后端的压缩内容
# 确保 Accept-Encoding 头被传递
request_header_access Accept-Encoding allow all
# 如果需要压缩,建议在 Squid 前使用 Nginx 处理
5.7 完整反向代理配置示例
# /etc/squid/squid.conf — 反向代理生产配置
# ============ 端口 ============
http_port 80
https_port 443 \
cert=/etc/squid/ssl/site.pem \
key=/etc/squid/ssl/site.key \
options=NO_SSLv3,NO_TLSv1,NO_TLSv1_1
# ============ ACL ============
acl SSL_ports port 443
acl Safe_ports port 80 443
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
# 搜索引擎爬虫白名单
acl search_engine src 66.249.64.0/19 # Google
acl search_engine src 207.46.0.0/16 # Bing
# 限制请求频率(简单实现)
acl rapid_req maxconn 50
http_access deny rapid_req !search_engine
http_access allow all
# ============ 后端服务器 ============
cache_peer web1.local parent 80 0 \
no-query originserver round-robin weight=5 \
connect-timeout=5 \
name=web1
cache_peer web2.local parent 80 0 \
no-query originserver round-robin weight=3 \
connect-timeout=5 \
name=web2
cache_peer backup.local parent 80 0 \
no-query originserver \
connect-timeout=10 \
name=backup
never_direct allow all
# ============ 缓存 ============
cache_dir ufs /var/spool/squid 20000 256 4096
cache_mem 2048 MB
maximum_object_size 256 MB
refresh_pattern -i \.(jpg|jpeg|png|gif|ico|webp)$ 1440 90% 43200
refresh_pattern -i \.(css|js|woff2|svg|ttf)$ 1440 90% 43200
refresh_pattern -i \.(mp4|webm|ogg|pdf|zip)$ 10080 90% 43200
refresh_pattern ^/api/ 0 0% 0
refresh_pattern . 60 20% 1440
# ============ 头部处理 ============
via off
forwarded_for delete
httpd_suppress_version_string on
request_header_add X-Real-IP "%>a" all
request_header_add X-Forwarded-For "%>a" all
request_header_add X-Forwarded-Proto "%>PROTO" all
reply_header_add X-Content-Type-Options "nosniff" all
reply_header_add X-Frame-Options "SAMEORIGIN" all
reply_header_add Strict-Transport-Security "max-age=31536000" all
reply_header_access Server deny all
reply_header_access X-Powered-By deny all
# ============ 日志 ============
access_log /var/log/squid/access.log squid
cache_log /var/log/squid/cache.log
# ============ 性能 ============
visible_hostname cdn.example.com
client_db off
pipeline_prefetch on
# 连接超时
connect_timeout 10 seconds
read_timeout 30 seconds
request_timeout 10 seconds
persistent_request_timeout 1 minute
5.8 Squid vs Nginx 反向代理
| 特性 | Squid | Nginx |
|---|---|---|
| 缓存能力 | ★★★★★ 专业级 | ★★★ 基础 |
| 负载均衡 | ★★★ 轮询/哈希 | ★★★★★ 丰富算法 |
| SSL 处理 | ★★★★ 原生支持 | ★★★★★ 成熟 |
| 配置复杂度 | 高 | 中 |
| HTTP/2 | 部分支持 | 完整支持 |
| WebSocket | CONNECT 代理 | 原生支持 |
| 动态上游 | 不支持 | 支持(商业版) |
| 监控 | Cache Manager | stub_status/Plus |
| 学习曲线 | 陡峭 | 平缓 |
建议:
- 需要强缓存能力:Squid
- 需要丰富负载均衡:Nginx
- 复杂场景:Nginx(前端 SSL + 负载均衡)→ Squid(缓存加速)→ 后端
5.9 本章小结
| 功能 | 关键配置 |
|---|---|
| 基础反向代理 | cache_peer ... originserver |
| SSL 卸载 | https_port + 证书配置 |
| 负载均衡 | round-robin / weight / sourcehash |
| 缓存加速 | cache_dir + refresh_pattern |
| 头部处理 | request_header_add / reply_header_add |
| 安全防护 | ACL + 限流 + 安全头 |