Nginx proxying http to https with client certificate

certificatehttpsnginxPROXYssl

We have an application that is not client-certificate aware and must consume a client-certificate authenticated web-service. To fix this, we're trying to use Nginx to reverse proxy a local (http) url which our application will hit to the remote HTTPS and client certificate authenticated service. The config is below:

location /secure/api/ {
    proxy_pass https://secure.webservice.com/secure/api/;
    proxy_ssl_certificate     /etc/ssl/api-client.crt;
    proxy_ssl_certificate_key /etc/ssl/api-client.crt.key;
    proxy_ssl_verify off;
}

When trying to connect to the reverse-proxy url (http://our.proxy.com/secure/api/) it just sits there and spins. If we test the connection from the proxy with wget or openssl, we can connect successfully.

Here's a snippit from nginx/error.log:

2015/08/25 15:33:56 [info] 29810#0: *57 client closed connection while waiting for request, client: x.x.x.x, server: 0.0.0.0:80
2015/08/25 15:34:05 [info] 29810#0: *53 epoll_wait() reported that client prematurely closed connection, so upstream connection is closed too while reading response header from upstream, client: x.x.x.x, server: our.proxy.com, request: "GET /secure/api/ HTTP/1.1", upstream: "https://y.y.y.y:443/secure/api/", host: "our.proxy.com"

The 'client closed connection' lines are concerning and I'm not sure which side of the connection is closing the connection; client->proxy or proxy->upstream.

Also, it's worth noting that tcpdump does show that nginx is initiating a connection to secure.webservice.com over 443.

I feel like the first step in figuring this out is deciphering which side of the connection is closing and why…thoughts?

Thanks in advance.

Note: x.x.x.x is a local (private) ip, y.y.y.y is an internet (public) ip.

Best Answer

There are a few articles regarding this configuration here and here. We also use client SSL certificates with Nginx and have the following working config with http/https redirect :

#config for upstream app servers (not aware of SSL)
upstream appcluster {
    server X.X.X.1:8000;
    server X.X.X.2:8000;
}
# http-to-https redirect 
server {
       listen         80;
       server_name    localhost;
       return         301 https://$server_name$request_uri;
}
# resolves SSL & client SSL here
server {
    listen      443;
    server_name localhost;
    ssl on;
    ssl_certificate    <path to cert.pem>;
    ssl_certificate_key <path to cert.key>;
    ssl_client_certificate <path to CA authority to resolve client ssl - this is ca.crt>;
    ssl_verify_client on;
    ...
    # after ssl resolution forward to upstream cluster
    location /restService {
        ... 
        proxy_pass http://appcluster/restService;
    }
}