33

I have the following nginx configuration fragment:

server {
   listen 80;

   server_name mydomain.io;

   root /srv/www/domains/mydomain.io;

   index index.html index.php;

   access_log /var/log/nginx/domains/mydomain.io/access.log;
   error_log /var/log/nginx/domains/mydomain.io/error.log;

   location ~\.php {
      try_files $uri =404;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_intercept_errors on;
      fastcgi_pass 127.0.0.1:9000;
      include /etc/nginx/fastcgi_params;
   }
}

First, how can I make the server block respond to both http://www.mydomain.io and also http://mydomain.io. Second, I want to force if they come from http://www.mydomain.io to redirect to http://mydomain.io.

Thanks.

Justin
  • 42,716
  • 77
  • 201
  • 296

6 Answers6

186

According to https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#server-name-if, you should use:

server {
  server_name www.example.com;
  return 301 $scheme://example.com$request_uri;
}
server {
  server_name example.com;
  # [...]
}
Ryan
  • 22,332
  • 31
  • 176
  • 357
  • 23
    Please upvote this, people. It makes me sad to see the least suitable answer accepted, the second best with a majority of the votes... meanwhile the correct answer languishes. Gerry's answer is better than Tisho's, however Ryan's answer here is the recommended way to it. Think about it. Do you want the server answering two requests for every request it gets to www? No, no you don't. – original_username Oct 08 '13 at 06:14
  • 1
    I’m using a more general block that handles my local server (localhost). unfortunately, this means that in production `www.` does not get dropped. how can i improve this block? (apologies for poor formating) server { listen 80; server_name ~^(www|app)\.(.*)$; return 301 $scheme://$1$request_uri; } – robinnnnn Jan 03 '17 at 23:27
  • 1
    The nginx pitfalls wiki page link above is broken. It should now be https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/. Also if you want to find the information above on that link search for 'Using if'. Thanks Ryan! Worked great! – junkie Mar 04 '17 at 21:35
  • 1
    Thanks @junkie! Updated. – Ryan Mar 04 '17 at 22:07
  • 3
    There is no `listen` statement in the code included in this answer. Without it, This won't work. – Ishan Jain Dec 26 '18 at 12:51
13

I believe it's better to add two seperate server blocks to avoid unnecessary checking by the if block. I also use the $scheme variable so that HTTPS requests will not be redirected to their insecure counterparts.

server {
    listen 80;

    server_name www.mydomain.io;

    rewrite ^ $scheme://mydomain.io$uri permanent;
}

server {
    listen 80;

    server_name mydomain.io;

    # your normal server block definitions here
}
Gerry
  • 6,012
  • 21
  • 33
  • 3
    I up-voted this by mistake, but it is also an incorrect answer. The use of `rewrite` in this way is highly discouraged by the NGINX documentation itself. Please see Ryan's answer about the proper use of `return 301 $scheme://domain.com$request_uri;` – Bryson Jan 27 '14 at 13:33
7

For a generic approach, without having to mention any specific domain or protocol, I have used this quite successfully:

  # rewrite to remove www.
  if ( $host ~ ^www\.(.+)$ ) {
    set $without_www $1;
    rewrite ^ $scheme://$without_www$uri permanent;
  }

This will redirect: https://www.api.example.com/person/123?q=45 to https://api.example.com/person/123?q=45

GeezerGeek
  • 101
  • 1
  • 5
5

Another way to code it :

if ($http_host ~* "^www\.(.+)$"){
    rewrite ^(.*)$ http://%1$request_uri redirect;
}

It works even with multiple domain names on the same code.

lio
  • 185
  • 1
  • 3
  • 12
-2
server {
    listen 80;
    server_name www.mydomain.io;
    return 301 https://$host$request_uri;
}

server {
    listen 80;
    server_name mydomain.io;
    ...
}
Time to Travel
  • 142
  • 1
  • 9
  • 1
    Variable $host in first server block has value "www.mydomain.io". So you redirect request from http:// www.mydomain.io to https:// www.mydomain.io but not to mydomain.io as requested – Alexander Ushakov Feb 24 '17 at 12:41
-21

On the first question - simply add both domains:

server_name mydomain.io www.mydomain.io;

For the second, you'll need this simple redirect:

server {
      listen 80;

      server_name www.mydomain.io mydomain.io;

      if ($host = 'www.mydomain.io' ) {
         rewrite  ^/(.*)$  http://mydomain.io/$1  permanent;
      }
Tisho
  • 8,320
  • 6
  • 44
  • 52
  • 6
    Using an if in nginx configs is strongly not recommended: http://wiki.nginx.org/IfIsEvil . Rather use two server blocks as suggested by @Gerry – Jrgns Feb 04 '13 at 03:09
  • 4
    @Jrgns: Also,`rewrite` is mentioned as one of the two "100% safe things which may be done inside if in location context" in the nginx wiki... – Tisho Feb 04 '13 at 12:55
  • 3
    If this gets enough down-votes that its value is negative will the system still retain it as the selected answer? – Bryson Jan 26 '14 at 02:18
  • This (or similar) solution is acceptable in some cases. For example, if you have regex or wildcard `server_name`, such as `server_name ~^.*\.mydomain\.(com|net|org)$` you probably don't want to have code duplication with other `server` blocks, so you may use something like `if ($host ~ "^www\.(.*)$") { #do redirect }`. BTW, this `if` is not in `location` context ;) – Oleg Nov 13 '15 at 14:20
  • I have tried with separate server blocks but, though Nginx is responding to both, I don't know why this happens but even after removing server_name www.mydomain.com from my original server block nginx is still responding to the request. Final I got your answer to handle it via IF condition, Thanks @Tisho – Tapas Thakkar Aug 18 '20 at 13:37