2

My nginx instance is behind a SSL terminated load balancer, and I want all urls to hit https endpoints, which means http to be redirected to https.

All is well when urls have a trailing slash. They all get redirected nicely:

#!/bin/sh

do_curl() {
   echo "\n$ do_curl $1"
   curl -L -s -D - "$1" -o /dev/null | grep -iE 'Location|HTTP/|server'
}

$ do_curl https://example.com/
HTTP/2 200

$ do_curl http://example.com/foo/
HTTP/1.1 301 Moved Permanently
Location: https://example.com/foo/
HTTP/2 200

$ do_curl https://example.com/foo/
HTTP/2 200

But when the same urls have no trailing slash, nginx's try_files seems to be issuing a http redirect always: bad.png

Here's my nginx vhost.conf:

server {
    listen 80;
    root /app/;
    index index.html index.htm;

    # This 'if' block is only needed because my SSL-terminated Load balancer proxies both http and https to nginx.
    # If my Load balancer only proxied https to nginx, and dropped http, this 'if' block can be omitted.
    if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

How do I get nginx's try_files to redirect directly with the https $scheme when it hits the $uri/ parameter (2nd parameter in my try_files above) and successfully finds a file matching $uri/<index> (where index is defined by the index directive in the nginx config above)?

I searched similar questions such as here, here, or here but still could not find anything remotely relevant.

L. J.
  • 56
  • 7
  • 2
    ```try_files``` will never *redirect*, it will always *rewrite*. That ```server``` you defined is listening on *http*. Make it always redirect using ```return```. Define another ```server``` that listens on *https*. – Florin Asăvoaie Feb 26 '19 at 03:07
  • thanks @RichardSmith. That link answered it. I posted an answer explaining the nature of my question, and how your answer in that link had the solution I needed. – L. J. Mar 11 '19 at 02:40

1 Answers1

2

As @Florin pointed out in the comments of the question, try_files only performs rewrites. So I went back and omitted the try_files block in my vhost.conf and true enough, I got back the very same behavior where https urls with no trailing slash get redirected to its http trailed counterpart.

Solution

Instead, my question title should have been more like 'How to prevent nginx redirecting from HTTPS to HTTP', which would then be a duplicate question of How to prevent nginx redirecting from HTTPS to HTTP on AWS? that @Richard pointed out in his comment on my question, and which he answered.

Coincidentally, my circumstances and question are in fact identical to those in that question. In his answer, @Richard points out that the best way to mitigate the problem where nginx assumes the same $scheme as the requester (i.e. SSL terminated Load balancer) would be to do a replacement of http with https in the Location header at the point of the Load balancer, which was not possible for me. He then goes on to describe three ways when performing redirects where the $scheme would be https.

Of the three solutions, the one that worked for me was to use absolute_redirect off;. This prevented nginx from using the wrong $scheme that it used in redirects.

Now, my vhost.conf would just have to be:

server {
    listen 80;
    root /app/;
    index index.html index.htm;

    absolute_redirect off;

    # This 'if' block is only needed because my SSL-terminated Load balancer proxies both http and https to nginx.
    # If my Load balancer only proxied https to nginx, and dropped http, this 'if' block can be omitted.
    if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri;
    }
}
L. J.
  • 56
  • 7