0

I am hosting a Rails app on Nginx that is accessible through a defined set of domains. For each of these domains I also want to forward www to non-www. Right now my config file looks like this:

server {
    listen      80;
    server_name www.domain1.com;
    rewrite ^ http://domain1.com$uri permanent;
}

server {
    listen      80;
    server_name www.domain2.com;
    rewrite ^ http://domain2.com$uri permanent;
}

server {
    listen      80;
    server_name www.domain3.com;
    rewrite ^ http://domain3.com$uri permanent;
}

server {
    listen            80;
    server_name       domain1.com domain2.com domain3.com;
    root              /home/rails/apps/myapp/current/public;
    passenger_enabled on;
}

So I have to repeat the part that forwards www to non-www for every domain and add that domain as a server_name to the last server {} directive. Right now I have about 15 domains configured like that and there are more to come, meaning it will get more and more cumbersome to maintain that list. What I would really like would be something like this: (pseudocode)

%domains = [domain1.com, domain2.com, domain3.com]

for each %domain in domains
    server {
        listen      80;
        server_name www.%domain;
        rewrite ^ http://%domain$uri permanent;
    }
end

server {
    listen            80;
    server_name       %domains;
    root              /home/rails/apps/myapp/current/public;
    passenger_enabled on;
}

One thing I cannot do is use a wildcard for forwarding ALL domains to their non-www variant, since I host other domains on the same Nginx as well. It has to be a defined set of domains.

Is there any way to accomplish anything like that? Or another way I could clean up the config file? All suggestions welcome!

EDIT:

With the help of rzab's answer I could get it down to this:

map $http_host $non_www_host {
  www.domain1.com domain1.com;
  www.domain2.com domain2.com;
  www.domain3.com domain3.com;
}

server {
  listen        80;
  server_name   www.domain1.com www.domain2.com www.domain3.com;
  rewrite ^     http://$non_www_host$uri permanent;
}

server {
    listen              80;
    server_name         domain1.com domain2.com domain3.com;
    root                /home/rails/apps/myapp/current/public;
    passenger_enabled   on;
}

It's less to write (maybe not with 3 domains but with more than 5 or more definitely) but now I have to add a new domain to 3 places! Is there any way I can just have the list of domains in one place?

2
  • Write a script to generate a config file, that's about the only thing you can do aside from a wildcard server block. Mar 29, 2011 at 12:15
  • Nginx favors static server names before regexps Mar 29, 2011 at 13:16

2 Answers 2

1

You can auto-generate 2 small files containing a map of hosts and server_name line, so that the full config would include

map $http_host $nonwww_host {
        www.domain1.com domain1.com;
        www.domain2.com domain2.com;
        # etc.
}

server {     
        server_name www.domain1.com www.domain2.com; # etc.
        rewrite ^ http://$nonwww_host$uri permanent;
}

Having 2 files (lets say, hostmap.conf and server_names.conf), the config can have

include hostmap.conf; # instead of "map $http_host $nonwww_host { ..."

server {
        include server_names.conf; # "server_name ..."
        rewrite ^ http://$nonwww_host$uri permanent;
}    
1
  • Thanks for your tip with using a map! I updated the post. I wouldn't extract the domains into external files, though. Then I would have to remember to update several files anytime I want to add a domain. However, with the map I now have 3 places I have to add a new domain. Is there any way of defining the domains in just one place? Apr 3, 2011 at 16:56
1
server {
        server_name ~^www\.(domain1\.com|domain2\.com|domain3\.com)$;
        set $non_www_host $1;
        rewrite ^ http://$non_www_host$uri permanent;
}

You need at least 0.7.40 nginx for regex in server_name support.

2) multiple regexes to split a long one with more than a few names.

server_name ~^www\.(domain1\.com|domain2\.com|domain3\.com)$;
server_name ~^www\.(domain4\.com|domain5\.com|domain6\.com)$;

3) multiple server_names. Looks obvious but I thought you want it to be concise

server_name www.domain1.com;
server_name www.domain2.com;
# etc.
3
  • This would be another option but the regex would get very long and cumbersome to work with as well once you have 10+ domains... besides, would it have an impact on performance using a regex instead of a static string? Apr 5, 2011 at 7:16
  • Pick you preference :) Regex to be concise. Multiple "server_name"s to be readable. You can have multiple server_names with regexes too, so they won't get that long. I'm updating the answer with the examples.
    – rzab
    Apr 5, 2011 at 9:52
  • Performance-wise, regexes are ok as long as you're not eager for a benchmark to see if it's ok. Static string is the fastest, but I cannot tell if regex performance is acceptable in your situation.
    – rzab
    Apr 5, 2011 at 10:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .