Catch-all redirection of domains with nginx
How to set nginx up to redirect wildcard domains to a single https site.
So today I set up nginx to redirect all traffic trying to connect to *.domain.com over to domain.com via https.
Non-SSL redirection is easy-peasy
The first bit is easy. I'm sure I'd done it before, essentially you simply tell the server .domain.com
to respond with a 301 to where you want it to go, thusly in <site>.conf
:
server {
listen 80;
listen [::]:80;
server_name .example.com;
return 301 https://example.com$request_uri;
}
I learned here, that .domain.com
is shorthand for *.domain.com
and also plain old domain.com
, so I only need to do this once to route anything coming in to https. I'm also forcing the target domain to where I want it.
It's also important to note that nginx seems to figure out request routing in the order they are in the config file, so this entry needs to come after any valid definitions.
With SSL it's only a tiny bit harder
So, SSL. Well here you need to authenticate yourself to the requestor before passing your 301. It's obvious but took me a minute to figure out that copy-paste wouldn't just work here, you'll get certificate errors.
In the end I created a wildcard LetsEncrypt cert and a plain domain cert, I use the wildcard to secure the redirection and the other for the site. I did it this way because I created the wildcard without the domain in the SAN list, so I can't use it in both places. Maybe that can be done, maybe not. I will look into this in the future.
Essentially I just create a second server in the site config to catch, secure, and redirect the request to the main site. Here it's important to use *.domain.com
in the server_name
because otherwise you'll catch also your target domain, and just loop round and round. I'm quietly proud I figured that out without breaking things :)
so, in the config file:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /srv/web-fe/<domain>/system/nginx-root; # Used for acme.sh SSL verification (https://acme.sh)
ssl_certificate /etc/letsencrypt/live/<domain>.com-0001/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<domain>.com-0001/privkey.pem;
server_name *.<domain>.com;
return 301 https://<domain>.com$request_uri;
}
quick nginx -t && systemctl restart nginx
and you're off the the races