Apache VirtualHost无法真正按域名单独启用双向认证,因TLS握手早于Host头解析;必须配置SSLEngine on、SSLCertificateFile/KeyFile、SSLCACertificateFile和SSLVerifyClient require四项,缺一不可,否则报500或退化为单向。

Apache 的 VirtualHost 无法真正“按域名”单独启用双向认证,因为 TLS 握手发生在 Host 头解析之前,服务器在知道访问的是哪个站点前,就必须决定是否要求客户端证书。但你可以通过合理组合配置,在逻辑上实现“仅对特定站点强制双向认证”的效果。
必须配置的四项核心指令
缺一不可,否则会报 500 错误或退化为单向 HTTPS:
- SSLEngine on:启用 SSL/TLS 模块;
- SSLCertificateFile + SSLCertificateKeyFile:指定服务端证书和私钥(用于证明服务器身份);
-
SSLCACertificateFile:指向可信 CA 根证书(PEM 格式),用于验证客户端证书签名——漏掉它,
SSLVerifyClient require直接失败; - SSLVerifyClient require:强制客户端提供并验证证书(不能只写这一行,必须配齐 CA 文件)。
解决“多站点共用 IP:443”的关键技巧
若多个 HTTPS 站点共享同一 IP 和端口(常见于 SNI 场景),无法在 TLS 层按域名开关验证。推荐两种实用路径:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
-
统一设为 optional_no_ca + 运行时拦截:在 VirtualHost 中设
SSLVerifyClient optional_no_ca,再用Require expr判断域名和证书状态。例如只对api.example.com强制校验:Require expr %{HTTP_HOST} == 'api.example.com' && %{SSL_CLIENT_VERIFY} == 'SUCCESS'; -
为双向站点分配独立 IP 或端口:最干净可靠的方式。比如给双向站点绑定
192.168.1.100:443,其他站点用192.168.1.101:443。这样可在对应<VirtualHost 192.168.1.100:443>块中直接使用require,无歧义、无绕过风险。
传递证书信息供后端识别用户
Apache 验证通过后,可把客户端证书字段注入请求头,让 PHP/Python 等后端做进一步鉴权:
- 加
SSLOptions +StdEnvVars +ExportCertData启用环境变量导出; - 用
RequestHeader set X-Client-CN "%{SSL_CLIENT_S_DN_CN}s"传 Common Name; - 也可传序列号(
%{SSL_CLIENT_M_SERIAL}s)或证书指纹,确保后端能唯一识别合法客户端。
安全加固与常见避坑点
生产环境务必注意:
- CA 文件权限必须是 600,属主为 Apache 运行用户(如 www-data 或 apache);
- PEM 文件不能含空行、注释、私钥或乱码,建议用
openssl x509 -in ca.crt -text -noout验证格式; - 禁用老旧协议:
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1; - 启用 OCSP 装订(
SSLUseStapling on)提升吊销检查效率; - 测试前运行
httpd -t或a2ensite -t检查语法,避免重启失败。

















