54

I try to configure an Nginx server as a reverse proxy so the https requests it receives from clients are forwarded to the upstream server via https as well.

Here's the configuration that I use:

http {

    # enable reverse proxy
    proxy_redirect              off;
    proxy_set_header            Host            $http_host;
    proxy_set_header            X-Real-IP       $remote_addr;
    proxy_set_header            X-Forwared-For  $proxy_add_x_forwarded_for;

    upstream streaming_example_com 
    {
          server WEBSERVER_IP:443; 
    }

    server 
    {
        listen      443 default ssl;
        server_name streaming.example.com;
        access_log  /tmp/nginx_reverse_access.log;
        error_log   /tmp/nginx_reverse_error.log;
        root        /usr/local/nginx/html;
        index       index.html;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_certificate /etc/nginx/ssl/example.com.crt;
        ssl_certificate_key /etc/nginx/ssl/example.com.key;
        ssl_verify_client off;
        ssl_protocols        SSLv3 TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers RC4:HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;


        location /
        {
            proxy_pass  https://streaming_example_com;
        }
    }
}

Anyway, when I try to access a file using reverse proxy this is the error I get in reverse proxy logs:

2014/03/20 12:09:07 [error] 4113079#0: *1 SSL_do_handshake() failed (SSL: error:1408E0F4:SSL routines:SSL3_GET_MESSAGE:unexpected message) while SSL handshaking to upstream, client: 192.168.1.2, server: streaming.example.com, request: "GET /publishers/0/645/_teaser.jpg HTTP/1.1", upstream: "https://MYSERVER.COM:443/publishers/0/645/_teaser.jpg", host: "streaming.example.com"

Any idea what I am doing wrong?

bschlueter
  • 107
  • 4
Alex Flo
  • 1,711
  • 3
  • 17
  • 23
  • Did you try without using `upstream` module by directly putting the WEBSERVER_IP in the proxy_pass directive to see if you get the same error ? – Benoit Mar 20 '14 at 11:34
  • No, I didn't try this but as explained below the option `proxy_ssl_session_reuse off;` made it work as expected. – Alex Flo Mar 28 '14 at 05:52
  • 11
    Please remove SSLv3 from supported protocols. It's not secure and you should not use it: ssl_protocols SSLv3 – user220703 Jul 01 '15 at 08:16

3 Answers3

38

I found what was the error, I needed to add proxy_ssl_session_reuse off;

Alex Flo
  • 1,711
  • 3
  • 17
  • 23
  • 1
    Thank you. For those out there who might still have issues after using this config, remember to use https instead of just http at the beginning of the URL given as a parameter in proxy_pass. Otherwise, nginx won't encrypt the traffic sent to upstream and you'll still get the same error message. – Lucio Mollinedo May 14 '19 at 17:21
  • According to the doc, only if you see the errors “SSL3_GET_FINISHED:digest check failed” appear in the logs, then try disabling session reuse. http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_session_reuse The better approach is to turn off SSLv3 protocl via `ssl_protocols` directive. – Devy Apr 06 '20 at 18:21
27

In my case, I was trying to reverse proxy a website behind Cloudflare. I got the same error in /var/log/nginx/error.log. I tried many solutions and this one worked for me:

proxy_ssl_server_name on;

See nginx documentation:

Enables or disables passing of the server name through TLS Server Name Indication extension (SNI, RFC 6066) when establishing a connection with the proxied HTTPS server.

If a server terminates the TLS connection first with a server-global TLS certificate, it can look at the HTTP Host header to figure out which user/application should receive the HTTP request. But if the server serves domains with different TLS certificates (what all CDNs like Cloudflare do), the server needs to know which TLS private-key to use for TLS termination. Therefore it needs to look at the unencrypted TLS SNI header, as the HTTP Host header is still encrypted.

vonox7
  • 103
  • 4
iBug
  • 1,048
  • 2
  • 9
  • 21
  • Thanks. This was same issue I had - my situation was two droplets on Digital Ocean, one which hosted the main domain and a second a subdomain. The main domain droplet was running Nginx and reverse proxying a specific path to the subdomain, which was running Caddy instead. Setting `proxy_ssl_server_name on;` resolved the various issues `SSL_do_handshake() failed` and `no live upstreams while connecting to upstream` on the Nginx server. – Anson VanDoren Jan 21 '21 at 22:52
1

This fully solved the issue for me:

location / {
    proxy_pass https://server2.example.com;
    proxy_set_header Host $host;
    proxy_ssl_name $host;
    proxy_ssl_server_name on;
    proxy_ssl_session_reuse off;
    ...
}

I also had to add proxy_ssl_name in order to make sure that nginx knew what name to pass to the upstream https server.

morganbaz
  • 111
  • 6