我有一个 nginx 和不同的子域:
a.mydomain.com
b.mydomain.com
c.mydomain.com
Nginx 有 4 条规则:
1)重写规则:
server {
listen 80
server_name gl.udesk.org;
root /nowhere;
rewrite ^ https://a.mydomain.com$request_uri permanent;
}
2)https规则:
server {
listen 443;
server_name a.mydomain.com;
root /home/a/a/public;
ssl on;
ssl_certificate conf.d/ssl/a.crt;
ssl_certificate_key conf.d/ssl/a.key;
ssl_protocols ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
location ...
}
3)http默认规则:
server {
listen 80 default_server;
return 444;
}
4)https默认规则:
server {
listen 443 default_server;
return 444;
}
如果我启动 nginx 并且:
- 如果我进入浏览器http://a.mydomain.com它会重定向到 https://a.mydomain.com然后它返回错误 107 (net::ERR_SSL_PROTOCOL_ERROR):SSL 协议错误。
- 如果我进入浏览器https://b.mydomain.com我期望它返回错误 444。但它却返回了相同的错误 107 (net::ERR_SSL_PROTOCOL_ERROR):SSL 协议错误。
- 对于所有由 DNS 提供商 CNAME 注册的记录(例如 a、b、c)也是如此
- 所有 http 版本(例如规则 3 - )均按预期工作:
- http://a.mydomain.com重定向到 https:// 版本,
- http://b.mydomain.com和http://c.mydomain.com按照配置返回错误 444。
那么为什么 https 规则nginx配置起来非常棘手,我应该如何正确配置它们才能获得与 http 版本相同的行为?
更新:
创建新证书并添加:
ssl on;
ssl_certificate conf.d/ssl/default.crt;
ssl_certificate_key conf.d/ssl/default.key;
现在可以使用,但我有一个不需要任何 SSL 证书的解决方案。只需重置所有 https(端口 443)子域的所有连接,但https://a.mydomain.com 无需提供证书。
答案1
不要将端口 443 与 SSL 混淆!Nginx 完全与端口无关。您也可以通过端口 80 提供 https。现代 nginx 版本允许
listen 1234 ssl;
那么你就不需要这ssl on;
条线了。
但是如果你想提供 https,你需要指定一个证书。当你的服务器将 http 请求重写为 https 请求时,它就会进入 https。
您收到协议错误,因为 SSL 握手是在任何其他操作之前完成的。因此return 444
未达到目的。并且任何 SSL 握手都需要证书和私钥,以便将证书/私钥对提供给加密算法。
答案2
该return
指令是重写模块的一部分。如果你检查文档,您可能会看到它适用于请求。在 HTTPS 中,只有在握手完成后才能发出请求。
有一个功能请求:https://trac.nginx.org/nginx/ticket/195并提供了解决方法。
server {
listen 443 ssl;
server_name bbb.example.com;
ssl_ciphers aNULL;
ssl_certificate /path/to/dummy.crt;
ssl_certificate_key /path/to/dummy.key;
return 444;
}
答案3
我找到了答案Nginx 文档:
SSL 连接是在浏览器发送 HTTP 请求之前建立的,nginx 并不知道所请求的服务器名称。因此,它可能只提供默认服务器的证书。
因此,您必须将 SSL 连接的默认证书配置为将首先用于请求的 default_server。之后,nginx 将搜索最佳匹配的 server_name 虚拟服务器并使用其配置。
此外,即使支持 SNI,您可能也需要为 default_server 设置 SSL 连接设置,因为匹配的服务器配置中的某些 SSL 设置将被忽略。我还不明白它是如何工作的,但 nginxssl_certificate
从匹配的服务器配置和ssl_protocols
default_server 配置接收到客户端。
从 Nginx 1.19.4 开始,你可以使用ssl_reject_handshake指示:
server {
listen 443 ssl;
ssl_reject_handshake on;
}