19

I'm trying to move from self-signed certificates to Let's Encrypt certificates on my nginx webserver.

Currently, I redirect all requests to http/80 to https/443, which uses a self signed certificate I created a while ago.

Now - from what I understand Let's Encrypt makes a request to port 80 (as I am using the webroot option of certbot). These requests are redirected, which renders the certificate generation unsuccessful.

I tried to achieve this with the following server block, listening at port 80:

server {
        listen  80;     
        server_name     sub.domain.tld;
        server_tokens   off;


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

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

But requests to /.well-known are redirected to https/443 anyways.

How can I redirect all requests from http/80 to https/443, except the requests to /.well-known/?

2
  • 1
    As far as I'm aware, the webroot of certbot option requires plain http.
    – SaAtomic
    May 12, 2017 at 10:28
  • 3
    How did you check redirect? I guess your browser respects HSTS headers for you domain, but let's encrypt bot would ignore it. Check with wget/curl
    – Alexey Ten
    May 12, 2017 at 10:39

2 Answers 2

25

Try this:

server {
    listen  80;     
    server_name     sub.domain.tld;
    server_tokens   off;

    root /var/www/letsencrypt;

    location /.well-known {
        try_files $uri $uri/ =404;
    }

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

Since there was no try_files entry in your virtual server, it didn't know what to do with requests coming to /.well-known.

2
  • 2
    location without try_files just sends file from root directory.
    – Alexey Ten
    May 12, 2017 at 10:37
  • 1
    weird, I have the exact same situation and I dont use try_files and it works perfectly fine for me. In fact I have the exact same config as stated in the question. Only difference is location /.well-known/ instead of location /.well-known (note the trailing slash). So maybe thats where the problem is? May 12, 2017 at 12:50
0

I ran into the same issue, but needed a slightly different solution.

Here's what my server block looked like

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

    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
        try_files $uri =404;
    }

    return 301 https://www.example.com$request_uri;
}

It turns out this is a "pitfall" NGINX dubs the Incorrect return context.

The return directive applies only inside the topmost context it’s defined in. In this example:

server {
   location /a/ {
       try_files test.html =404;
   }

   return 301 http://example.org;
}

A request to /a/test.html will return a 301. To make this work as expected wrap the second block inside a location /:

server {
   location /a/ {
       try_files test.html =404;
   }

   location / {
       return 301 http://example.org;
   }
}

I understand what they mean, but the phrasing makes it a little confusing. I would instead describe the behavior as

The return directive takes precedence over all location blocks defined in the same context.

Wrapping the return in a location / block, as suggested, solved the issue.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .