41

I'm building a proxy for an internal API to allow clients to connect without having to have the self-signed certificates installed.

Clients (built, owned and used only internally) will connect over SSL to the nginx box, where I'm using XSendfile to validate credentials at the application level (a rails app). If the credentials are valid, the connection is passed back up to nginx where it uses proxy_pass to send the connection onto the upstream server.

Now this works great for standard http connections, but I'm trying to figure out how to add our certificates into the mix.

This question is almost identical to this one, but with awkward certificate requirements.

Is this even possible with nginx? Is there a better solution?

I'd also settle for http from client -> nginx, and self-signed certificate from nginx to the API.

simonmaddox
  • 560
  • 1
  • 4
  • 7

3 Answers3

40

For anybody stumbling across this question that wants to use nginx you can set this up like any normal proxy, and to accept a self-signed certificate from the backend you need to provide the exported pem certificate (and perhaps a key) and set ssl verification off. For example:

...

server {
    listen       10.1.2.3:80;
    server_name  10.1.2.3 myproxy.mycompany.com;

    location / {
         proxy_pass                    https://backend.server.ip/;
         proxy_ssl_trusted_certificate /etc/nginx/sslcerts/backend.server.pem;
         proxy_ssl_verify              off;

         ... other proxy settings
    }

If your secure back end is using Server Name Identification SNI with multiple hosts being served per IP/Port pair you may also need to include proxy_ssl_server_name on; in the configuration. This works on nginx 1.7.0 and later.

shonky linux user
  • 1,163
  • 10
  • 15
  • 5
    `proxy_ssl_server_name on;` was all I needed to get this working when proxying traffic to a host on Google App Engine using its built-in Google-managed SSL! (This isn't a self-signed cert or anything, so it just needed that one line). Thanks for the great tip. – XP84 Sep 09 '18 at 05:29
  • I get 'no "ssl_certificate" is defined for the "listen ... ssl" directive' if I don't use ssl_certificate. Is it possible to proxy SSL without providing the upstream certificate ? – Damien Sep 13 '18 at 12:26
  • Comment is off topic as this is about proxying http connecting to upstream https. If you want to proxy https then it is probably better addressed as a separate question. The quick and short answer is No Nginx cannot "listen" to a https port without a certificate and private key. – shonky linux user Sep 14 '18 at 00:55
  • 3
    If you set "proxy_ssl_verify off" then SSL issues will be ignored at all (and proxy_ssl_trusted_certificate is not used). To validate certificate from backend.server.ip the proxy_ssl_verify should be "on". See http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_verify See also https://stackoverflow.com/questions/36507852/force-nginx-to-verify-upstream-certs – Maksym Anurin Mar 26 '21 at 12:43
  • @MaksymAnurin the question and answer is specifically about self signed certificates that by design are not validated with a CA. Of course if you are doing something different to the OP and proxying to a public HTTPS address with a CA validated certificate then by all means set verification on. – shonky linux user Apr 05 '23 at 05:58
7

I think you probably want something like this (obviously simplified for this example):

worker_processes  1;
events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    upstream backend {
        server mybackendserver:443;
    }

    server {
        server_name localhost;
        listen 443 ssl;
        ssl_certificate /etc/nginx/server.crt;
        ssl_certificate_key /etc/nginx/server.key;
        ssl_verify_client off;
        location / {
            proxy_pass  https://backend;
            proxy_set_header Host $http_host;
            proxy_set_header X_FORWARDED_PROTO https;
        }
    }
}

The only thing you may have to change would be to make the "Host" explicit - if, for example, your proxied host name wasn't the same as the host name used on the nginx proxy server.

Jam
  • 89
  • 2
  • From my understanding, the ssl_certificate and ssl_certificate_key parameters refer to the *client* connection, not the upstream connection. Is that the case? – simonmaddox Dec 14 '11 at 21:31
  • 2
    From what I understand, yes. In this example, the certificate the client sees is the one provided by nginx. nginx sees (and verifies? I'm not sure...) the one provided by the server, but doesn't pass it through to the client. – Jam Dec 14 '11 at 21:33
5

For anyone that comes across this in the future, I ended up not using nginx for this.

Instead, I ended up using stunnel in "client mode". Very easy to set up, and does exactly what I need.

simonmaddox
  • 560
  • 1
  • 4
  • 7