Let's Encrypt using webroot on nginx with an SSL redirect

I have a web site being served with nginx with the following requirements:

  1. Redirect all http -> https
  2. Zero-downtime Let's Encrypt certificate renewal

In order to satisfy (1) I have a small http->https redirect in my nginx config. In order to satisfy (2) I'll need to modify said config so that I can use the webroot Let's Encrypt authentication method.

I'm trying to figure out the optimal solution that will satisfy both requirements. I've come up with the following, which works.

Before:

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

After:

server {
    listen 80;
    server_name example.com;
    location ~ /\.well-known\/acme-challenge {
        root /usr/share/nginx/html;
        allow all;
    }
    if ($request_uri !~ /\.well-known) {
        return 301 https://example.com$request_uri;
    }
}

However, I was hoping to figure out another way of doing it. The reasons for that are:

  1. if is evil. Might not be such a big deal in this case because this is just the http->https redirect, which should be very low-traffic.

  2. More importantly, avoiding the if would make it easier to bolt on webroot authentication to all of my sites running behind nginx since I could just plop that location directive in a .conf that I could then include willy-nilly inside all of my little http->https redirect blocks.

In this question, Alex gives an example using a bare return statement, but that doesn't work for me (nginx -t complains with nginx: [emerg] invalid number of arguments in "return" directive in /etc/nginx/...).

Is there a better way of doing this? Or is my solution above as good as it gets?


You can replace the if with a normal location:

server {
    listen 80;
    server_name example.com;
    location /.well-known/acme-challenge {
        root /usr/share/nginx/html;
        allow all;
    }
    location / {
        return 301 https://example.com$request_uri;
    }
}

Reason: the location with the longest matching prefix is selected and remembered.

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

Source: Nginx Docs