3.5 Web 服务器进阶——Apache httpd 深入与 SSL 卸载
预计阅读时间:16 分钟
📖 目录
Apache httpd 在模块生态、.htaccess 分布式配置、动态内容处理方面仍有独到优势。本文深入 httpd 核心配置,并讲解 SSL 卸载、mTLS 双向认证、CDN 回源等企业级实践。
/etc/httpd/、/etc/pki/tls/certs/、命令 httpd/apachectl)。Ubuntu/Debian 用户对应替换为 apache2 包、/etc/apache2/ 与 a2enmod,配置语法与本节内容完全一致。学习目标
- 掌握 Apache httpd 的 VirtualHost 与 .htaccess 分布式配置机制,理解 AllowOverride 的作用
- 理解 mod_rewrite、IP 访问控制、基本认证等常用模块的配置方法
- 能部署 SSL 卸载架构:前端 Nginx/CDN 终止 TLS,后端 httpd 只处理 HTTP 明文
- 能配置 mTLS 双向认证,处理客户端证书验证与健康检查排除问题
- 能基于 X-Forwarded-* 头与 RemoteIPTrustedProxy 正确处理 CDN 回源与客户端真实 IP
- 能根据业务场景在 Nginx 与 Apache httpd 之间做出合理选型并组合使用
前置知识
- 3.4:Nginx Web服务器 Nginx Web 服务器配置与管理——SSL 卸载场景中通常由 Nginx 担任前端,且与 httpd 互为对比参照
- 3.11:SSL/TLS 证书管理 SSL/TLS 证书管理——mTLS 与 SSL 卸载依赖证书签发、证书链与续期知识
- sec_web01 WAF:ModSecurity 配置——反向代理层防护与 WAF 部署架构呼应
- 3.3:实战:搭建个人网站 实战:搭建个人网站——Nginx 静态站、HTTPS 与域名绑定的实战基础
1. Apache httpd 核心配置
1.1 VirtualHost 基础
# /etc/httpd/conf.d/vhosts.conf(CentOS/RHEL)
<VirtualHost *:80>
ServerName www.example.com
DocumentRoot /var/www/example
ErrorLog /var/log/httpd/example_error.log
CustomLog /var/log/httpd/example_access.log combined
<Directory /var/www/example>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
1.2 .htaccess 分布式配置
httpd 支持 .htaccess 在目录级别覆盖主配置(需要 AllowOverride All),适合共享主机或无法重启 httpd 的场景:
# /var/www/example/.htaccess
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
ErrorDocument 404 /errors/404.html
# IP 访问控制(注意合并语义:并列的 Require 之间默认是 OR;
# 若想"白名单 + 密码"同时满足,需用 包住 IP 与 valid-user)
# 下面用 RequireAll 包两个网段时是 AND 关系——两个不相交网段恒为假,等价于谁都无法通过,
# 所以并列网段用两条 Require 即可(OR):
<RequireAll>
Require ip 10.0.0.0/8
Require ip 192.168.1.0/24
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/httpd/.htpasswd
Require valid-user
</RequireAll>
1.3 mod_rewrite URL 重写
RewriteEngine On
LogLevel alert rewrite:trace6
# 非 www 跳转到 www
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
# 去除 .html 后缀(伪静态)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.+)$ $1.html [L]
# WordPress 式固定链接
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /index.php?/$1 [QSA,L]
# 反向代理到后端
RewriteCond %{HTTP_HOST} ^api\.example\.com
RewriteRule ^/(.*)$ http://127.0.0.1:8080/$1 [P,L]
| 标记 | 含义 |
|---|---|
L | 最后一条规则,停止处理 |
R=301/302 | 301 永久重定向 / 302 临时重定向 |
QSA | 追加原始查询字符串 |
P | 代理请求(需 mod_proxy) |
NC | 不区分大小写 |
1.4 Apache 性能调优:MPM 与 KeepAlive
MPM(多进程处理模块)决定 httpd 处理并发的方式,是性能调优的第一决策点。三种 MPM 各有适用场景:
| 维度 | prefork | worker | event |
|---|---|---|---|
| 模型 | 一进程一线程 | 多进程 × 多线程 | worker + 事件驱动(基于 epoll) |
| 并发能力 | 低(受进程数限制) | 中 | 高,最适合 KeepAlive 长连接 |
| 内存占用 | 最高(每进程独立内存) | 中 | 低(空闲连接不占线程) |
| 兼容性 | mod_php 等非线程安全模块 | 线程安全模块 | 同 worker,PHP-FPM 场景最佳 |
| 适用场景 | 老 LAMP(mod_php)、兼容性优先 | 混合负载 | 高并发静态/反向代理 |
# CentOS/RHEL 选择 event MPM(2.4 默认)
LoadModule mpm_event_module modules/mod_mpm_event.so
# event 调优示例
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 400 # 峰值并发上限,按内存估算
MaxConnectionsPerChild 10000 # 定期回收进程,防内存碎片
</IfModule>
# 查看当前 MPM 与并发上限
httpd -V | grep -i mpm
KeepAlive 允许同一 TCP 连接复用多次请求,对含大量静态资源的页面收益明显,但要防止空闲连接长期占线程:
# /etc/httpd/conf/httpd.conf
KeepAlive On
MaxKeepAliveRequests 100 # 单连接最大请求数,0 为不限
KeepAliveTimeout 5 # 空闲 5 秒即关闭,不宜过大(防资源占用)
# 验证效果:同一命令带两个 URL,同连接连续请求,第二个请求复用连接不再 TCP 握手
curl -v http://localhost/ http://localhost/ 2>&1 | grep -E "Re-using"
2. SSL 卸载(SSL Termination)
SSL 卸载是指在反向代理层(Nginx、HAProxy 或 CDN)终止 TLS 握手,后端只处理 HTTP 明文。好处:减少后端 TLS 计算开销、统一证书管理、简化后端架构。
# 前端 Nginx(SSL 卸载)
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
location / {
proxy_pass http://10.0.0.5:80; # 后端 httpd,明文 HTTP
}
}
server {
listen 80;
server_name www.example.com;
return 301 https://$host$request_uri;
}
# 后端 httpd 信任代理头(否则会导致 HTTPS 重定向死循环)
LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPTrustedProxy 10.0.0.0/8
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
如果后端 httpd 需要直接对外提供 HTTPS(无前置 Nginx/CDN),则由 httpd 自己终止 TLS。完整配置如下,注意证书链、会话缓存与 OCSP Stapling 三项缺一不可:
# /etc/httpd/conf.d/ssl-example.conf
Listen 443
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/example
SSLEngine On
# 证书链:服务器证书 + 中间 CA 拼接在一个文件中
SSLCertificateFile /etc/pki/tls/certs/example.com-fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/example.com.key
SSLCACertificateFile /etc/pki/tls/certs/root-ca.pem
# 只允许 TLS 1.2/1.3
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder on
# 性能参数 1:会话缓存(免去重复握手,减 2 个 RTT)
SSLSessionCache "shmcb:/run/httpd/sslcache(512000)"
SSLSessionCacheTimeout 300
# 性能参数 2:OCSP Stapling(客户端无需再向 CA 查询吊销状态)
SSLUseStapling On
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors Off
SSLStaplingCache "shmcb:/run/httpd/ocsp_cache(128000)"
# 可选:HSTS 与安全响应头
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>
# 验证 SSL 配置
httpd -t
apachectl configtest
curl -I https://localhost/ -k
# 检查证书链与 OCSP Stapling 是否生效
openssl s_client -connect www.example.com:443 -status -tlsextdebug 2>/dev/null | grep -A5 "OCSP response"
# 输出 "OCSP Response Status: successful" 表示 Stapling 正常
3. mTLS 双向认证
mTLS(Mutual TLS)要求客户端也提供证书,服务端验证客户端身份。适用于微服务间通信、API 网关认证、零信任架构。
3.1 生成证书
# 生成 CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/C=CN/ST=Beijing/O=MyOrg/CN=MyCA"
# 生成服务端证书
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
-subj "/C=CN/ST=Beijing/O=MyOrg/CN=example.com"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 365
# 生成客户端证书
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
-subj "/C=CN/ST=Beijing/O=MyOrg/CN=api-client-01"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt -days 365
3.2 httpd 配置 mTLS
<VirtualHost *:443>
ServerName api.example.com
SSLEngine On
SSLCertificateFile /etc/httpd/ssl/server.crt
SSLCertificateKeyFile /etc/httpd/ssl/server.key
SSLCACertificateFile /etc/httpd/ssl/ca.crt
# mTLS 核心:强制客户端证书
SSLVerifyClient require
SSLVerifyDepth 2
# 将客户端证书信息传递给后端应用
RequestHeader set X-SSL-Client-CN "%{SSL_CLIENT_S_DN_CN}s"
RequestHeader set X-SSL-Client-Verify "%{SSL_CLIENT_VERIFY}s"
DocumentRoot /var/www/api
</VirtualHost>
3.2.1 客户端证书测试与撤销
# 带客户端证书访问(.crt/.key 分文件)
curl -sS --cert client.crt --key client.key \
-H "Host: api.example.com" https://api.example.com/ping
# 证书 + 私钥打包为 PEM 后访问(更常见)
openssl pkcs12 -export -out client.p12 -inkey client.key \
-in client.crt -certfile ca.crt -passout pass:client-password
curl -sS --cert-type p12 --cert client.p12:client-password \
https://api.example.com/ping
# 不带证书访问应被拒绝(验证 mTLS 生效)
curl -sS https://api.example.com/ping
# 期望输出: TLS 握手阶段被拒:curl: (35) SSL connect error
# SSL alert number 116 (certificate required)(收不到 HTTP 400,握手就失败了)
# 在服务端查看验证结果
# 请求头 X-SSL-Client-Verify 应为 SUCCESS,X-SSL-Client-CN 为客户端 CN
客户端证书泄露或人员离职时必须吊销。httpd 通过 SSLCARevocationFile 加载 CRL:
# 生成 CRL 并在 httpd 中引用
# 注意:openssl ca 需要 CA 的配置文件(index.txt 数据库等),
# 若客户端证书是用 openssl x509 -req 直接签发的(未进 ca 数据库),
# 吊销会失败——生产环境请用 openssl ca 统一签发并维护 index.txt:
# openssl ca -config ca.cnf -in client.csr -out client.crt
openssl ca -gencrl -config ca.cnf -out crl.pem -crldays 30
# 追加到 httpd 配置
# SSLCARevocationFile /etc/pki/tls/certs/crl.pem
# SSLCARevocationCheck chain
# 吊销某张客户端证书(证书必须存在于 ca 的 index.txt 中)
openssl ca -revoke client.crt -config ca.cnf
openssl ca -gencrl -config ca.cnf -out crl.pem -crldays 30
systemctl reload httpd
3.3 Nginx 做 mTLS 卸载
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_trusted_certificate /etc/nginx/ssl/ca.crt;
ssl_client_certificate /etc/nginx/ssl/ca.crt;
ssl_verify_client on;
proxy_set_header X-SSL-Client-CN $ssl_client_s_dn_cn;
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
4. Nginx vs Apache httpd 对比选型
| 维度 | Nginx | Apache httpd |
|---|---|---|
| 架构 | 事件驱动,异步非阻塞 | 进程/线程模型(MPM) |
| 静态文件性能 | 极高,内存占用低 | 良好,prefork 模式下较高 |
| 动态内容 | FastCGI 代理(PHP-FPM) | 原生 mod_php 嵌入 |
| 分布式配置 | 不支持 .htaccess | 支持 .htaccess(共享主机友好) |
| URL 重写 | 原生 rewrite,性能好 | mod_rewrite 功能更强 |
| 反向代理 | 原生强项,负载均衡丰富 | mod_proxy,功能齐全但性能略逊 |
| SSL/TLS | 原生支持,配置简洁 | 依赖 mod_ssl,配置稍繁琐 |
| 适用场景 | 反向代理、高并发、CDN 边缘 | 传统 LAMP、共享主机、.htaccess 需求 |
httpd 性能监控指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
| BusyWorkers | 当前处理请求的 worker 数 | > MaxRequestWorkers × 80% |
| IdleWorkers | 空闲的 worker 数 | < 5(可能请求堆积) |
| ReqPerSec | 每秒处理请求数 | 按基线调整 |
| BytesPerSec | 每秒发送字节数 | 接近带宽上限 |
| Load5 | 服务器负载 | > CPU 核心数 × 2 |
# 查看 httpd 状态页(需启用 mod_status)
# httpd.conf 中添加:
# ExtendedStatus On
# <Location /server-status>
# SetHandler server-status
# Require ip 127.0.0.1
# </Location>
curl http://localhost/server-status?auto
4.1 场景选型对照
| 业务场景 | 推荐方案 | 理由 |
|---|---|---|
| 高并发静态站 / CDN 边缘 | Nginx | 事件驱动,内存占用低,天然扛长连接 |
| 传统 PHP 站点(mod_php) | Apache prefork | 非线程安全模块的唯一选择,兼容老代码 |
| PHP-FPM + 高并发 | Nginx 前端 + httpd event 后端(或纯 Nginx) | event MPM 或 Nginx 都适合 FastCGI 代理 |
| 共享主机多租户 | Apache | .htaccess 让用户免重启改配置 |
| 反向代理 + 负载均衡 | Nginx | upstream 健康检查、加权轮询开箱即用 |
| 复杂 URL 重写规则 | Apache mod_rewrite | RewriteCond/RewriteRule 表达力强,支持多条件回溯 |
| 企业内网系统 / 旧应用迁移 | Apache | 模块生态全,LDAP、SSO 等模块成熟 |
5. CDN 回源配置要点
用户 → CDN 边缘节点(TLS 终止)
↓(HTTP 明文或 mTLS)
回源服务器(Nginx / httpd)
回源协议选择:
HTTP 明文 → CDN 边缘到源站加密链路不保证(内网可用)
HTTPS → 源站需配 TLS 证书,CDN 二次 TLS 终止
mTLS → CDN 到源站双向认证(高安全场景)
# CDN 回源关键配置
# 回源 Host 用源站域名,避免 httpd 虚拟主机匹配错误
# Header 透传:X-Real-IP / X-Forwarded-For / X-Forwarded-Proto
# 源站 httpd 信任 CDN 回源代理段
RemoteIPTrustedProxy 100.100.0.0/16
RemoteIPTrustedProxy 47.88.0.0/14
# 防止 HTTPS 重定向死循环
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
SSLCACertificateFile 指向 CDN 的 CA。5.1 mod_remoteip 获取真实 IP
CDN 回源后,httpd 的 %h 记录的是 CDN 边缘 IP。用 mod_remoteip 解析 X-Forwarded-For,把客户端真实 IP 写入访问日志,并让 Require ip、限流规则都基于真实 IP 生效:
# /etc/httpd/conf.modules.d/00-remoteip.conf
LoadModule remoteip_module modules/mod_remoteip.so
# 信任 CDN 回源网段(务必精确,不要用 0.0.0.0/0)
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 100.100.0.0/16 # 阿里云 CDN 回源段
RemoteIPTrustedProxy 47.88.0.0/14 # 自定义边缘段
# 访问日志改用 %a(mod_remoteip 重写后的真实 IP)
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_real
CustomLog /var/log/httpd/example_access.log combined_real
5.2 回源校验与源站保护
# 方案一:IP 白名单——源站只接受 CDN 回源段访问
<VirtualHost *:80>
ServerName www.example.com
<Location />
Require ip 100.100.0.0/16
Require ip 47.88.0.0/14
Require ip 127.0.0.1 # 本机健康检查
</Location>
</VirtualHost>
# 方案二:自定义头校验——CDN 回源时注入固定 Token
# CDN 控制台回源配置:回源请求头 X-Origin-Token: 9f8a7b6c...
RewriteEngine On
RewriteCond %{HTTP:X-Origin-Token} !=9f8a7b6c...
RewriteRule ^ - [F]
# 方案三:隐藏源站地址
# 源站域名不发布 DNS 记录,仅 CDN 通过 CNAME 或回源配置访问;
# 源站安全组只放行 CDN 回源 IP 段的 80/443 端口
Require ip 白名单或触发限流误杀。CDN 回源配置案例
# 完整的 CDN 回源 httpd 配置
# /etc/httpd/conf.d/cdn-origin.conf
# 信任 CDN 回源 IP 段
LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 100.100.0.0/16 # 阿里云 CDN
RemoteIPTrustedProxy 173.245.48.0/20 # Cloudflare
# 防止 HTTPS 重定向死循环
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# 访问日志使用真实 IP
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" cdn_real
CustomLog /var/log/httpd/cdn_access.log cdn_real
# 源站保护:只接受 CDN 回源请求
<Location />
Require ip 100.100.0.0/16
Require ip 173.245.48.0/20
Require ip 127.0.0.1
</Location>
常见错误
1. HTTPS 重定向死循环
症状:浏览器反复提示重定向次数过多。原因:后端 httpd 未信任前端代理的 X-Forwarded-Proto 头,导致 httpd 误判请求为 HTTP 并再次重定向。
排查:检查是否配置了 RemoteIPTrustedProxy 并在 RewriteCond 中判断 %{HTTP:X-Forwarded-Proto}。
2. mTLS 客户端证书验证失败(SSL_ERROR_RX_RECORD_TOO_LONG)
症状:curl 报 SSL_ERROR_RX_RECORD_TOO_LONG,或浏览器报 ERR_SSL_PROTOCOL_ERROR。原因:httpd 未启用 SSL 或 443 端口被其他服务占用。
排查:httpd -t 检查配置语法,ss -tlnp | grep 443 确认端口监听,openssl s_client -connect localhost:443 测试 TLS 握手。
3. .htaccess 规则不生效
症状:URL 重写无效果。原因:VirtualHost 中 AllowOverride None(默认值)禁止了 .htaccess 解析。
排查:确认对应 <Directory> 块中设置了 AllowOverride All,并重启 httpd 使配置生效。
4. SSL 证书链不完整导致客户端报不受信任
症状:部分浏览器正常、部分报证书不受信任。原因:SSLCertificateFile 中只放了服务器证书,缺少中间 CA 证书。
排查:用 openssl s_client -showcerts -connect example.com:443 检查证书链,将中间证书拼接到服务器证书文件中。
5. SSLVerifyClient require 后所有请求返回 400
症状:配置 mTLS 后正常浏览器请求也返回 400 Bad Request。原因:没有排除健康检查或静态资源的客户端证书验证。
排查:在需要排除的 Location 中设置 SSLVerifyClient none,或使用 SSLVerifyClient optional_no_ca 做选择性验证。
最佳实践
1. SSL 卸载放在反向代理层
证书管理集中在 Nginx/CDN,后端 httpd 只处理 HTTP 明文。统一续期、统一管理,后端无需暴露 443 端口。
2. .htaccess 仅在必要时使用
高并发站点应在 VirtualHost 块中直接写入配置,避免 .htaccess 的逐目录扫描开销。共享主机或无法重启 httpd 时才考虑 .htaccess。
3. mTLS 证书设置合理有效期与轮换周期
客户端证书有效期建议 1 年,配合自动化续期。定期轮换 CA 证书,吊销列表(CRL)或 OCSP 应及时更新。
4. CDN 回源务必信任代理 IP 段
源站 httpd 必须配置 RemoteIPTrustedProxy 添加 CDN 回源 IP 段,否则客户端真实 IP 会丢失,且可能触发错误的 HTTPS 重定向。
5. 禁用 SSLv3 和 TLS 1.0/1.1
在 httpd 和 Nginx 配置中显式指定 SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1,只允许 TLS 1.2+,避免已知安全漏洞。
故障排查案例:SSL 证书链不完整
现象:Chrome 浏览器正常访问,但 curl 和部分移动端报 SSL certificate problem: unable to get local issuer certificate。
排查:执行 openssl s_client -connect example.com:443 -showcerts,输出中只显示了服务器证书,缺少中间 CA 证书。
根因:httpd 的 SSLCertificateFile 中只包含服务器证书,未拼接中间 CA 证书。Chrome 内置 AIA(Authority Information Access)可以自动补全中间证书,但 curl 和旧版 Android 不支持此机制。
修复:将中间证书拼接到服务器证书文件中,顺序为:服务器证书在前,中间 CA 在后。
# 拼接证书链
cat server.crt intermediate-ca.crt > /etc/httpd/ssl/example.com-fullchain.pem
# 验证证书链完整性
openssl verify -CAfile root-ca.crt example.com-fullchain.pem
# 输出: example.com-fullchain.pem: OK
# 重载 httpd
apachectl graceful
# 再次测试
curl -v https://example.com/ 2>&1 | grep -E "SSL certificate|subject|issuer"
练习题
1. 配置 SSL 卸载
假设源站 httpd 运行在 80 端口,前端 Nginx 做 SSL 卸载。请写出:(a) Nginx 的 443 端口 VirtualHost 配置(含证书路径和 proxy_pass);(b) httpd 需要添加的 mod_remoteip 配置,使其信任 Nginx 所在网段 10.1.0.0/16。
2. 排查重定向死循环
某站点前端是阿里云 CDN(回源 HTTP),后端 httpd 配置了 HTTPS 重定向规则。用户访问时浏览器报 ERR_TOO_MANY_REDIRECTS。请列出 3 个可能的原因和对应的修复方法。
3. mTLS 证书签发与配置
为一个微服务 API 网关配置 mTLS:(a) 用 openssl 生成 CA、服务端证书、客户端证书的命令;(b) httpd VirtualHost 中启用 mTLS 并将客户端 CN 传递给后端应用的完整配置。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 SSL 卸载的概念和作用 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成 httpd SSL 配置、mTLS 证书生成 | 在终端实际执行 |
| 原理掌握 | 能说出 Apache httpd 的模块化架构和工作原理 | 画出流程图 |
| 故障排查 | 能独立排查 HTTPS 重定向死循环、SSL 证书错误 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么需要在 CDN 环境中正确处理 X-Forwarded-Proto | 对比不同方案 |
本章总结
Apache httpd 凭借模块生态与 .htaccess 分布式配置在共享主机和传统 LAMP 场景中仍有不可替代的价值,但高并发场景应将 SSL 卸载与 mTLS 终结交给 Nginx/CDN,后端 httpd 专注业务处理。CDN 回源必须信任代理 IP 段并正确处理 X-Forwarded-Proto,否则会陷入 HTTPS 重定向死循环。选型的关键不是谁更好,而是让每层组件做自己擅长的事。
延伸阅读
- 3.11:SSL/TLS 证书管理 SSL/TLS 证书管理(HSTS 与 HTTPS 强化)
- sec_web01 Web 应用防火墙:ModSecurity + OWASP CRS
- 3.4:Nginx Web服务器 Nginx Web 服务器配置与管理
- 5.1:Linux 安全加固 Linux 安全加固(操作系统层安全)