18

The nginx documentation says that the server_name directive supports regular expressions. I've been banging my head against the wall trying to get even a trivial regex working.

I want http://subdomain.mydomain.com to redirect to http://mydomain.com/subdomain

Here is my code.

server {
  server_name "~^subdomain\.mydomain\.com$";
  rewrite ^ http://mydomain.com/subdomain;
}

Also, potentially noteworthy. Further down in the nginx config file there is a rule:

server {
  server_name *.mydomain.com
  ...
}

What am I doing wrong?

UPDATE:

It has been suggested that I not use regex for this... to offer a little more clarity: the trivial regex was simply for purposes of troubleshooting. The real regex will look more like...

server {
  server_name "~^.*(cvg|cincinnati)\.fakeairport(app)?\.(org|com)$";
  rewrite ^ http://fakeairport.com/cincinnati;
}

server {
  server_name "~^.*(lex|lexington)\.fakeairport(app)?\.(org|com)$";
  rewrite ^ http://fakeairport.com/lexington;
}

So it would be preferable to use regex.

danott
  • 923
  • 1
  • 8
  • 14

5 Answers5

43

To answer an old question to help others

using nginx 1.1.19 you can do the following:

server {
    server_name     ~^(?<subdomain>\w+)\.domainA\.com$;

    location / {
            rewrite ^ https://$subdomain.domainB.com$request_uri permanent;
    }
}

The subdomain before domainA.com is matched and stored in variable $subdomain which then can be used in the rewrite. This rewrites url like xxx.domainA.com to xxx.domainB.com with only one server directive.

Bart
  • 446
  • 5
  • 3
19

Gotta love regex with NGINX!

As I often work with multiple domain-names and I like to keep my configs as clean and rock solid as possible I almost always use regex with nginx.

In this case I've solved it with the following regex:

server {
    listen 80;
    server_name ~^((?<subdomain>.*)\.)(?<domain>[^.]+)\.(?<tld>[^.]+)$;
    return 301 $scheme://${domain}.${tld};
}

What this does is the following: every subdomain.domain-name.tld that points to this server (ip address) is automatically redirected to domain-name.tld.

So for instance www.myexampledomain.com is redirected to myexampledomain.com.

To answer the question, what you could also do is the following:

server {
    listen 80;
    server_name ~^((?<subdomain>.*)\.)(?<domain>[^.]+)\.(?<tld>[^.]+)$;
    return 301 $scheme://${domain}.${tld}/${subdomain};
}

Now mysubdomain.myexampledomain.com is converted into myexampledomain.com/mysubdomain.

Above regex is great as you can throw anything at it that you like and it will convert it for you.

Ottonet
  • 311
  • 2
  • 4
  • 2
    The RegEx captures in `server_name` in your examples are amazingly useful! A fantastic bonus was that I was able dynamically define a shared `root` path by chopping off the subdomain like so: `root /home/www-data/$domain.$tld/;` Your answer uses much more modern techniques and should be updated to the accepted answer. – FactoryAidan Apr 28 '16 at 01:16
5

If you read the server_name matching rules, you'll see that prefix and suffix server_names are checked before regex names, but after exact hostnames. Since *.mydomain.com matches, the regex isn't tested. The fact that it's listed earlier in the config makes no difference. Since you're just trying to match a single hostname with your regex, a simple:

server {
  server_name subdomain.mydomain.com;
  rewrite ^ http://mydomain.com/subdomain$request_uri?;
}

server {
  server_name *.mydomain.com;

  # stuff
}

will work for you.

kolbyjack
  • 17,660
  • 5
  • 48
  • 35
  • The trivial regex was simply for purposes of troubleshooting. Some more details about why I need to use a regex has been added to the original question. – danott Mar 06 '12 at 16:47
  • Ah, I should have realized that. What are you using the suffix domain for? As long as you have it, no regex server will match that suffix. – kolbyjack Mar 06 '12 at 17:16
  • The architecture of our application used to use a ton of subdomains, so it is used as a catch-all to redirect any additional subdomain that doesn't have a specific redirect. – danott Mar 06 '12 at 19:05
  • Is it the only catchall you have? If so, then you could just use the default_server flag on that server's listen instead of matching the suffix, and then you'd be able to use a regex + a map to get your redirect working. – kolbyjack Mar 06 '12 at 21:26
1

Just as a comment. If you want to redirect all subdomain levels to first subdomain level, util when you use a wildcard SSL certificate for example, you could use:

server {
    listen 80;
    server_name ~^(.*)\.(?<subdomain>\w+).mydomain\.com$;
    return          301 https://$subdomain.mydomain.com$request_uri; 
}

server {
    listen 80;
    server_name ~^(?<subdomain>\w+).mydomain\.com$;
    return          301 https://$subdomain.mydomain.com$request_uri;
}

The first is for redirect an http multiple level subdomain to the first subdomain level in https. And the next is for redirect the first level subdomain in http to the same subdomain in https.

Harry Martel
  • 1,207
  • 8
  • 6
1

I know everyone is saying if is evil in nginx config files, but sometimes you can't get around any other way.

server {
      server_name .mydomain.com;

      if ( $host ~ subdomain.mydomain.com ) {
                rewrite ^(.*) http://mydomain.com/subdomain$1;
      }
}
petermolnar
  • 1,626
  • 14
  • 23
  • 2
    You should NEVER use an if when it's not needed. That's just asking for troubles. – MTeck Mar 06 '12 at 22:02
  • 2
    Correct but as you imply, there are situations when it is needed and if configured properly (with rewrite module commands only) it is perfectly safe to use. The problem with "if" is not that it should NOT be used, but that it be used with understanding. – Dayo Mar 07 '12 at 03:53
  • 8
    I'm really getting tired of most people saying "NEVER USE IF". Why in the world it is even implemented, if it's prohibited to be used?! – petermolnar Mar 07 '12 at 10:12
  • 4
    Also, I am using if statements in my current, live config, without any trouble of throttling, so I do think if has it's part and can be used correctly. Don't be blind or be fooled by myths running around. – petermolnar Mar 07 '12 at 10:14
  • 1
    I can also name a situation, where a mapping and an if speeds up a WordPress Network really seriously. http://petermolnar.eu/linux-tech-coding/nginx-config-for-wordpress-network/ – petermolnar Mar 07 '12 at 10:17