强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Squid 完全指南 / 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 哈希sourcehashCDN、缓存优化★★★★★
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 反向代理

特性SquidNginx
缓存能力★★★★★ 专业级★★★ 基础
负载均衡★★★ 轮询/哈希★★★★★ 丰富算法
SSL 处理★★★★ 原生支持★★★★★ 成熟
配置复杂度
HTTP/2部分支持完整支持
WebSocketCONNECT 代理原生支持
动态上游不支持支持(商业版)
监控Cache Managerstub_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 + 限流 + 安全头

扩展阅读