NGINX redirect everything except letsencrypt to https

Solution 1:

Well, wasn't the HSTS in my case

server {
    # ...
    location /.well-known/acme-challenge/ {
        # put your configuration here, if needed
    }
    location / {
        return 301 https://$server_name$request_uri;
    }
}

Summary: put the 301 redirect inside the / location

Solution 2:

You have HSTS headers set in your https server block. This means that if you visit your site with https once with your browser, your browser will always connect to your domain with https after the first visit.

This means that you cannot test your configuration with a browser. You need to test it with curl or similar tool that doesn't store HSTS lists.

There is a minor tweak for your configuration, you can use a simple prefix match location /.well-known/acme-challenge for your LetsEncrypt location. nginx will use the most specific match from the location blocks.


Solution 3:

You can create a snippet to use in your config in /etc/nginx/snippets.d/letsencrypt

location ~ /\.well-known/acme-challenge/ {
  allow all;
  default_type "text/plain";
  root /usr/share/nginx/html;
  try_files $uri =404;
  break;
} 

then include it in your location:

server {
  listen 80;
  server_name *.yourdomain.org yourdomain.org;
  location / {
    return 301 https://$host$request_uri;
  }
}

server {
  listen 443 ssl;
  server_name *.yourdomain.org yourdomain.org;
  include snippets.d/letsencrypt;
  ssl_certificate     /etc/letsencrypt/live/yourdomain.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/yourdomain.org/privkey.pem;
  location / {
      # your config for the domain goes here
  }
}
  1. Make sure, the 301 redirect is inside a location block (otherwise it will be called everytime).

  2. Make sure, the redirect leads to a whole domain and not a subdirectory of another domain (like https://yourdomain.org/subdir$request_uri) so the well-known challenge is routed correctly.