How do I properly configure SSL on the backend between nginx and an app?
I am trying to configure re-encryption on a backend, so that traffic between nginx and the upstream app is encrypted separately from traffic between the user and nginx. For the purpose of a test example, I am using this: https://github.com/jlengstorf/tutorial-deploy-nodejs-ssl-digitalocean-app.git. I have read many threads, but I always end up getting Error 502: Bad Gateway. Also, I am not sure how paranoid it is to even bother with this. Everything is on one host, but I will be running several services and my reasoning is that any one of them might have exploits and that risk could be mitigated by each app communicating with nginx under a different certificate. To keep the example simple, I just used one key for Everything. Obviously if I were doing this for real I would make a new certificate for each instance of re-encryption. I'm new to web hosting and thinking about security, so please let me know if I said anything cringy above.
mydomain.conf
# HTTP — redirect all traffic to HTTPS
server {
listen 443 ssl;
server_name 127.0.0.1:5000;
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
root /var/www/html;
index test_index.html;
return 301 https://$host$request_uri;
}
# HTTPS — proxy all requests to the Node app
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mydomain.com;
root /var/www/html;
index test_index.html;
# Use the Let’s Encrypt certificates
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
# Include the SSL configuration from cipherli.st
include snippets/ssl-params.conf;
location /app {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass https://localhost:5000/;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
proxy_ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
}
The corresponding error from /var/nginx/error.log:
2020/10/22 16:17:13 [error] 11311#11311: *1 SSL_do_handshake() failed
(SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
) while SSL handshaking to upstream, client: xx.xxx.xx.xx, server: the
3guys.com, request: "GET /app HTTP/1.1", upstream: "https://127.0.0.1:
5000/", host: "mydomain.com"
In ssl-params.conf snippet included in the nginx site conf, I set to use all versions of TLS that I am aware of:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
In general there is absolutely no security benefit to encrypting traffic between services running on the same host.
(Localhost traffic can only be intercepted by an attacker that has full access to the server. When they can do that they can already access all data stored on your server directly (from the file system) and won't need to bother with intercepting traffic.)
Your error messages seems to indicate that you tried converting your existing connection to your app server by switching from
proxy_pass http://localhost:5000/;
To
proxy_pass https://localhost:5000/;
Without actually converting the backend to actually run https.
Generally you also cannot run http and https services concurrently on the same port.
To connect to your Node.js application over https you first need to configure that it actually loads a certificate and starts supporting https.
Then proxy_ssl_verify on
is probably not good idea either in combination with proxy_pass https://localhost
as you cannot get public TLS certificates for the localhost
domain name.