Redirect Every Subdomain to the Same Subdomain on a Different Host with Nginx
The title is unfortunately the most succinctly I can put the problem. At work
I have a bunch of websites under <projectname>.temp.example.org
where temp.example.org
is the domain under which we collect all kinds
of temporary tests, interactive mockups and the like.
However, we also own example.com
, which is our primary company
website. This means I'm very used to typing out example.com
, which
in turn means I often mistype <projectname>.temp.example.org
as <projectname>.temp.example.com
(note the top-level domain.)
This wouldn't be too bad, if we hadn't set up nginx so that all traffic to
*.example.com
is redirected to www.example.com
because we
want mistyping customers to get to the landing page even if they slip up badly.
I eventually got tired of ending up on the company landing page when mistyping the domain of an internal prototype, so I wanted to find a fix for a pretty odd problem.
So we could easily imagine specifying an A record for *.temp.example.com
pointing to a server running Nginx, and in that Nginx configuration specify a server
block like
server {
listen 80;
server_name *.temp.example.com;
return 302 $scheme://???.temp.example.org$request_uri;
}
The problem, as the attentive reader might have spotted, is that we don't quite know which domain to redirect to. Which subdomain did the user try to visit? We might be able to extract this with some sort of variable binding magic, but there is an easier solution.
Nginx + regexes = love
It turns out Nginx allows you to specify regexes pretty much anywhere in its configuration.
You can even specify your server_name
with regexes. And if you
include a named capture group, the matching group in the regex will get bound to
a variable with the name you specify. So we could write our redirect server as
server {
listen 80;
server_name ~^(?<subdomain>[^.]+)\.temp\.example\.com$;
return 302 $scheme://$subdomain.temp.example.org$request_uri;
}
and now we get a $subdomain
variable we can use in the redirect!
Fancy that.