I have a website served by nginx behind an AWS ELB Load Balancer. Only HTTPS is enabled on the load balancer.
Requesting individual files, or directories with a trailing slash, work fine. However, requesting directories without a trailing slash don't work.
The reason is, when I request the directory without the trailing slash, nginx does a redirect to the path with the trailing slash (that's OK), but it also changes from HTTPS to HTTP. The load balancer is configured to only allow HTTPS, so that doesn't work (timeout).
On the nginx logfile, I can see that the request reaches nginx, and that it's nginx that responds with the 301 Permanent Redirect (so it's not e.g. a problem with the load balancer setup).
10.100.10.15 - - [24/Nov/2017:15:41:08 +0000] "GET /admin HTTP/1.1" 301 178 "-" "Wget/1.18 (darwin16.0.0)"
When I request the URL via curl
I see the redirect:
$ curl -v https://example.com/admin
* Trying 1.2.3.4...
* TCP_NODELAY set
* Connected to example.com (1.2.3.4) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: example.com
* Server certificate: Amazon
* Server certificate: Amazon Root CA 1
* Server certificate: Starfield Services Root Certificate Authority - G2
> GET /admin HTTP/1.1
> Host: example.com
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Date: Mon, 27 Nov 2017 09:19:05 GMT
< Content-Type: text/html
< Content-Length: 178
< Connection: keep-alive
< Server: nginx
< Location: http://example.com/admin/
< X-UA-Compatible: IE=Edge
<
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host example.com left intact
My nginx config file is just
server {
root /var/www;
}
The /etc/nginx/nginx.conf is here.
I have tried server_name_in_redirect off
but it did not make any difference.
I would like to avoid putting the hostname in the config file, because this is packed into a Docker image which is then deployed on different hosts (QA, Prod, etc.).
I would like nginx to do this redirect, but stay on HTTPS. What can I do?
The best place to fix the problem is where the SSL connection is terminated. If it was running
nginx
, you would use aproxy_redirect
statement to maphttp
tohttps
in theLocation
header. I don't know AWS ELB so cannot comment on how to fix it there.Certain circumstances causes
nginx
to respond with a redirect, and it assumes that the scheme is the same as the scheme used to connect to it (i.e. from AWS ELB). AFAIK there are three ways to mitigate the problem in the back-endnginx
server.1) From version 1.11.8 onwards, the
absolute_redirect off;
statement will cause theLocation
header to use a relative URL, which means that the scheme and domain name are missing.See this document for more.
2) Inhibit the behaviour of appending a trailing
/
to directories by using atry_files
statement:See this document for more.
3) Fix the problem with an explicit
return
statement.See this document for more, and this caution on the use of
if
.Try this
If it doesn't work please edit your question to include whatever's in basic.conf and nginx.conf. Also do a curl showing the problem, including the response headers and the single corresponding Nginx access log file.
You can try to use a "evil if" sentence:
Not tested on AWS, however I solved with this line in each
location
block: