先说一个常见误区:不少朋友误以为,在Apache上配置多个HTTPS域名,只需手动修改一下证书路径就能搞定。实际操作后,往往发现只有一个域名能成功访问,其余的都会直接报错ERR_SSL_PROTOCOL_ERROR。这背后的原因其实很简明——Apache在同一个IP和端口上,默认不会依据域名来切换证书。

通俗点说,Apache会直接加载第一个匹配的配置及其证书,然后对所有后续的HTTPS请求都“一视同仁”。如果请求的域名和这个证书不匹配,握手过程自然会失败。要解决此问题,必须启用SNI(Server Name Indication)技术,并为每一个独立配置完整的SSL指令。
为何只有首个VirtualHost生效:SNI缺失与配置不全
Apache默认在同一端口(例如*:443)上,不支持“按域名动态切换证书”。这项能力必须依赖SNI,同时需要客户端(浏览器)的兼容。在XAMPP的默认配置里,既没有显式开启SNI,也没有在每个站点中完整配置SSL参数。因此,你极可能遇到的情况是:访问https://a.test顺利无误,但https://b.test却直接白屏或报错。
排查步骤如下:
- 确认模块已加载: 首先检查
httpd.conf中,LoadModule ssl_module modules/mod_ssl.so和Include conf/extra/httpd-ssl.conf这两行是否被注释掉。它们必须处于激活状态。 - 清理默认VirtualHost: 关键的一步。如果你在
httpd-ssl.conf里发现了一个“万能”的配置,它可能会“霸占”所有443端口的请求。你需要将其禁用或注释掉。 - 为每个站点配齐参数: 每个独立的HTTPS
里,必须像下面这样,将三个核心指令写全,缺一不可:SSLEngine on SSLCertificateFile "你的证书路径" SSLCertificateKeyFile "你的私钥路径" - 证书与域名严格绑定: 如果你采用的是自签名证书,生成证书时填写的
Common Name必须与ServerName完全一致,否则浏览器会报NET::ERR_CERT_COMMON_NAME_INVALID错误。
更稳妥的方案:使用不同端口区分站点
如果觉得SNI的配置及兼容性测试过于繁琐,这里有一个更稳妥、更直接的解决方案:为每个站点分配一个独立的HTTPS端口,例如4433、4443、4453。尤其在Windows环境下,系统服务经常抢占443端口,修改端口反而是快速解决问题的有效方式。
具体操作也十分明确:
- 添加监听端口: 在
httpd.conf的最顶部,加入你想要使用的端口号,例如Listen 4433和Listen 4443。这行指令不能写在httpd-ssl.conf里。 - 配置独立的VirtualHost: 在
httpd-ssl.conf文件的底部,追加两个独立的配置块。每个块的端口号必须与你刚才添加的Listen指令严格对应。示例如下:
另一个站点同理,只需替换端口号、网站根目录及对应的DocumentRoot "D:/xampp/htdocs/site-a" ServerName a.test SSLEngine on SSLCertificateFile "conf/ssl.crt/a.test.crt" SSLCertificateKeyFile "conf/ssl.key/a.test.key" ServerName。 - 注意路径格式: 证书路径中,务必使用正斜杠
/或双反斜杠\\。单反斜杠\在Apache配置中会被视为转义字符,导致路径识别错误。 - 彻底重启: 完成配置修改后,必须完全停止(Stop)Apache服务,然后再重新启动(Start)。仅执行“重新加载(Restart)”操作,SSL模块的状态可能无法被刷新。
证书路径与格式:常见陷阱与注意事项
Apache对证书文件的要求非常“严格”,路径不能有丝毫差错,格式和权限也必须正确。否则,要么启动失败,要么握手过程中断。错误日志中最常见的是SSL Library Error: error:02001003:system library:fopen:No such process或error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch。
以下细节能帮你节省大量调试时间:
- 使用自带的openssl: 不要使用第三方工具,必须采用XAMPP自带的
openssl.exe(位于目录下)来生成证书。否则,生成的PEM编码可能不兼容。\apache\bin\ - 私钥不要加密: 生成私钥时,务必添加
-nodes参数(不加密)。否则Apache启动时需要手动输入密码,无法实现自动启动。 - 路径是相对conf目录的: 配置中的
SSLCertificateFile "conf/ssl.crt/a.test.crt",实际指向的是。\apache\conf\ssl.crt\a.test.crt - 手动创建并授权: 目录
ssl.crt和ssl.key必须手动在conf\目录下创建,Apache不会自动生成。创建后,还必须在Windows的“安全”属性中,为SYSTEM用户添加“读取”权限。
hosts与浏览器:解决问题的辅助环节
即使Apache配置完美无瑕,你仍可能遇到无法访问的情况。问题通常出在本机DNS解析或浏览器缓存上。
- 修改hosts文件: 必须前往
C:\Windows\System32\drivers\etc\hosts文件,手动添加域名映射:127.0.0.1 a.test和127.0.0.1 b.test。仅依靠localhost是无法生效的。 - 处理自签名证书警告: 首次访问自签名证书站点时,Chrome会拦截并显示“您的连接不是私密连接”。不必慌张,点击“高级”按钮,然后选择“继续前往a.test(不安全)”。随后浏览器会记住这个例外。
- 清除HSTS缓存: 有时,浏览器会强制将HTTP请求升级到HTTPS,导致访问失败。可以打开
chrome://net-internals/#hsts,在“Delete domain security policies”中输入你要测试的域名,清除HSTS缓存记录。 - 处理混合内容: 如果项目代码中硬编码了
https://的资源链接(例如JS文件或API地址),HTTPS页面会因“混合内容”被浏览器拦截。记得将所有资源链接改为https://或相对协议//。
归根结底,配置Apache多站点HTTPS时,最令人困扰的往往不是语法本身,而是证书路径是否真实存在、Listen与的端口号是否完全一致、以及在Windows后台悄悄占用443端口的那个svchost.exe进程。把这些细节一一理清后,后续的操作便会水到渠成。
