I'm having a weird issue with an nginx configuration. I have the following server block:
server {
listen 80;
listen [::]:80;
server_name stats.example.com;
root /usr/share/nginx/html;
location = /foobar {
return 403;
}
# ACME challenge configuration for Letsencrypt
location ^~ /.well-known/acme-challenge/ {
try_files $uri =404;
}
return 301 https://stats.example.com$request_uri;
}
This is a simple block that should redirect any non-https traffic to it's https counterpart. I tried to create an exception for the "ACME Challenge" that the Certbot for Letsencrypt uses to validate a domain prior to issuing a certificate. I have a similar setup on various servers and it usually works without problems, but on this particular server, it doesn't seem to parse the location blocks properly. To verify the server block I also added the custom /foobar
location, just to make sure that when I hit that it should throw a 403.
But both location blocks do not seem to work. Whenever I request something from one of them, it returns the 301 to the https URL as set in the last line of the server block:
% curl -I 'http://stats.example.com/foobar'
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Mon, 01 May 2017 11:25:10 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://stats.example.com/foobar
It does the same for the ACME challenge URLs, which is why I cannot issue a certificate for this domain using Certbot. What am I missing here? Why are the location blocks not returning the 403 or the actual file (or 404)? Why is the 301 enforced here for all URLs?
I figured out the problem after debugging and trying some more solutions. Apparently the 301 rule is parsed by nginx prior to any location block handling, thus the 301 was always the first and final rule to be applied to all URLs. I created a separate "catch-all" location block that serves the 301 if no other locations match, so my final configuration now looks like this:
I was now able to successfully issue the certificate using Certbot.