Apache/Nginx多Vhost仅Chrome报ERR_SSL_PROTOCOL_ERROR求助
我有一台IPv4服务器,两个子域名domain1.dns.fr和domain2.dns.fr均指向该服务器。近期发现仅在Google Chrome浏览器中访问domain2.dns.fr时会出现ERR_SSL_PROTOCOL_ERROR错误,Firefox、Edge浏览器可正常访问。尝试调整Apache2(2.4.10)和Nginx(1.6.2)的Vhost配置后问题依旧,更奇怪的是:调换Vhost声明顺序后,domain2.dns.fr可正常工作,但domain1.dns.fr会出现相同的ERR_SSL_PROTOCOL_ERROR错误。已排除浏览器缓存问题,怀疑Vhost/服务器存在SSL证书冲突,但未找到根源。
补充:若放宽ServerName绑定限制,访问domain2.dns.fr时浏览器会返回domain1.dns.fr的SSL证书,Vhost出现混淆。
技术栈
- 操作系统:Ubuntu 14.10
- Apache版本:Apache/2.4.10
- Nginx版本:nginx/1.6.2
Apache配置
<VirtualHost domain1.dns.fr:443> ServerName domain1.dns.fr ProxyPass / http://localhost:8080/ SSLEngine on SSLProtocol -all +TLSv1.2 SSLCertificateFile /root/.acme.sh/domain1.dns.fr/domain1.dns.fr.cer SSLCertificateChainFile /root/.acme.sh/domain1.dns.fr/ca.cer SSLCertificateKeyFile /root/.acme.sh/domain1.dns.fr/domain1.dns.fr.key </VirtualHost> <VirtualHost domain2.dns.fr:443> ServerName domain2.dns.fr DocumentRoot /var/www/domain2.dns.fr/public <Directory /var/www/domain2.dns.fr/public> Require all granted Options -Indexes +FollowSymLinks AllowOverride all </Directory> SSLEngine on SSLCertificateFile /root/.acme.sh/domain2.dns.fr/domain2.dns.fr.cer SSLCertificateChainFile /root/.acme.sh/domain2.dns.fr/ca.cer SSLCertificateKeyFile /root/.acme.sh/domain2.dns.frdomain2.dns.fr.key </VirtualHost>
Nginx配置
server { listen *:443 ssl; server_name domain1.dns.fr; charset utf-8; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-for $remote_addr; port_in_redirect off; proxy_redirect off; } ssl on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache shared:SSL:20m; ssl_session_timeout 60m; ssl_prefer_server_ciphers on; ssl_certificate /root/.acme.sh/domain1.dns.fr/domain1.dns.fr.cer; ssl_certificate_key /root/.acme.sh/domain1.dns.fr/domain1.dns.fr.key; } server { listen *:443 ssl http2; server_name domain2.dns.fr; charset utf-8; location / { # redirect on apache instance reconfigured on port 7000 for test without php-fpm installation proxy_pass http://localhost:7000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-for $remote_addr; port_in_redirect off; proxy_redirect off; } ssl on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache shared:SSL:20m; ssl_session_timeout 60m; ssl_prefer_server_ciphers on; ssl_certificate /root/.acme.sh/domain2.dns.fr/domain2.dns.fr.cer; ssl_certificate_key /root/.acme.sh/domain2.dns.fr/domain2.dns.fr.key; }
/etc/hosts配置
127.0.0.1 localhost 151.80.129.173 vpsXXXXX.ovh.net vpsXXXXX
DNS区域配置
domain1.dns.fr -> TLS 0 -> A -> XXX.XXX.XX.XX domain2.dns.fr -> TLS 0 -> A -> XXX.XXX.XX.XX
解决思路与方案
1. 修正Apache VirtualHost绑定逻辑
Apache的<VirtualHost>使用域名绑定(如domain1.dns.fr:443)存在本质问题:SSL握手发生在HTTP请求之前,服务器无法提前识别请求域名,会默认返回第一个匹配Vhost的证书。正确做法是将所有HTTPS Vhost绑定到通用地址,通过ServerName区分域名:
<VirtualHost *:443> ServerName domain1.dns.fr # 其余配置不变 </VirtualHost> <VirtualHost *:443> ServerName domain2.dns.fr # 其余配置不变 </VirtualHost>
同时确保启用mod_ssl和mod_socache_shmcb,添加全局SSL会话缓存配置:
SSLSessionCache "shmcb:/var/run/apache2/ssl_scache(512000)"
2. 修复Apache证书路径错误
domain2的Apache配置中,SSLCertificateKeyFile路径存在拼写错误:/root/.acme.sh/domain2.dns.frdomain2.dns.fr.key,正确路径应为/root/.acme.sh/domain2.dns.fr/domain2.dns.fr.key,这是导致SSL加载失败的直接原因之一。
3. 统一Nginx监听配置
Nginx中domain2启用了http2而domain1未启用,Chrome对HTTP/2的SSL兼容性要求更严格。建议先统一关闭http2测试,或保持两个域名监听配置一致:
server { listen *:443 ssl; # 暂时移除http2 server_name domain2.dns.fr; # 其余配置不变 }
另外,Nginx 1.6.2版本较老,SNI支持存在兼容性问题,建议升级到1.14+版本以获得更好的SSL协议支持。
4. 验证SNI功能正确性
执行以下命令测试服务器SNI响应:
openssl s_client -connect 你的服务器IP:443 -servername domain1.dns.fr openssl s_client -connect 你的服务器IP:443 -servername domain2.dns.fr
检查返回的证书是否对应正确域名,若返回错误证书,说明SNI配置失效。
5. 统一SSL协议与密码套件
Chrome对SSL协议和密码套件的要求更严格,建议在Apache和Nginx中配置符合现代标准的套件:
Apache补充配置:
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 SSLHonorCipherOrder on
Nginx补充配置:
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
内容的提问来源于stack exchange,提问作者Gawel

