System Administration & Network Administration
nginx ssl-certificate certbot
Updated Sun, 10 Jul 2022 08:37:01 GMT

Nginx load balancer and forcing HTTPS


I have an Nginx server being used as a load balancer. I have just installed an SSL certificate with Let's Encrypt and I am now looking into forcing HTTPs. The following is my config:

upstream backend {
   server one.example.com;
   server two.example.com;
}
server {
   server_name example.com;
   location / {
      proxy_pass http://backend;
      proxy_set_header Host               $host;
      proxy_set_header X-Forwarded-Host   $host;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header X-Real-IP          $remote_addr;
      proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
   }
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80;
    server_name example.com;
    return 404; # managed by Certbot
}

https requests are working correctly, but http requests are throwing a 301 Moved Permanently, the access logs show the following:

[07/Feb/2019:15:28:11 +0000] <ip> -> - | POST /api/test HTTP/1.1 | upstream_response_time - msec | request_time 0.000 msec | status: 301
[07/Feb/2019:15:28:11 +0000] <ip> -> <one.example.com IP>:80 | GET /api/test HTTP/1.1 | upstream_response_time 0.007 msec | request_time 0.007 msec | status: 405

(my log format is '[$time_local] $remote_addr -> $upstream_addr | $request | upstream_response_time $upstream_response_time msec | request_time $request_time msec | status: $status'

The return 301 seems to be modifying the request type from POST to GET (which the destination application does not allow). I have very similar setups on non load balanced web servers, all working as expected.

It's also important to note that the final config file was generated by certbot.




Solution

You can't redirect POST with 301 (up to where my knowledge gets). if you want to POST something securely (via https), directly make the POST via https, as if you redirect on your server to https, the POST is not secure until you get there.

Another thing I've seen you can make, is to redirect by 307 and not 301, which looks to preserve the POST, but you loose the "permanent" redirection 301 gets you.

INFO on the second part: https://stackoverflow.com/questions/39280361/nginx-loses-post-variable-with-http-https-redirect

But I would implement the first one, if you have a certificate, POST anything via https.