Two Wrongs

Redirect Every Subdomain to the Same Subdomain on a Different Host with Nginx

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.