【问题标题】:nginx proxy based on host when using https使用 https 时基于主机的 nginx 代理
【发布时间】:2013-08-21 14:23:05
【问题描述】:

我需要使用 Nginx 作为 SSL 代理,根据子域将流量转发到不同的后端。

我似乎到处都应该定义多个“服务器{”部分,但这不适用于 SSL。这样做我将始终在第一个虚拟主机中处理 SSL,因为在您处理 https 流量之前,服务器名称是未知的。

场景:

  • 一个 IP 地址
  • 一个 SSL 通配符通配符
  • 需要访问的多个后端,如下所示:

    https://one.mysite.com/ -> http://localhost:8080
    https://two.mysite.com/ -> http://localhost:8090
    

Nginx 说“如果”是邪恶的:http://wiki.nginx.org/IfIsEvil,但我还能做什么?

我已经尝试过了,但它不起作用,我收到 500 错误但错误日志中没有任何内容。

    server {
    listen 443;
    server_name *.mysite.com;

    ssl on;
    ssl_certificate ssl/mysite.com.crt;
    ssl_certificate_key ssl/mysite.com.key;

    location / {
        if ($server_name ~ "one.mysite.com") {
            proxy_pass http://localhost:8080;
        }
        if ($server_name ~ "two.mysite.com") {
            proxy_pass http://localhost:8090;
        }
    }

有没有人用 Nginx 做到这一点?任何帮助/替代方案,链接,将不胜感激。

【问题讨论】:

    标签: ssl https nginx proxy wildcard-subdomain


    【解决方案1】:

    根据http://www.informit.com/articles/article.aspx?p=1994795,您确实应该有两个“服务器”部分,有两个不同的服务器名称。 在每一个中,您都应该包含您的 ssl_* 指令。

    【讨论】:

    • 这有一个问题,让我用一个例子来解释一下:如果你有两个“服务器”部分,在端口 443 上监听 SSL,Nginx 将使用第一个虚拟主机进行 SSL 解密,因为它仍然不知道您拥有什么域。一旦域可以匹配,它将执行正确虚拟主机的指令,但 SSL 解密将发生在错误的虚拟主机中。 JAVA 和 curl(可能更多 SSL 客户端)将失败,因为主机名和实际使用的域不匹配。
    • 这是 SNI 修复的问题。现在大多数合理的现代浏览器都支持它,这让生活变得更加简单。
    【解决方案2】:

    我找到的解决方案基本上是在“服务器”块之外定义 SSL 选项和 SSL 证书:

    ssl_certificate ssl/mysite.com.crt;
    ssl_certificate_key ssl/mysite.com.key;
    ssl_session_timeout  5m;
    ssl_protocols        SSLv3 TLSv1;
    ssl_ciphers          ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+EXP;
    ssl_prefer_server_ciphers   on;
    
    server {
        listen 80;
        server_name *.mysite.com;
        rewrite ^ https://$host$request_uri? permanent;
    }
    server {
        listen 443 ssl;
        server_name one.mysite.com;
    
        ssl on;
    
        location / {
            proxy_pass http://localhost:8080;
        }
    }
    server {
        listen 443 ssl;
        server_name two.mysite.com;
    
        ssl on;
    
        location / {
            proxy_pass http://localhost:8090;
        }
    }
    

    关键点:

    • "ssl 开启;"是唯一需要在侦听 https 的“服务器”块内的东西,您也可以将其放在外面,但是什么会使侦听端口 80 的“服务器”块使用 https 协议而不是预期的 http。
    • 因为“ssl_certificate”、“ssl_ciphers: 和其他“ssl_*”在“server”块之外,Nginx 在没有 server_name 的情况下执行 SSL 卸载。这是它应该做的,因为 SSL 解密不能基于任何主机名,因为在此阶段 URL 已加密。
    • JAVA 和 curl 现在不会失败。没有 server_name - 主机未匹配。

    【讨论】:

    【解决方案3】:

    简短的回答是使用Server Name Indication。默认情况下,这应该在常见的浏览器和 cURL 中有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-24
      • 2017-07-15
      • 2018-10-30
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      相关资源
      最近更新 更多