Nginx 反向代理到 Heroku 的 SSL 握手失败

问题描述 投票:0回答:5

不幸的是,我不是一个系统管理员,并且遇到了一个让我头撞墙的问题。

简短的故事是,我在 EC2 (Ubuntu 14.04.4 LTS) 上运行 Nginx,以 (a) 托管我公司的营销网站(https://example.com,顺便说一句是 Wordpress)和 (b) 提供服务对于某些路径,作为运行在 Heroku (https://app.example.com) 上的 Rails 应用程序的反向代理。 我们对 example.com 和 app.example.com 使用相同的 SSL 证书。所有这些在 8-10 个月内都运行良好,但我最近从 Heroku 的付费 SSL 插件切换到新的免费 SSL 产品,现在我们的反向代理被破坏了。

在检查 Nginx 错误日志时,我看到以下内容:

SSL_do_handshake() 失败(SSL:错误:14094438:SSL 例程:SSL3_READ_BYTES:tlsv1 警报内部错误:SSL 警报编号 80) 当 SSL 与上游握手时,客户端:ipaddress1,服务器: example.com,请求:“GET /proxiedpath/proxiedpage HTTP/1.1”, 上游:“https://ipaddress2:443/proxiedpath/proxiedpage”,主机: “example.com”

我尝试四处寻找一些额外的指导 - 我升级了 Nginx (1.10.1) 和 OpenSSL (1.0.2h),但没有成功。 我怀疑这个问题可能是由于 Heroku 在新的免费 SSL 功能中使用了 SNI (https://devcenter.heroku.com/articles/ssl-beta),但无法确定为什么会出现这种情况有问题。

我对这一点的探索还有几点:

  • 当我切换到新的免费 Heroku SSL 时,我按照文档的指示将 app.example.com DNS 记录更改为指向 app.example.com.herokudns.com。 该应用程序可以通过 app.example.com 正常访问,当我在 app.example.com 和 app.example.com.herokudns.com 上运行 nslookup 时,我会得到相同的 IP 地址。 不过……

  • 我无法通过 nslookup 返回的 IP 地址或 app.example.com.herokudns.com 访问该应用程序。 我怀疑这是正常的并且是预期的,但不知道到底为什么会这样。 还有...

  • 从 nslookup 返回的 IP 地址与上面日志错误消息中引用的 IP 地址(“ipaddress2”)不同。 事实上,“ipaddress2”在整个日志中并不一致 - 它似乎定期更改。 再说一次,我知道的东西不够多,无法知道我不知道的事情……Heroku 这边的负载平衡?

最后,我的 Nginx 反向代理在 nginx.conf 中配置如下:

http {

    client_max_body_size 500M;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    server_names_hash_bucket_size 64;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_disable "msie6";

    server {

        listen 443 default_server;
        server_name example.com;

        root /usr/share/nginx/html;
        index index.php index.html index.htm;

        ssl on;
        ssl_certificate mycompanycert.crt;
        ssl_certificate_key mycompanykey.key;

        ssl_session_timeout 5m;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
        ssl_prefer_server_ciphers on;

        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;

        location / {
            try_files $uri $uri/ /index.php?q=$uri&$args;
        }

        location ^~ /proxiedpath/ {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto https;
            proxy_pass https://app.example.com/proxiedpath/;
        }

    }

}

非常感谢任何帮助 - 非常感谢!

ssl heroku nginx configuration reverse-proxy
5个回答
104
投票

我今天解决了这个问题,并想发布解决方案,以防其他人遇到同样的问题。

事实证明,问题毕竟与SNI有关。我在 nginx.org 上找到了这张票:

https://trac.nginx.org/nginx/ticket/229

这让我找到了 proxy_ssl_server_name 指令:

http://nginx.org/r/proxy_ssl_server_name

通过在配置中设置为“on”,您将能够使用 SNI 代理到上游主机。

感谢所有提出评论和建议的人!


16
投票

请尝试添加

proxy_ssl_server_name on

location ^~ /proxiedpath/ {
    proxy_ssl_server_name on;
 }

13
投票

请注意,Heroku 强加的一个相关条件是 HOST 字段必须与自定义域名匹配。

因此,除了

proxy_ssl_server_name
之外,您可能还想设置一行,例如:

proxy_set_header Host mycustomdomain.com;

当然,这只适用于传入服务器的主机字段与您的服务器所在的域不同的情况。

您得到的具体错误是:

SSL 证书错误

SSL 连接、其证书和/或包含的 HTTP 请求之间存在冲突信息。


0
投票

只是想插话说,经过几天的头撞桌子,我终于解决了我的问题。想将其发布在这里,以防对其他人有帮助。

我的问题是我只配置了服务器证书和密钥,在 https://www.ssllabs.com 上运行测试后,它报告证书链不完整。我将服务器证书更改为完整链,我的问题现已解决。

希望能帮助其他有同样处境的人。


0
投票

如果有人遇到同样的问题并且上述指令还不够,您将需要使用“proxy_ssl_name name” - https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_name:

proxy_ssl_server_name 开启; #强制的 proxy_ssl_protocols TLSv1.3; #有时需要 proxy_ssl_name myfqdn.com;

为什么? 有时“proxy_set_header 主机 myfqdn.com;”不足以满足上游组服务器的SNI。

© www.soinside.com 2019 - 2024. All rights reserved.