Does order of lines matter in Nginx?

I have a server file like this

server {
listen 80;
server_name subdomain.example.com;

return 301 https://$server_name$request_uri;

location /.well-known/acme-challenge {
        root /var/www/letsencrypt;
    }
}

Now when I try sudo letsencrypt renew. It throws up and error saying can't find .well-known/acme-challenge. But as soon as I commented the return 301 line restarted the server and It worked.

Now I want to retest it putting the location first and not commenting the return 301 statement but it says certificate not due for renewal.So the question is does order in which the file is read, does it matter? and it won't automatically renew because of this reason for me, those who do renewal how do you handle this situation?


In this case, it isn't so much the ordering (a good explanation of how location and regex is evaluated can be found here: https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms).

For things like location blocks, the short version is best match wins, rather than the first match.

In your case, however, order counts because you use return. Per https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return:

Stops processing and returns the specified code to a client. The non-standard code 444 closes a connection without sending a response header.

The key here is that a return immediately stops processing/evaluation, so what is happening is that nginx isn't looking at anything below return.

So you just need to move that return clause below your location block.

As for testing, I would try adding --test-cert to your commandline (see https://certbot.eff.org/docs/using.html#certbot-command-line-options).

That should avoid the 'problem' you are having when trying to use their production server, which reports you have a valid cert and do not need a new one right now.


You should include your return directive in a location block, then the normal location block matching rules are used:

server {
    listen 80;
    server_name subdomain.example.com;

    location / {
        return 301 https://$server_name$request_uri;
    }

    location /.well-known/acme-challenge {
        root /var/www/letsencrypt;
    }
}