Nginx no-www to www and www to no-www

2018-12-31 14:29发布

问题:

I am using nginx on Rackspace cloud following a tutorial and having searched the net and so far can\'t get this sorted.

I want www.mysite.com to go to mysite.com as normal in .htaccess for SEO and other reasons.

My /etc/nginx/sites-available/www.example.com.vhost config:

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/www.example.com/web;

       if ($http_host != \"www.example.com\") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

I have also tried

server {
       listen 80;
       server_name example.com;
       root /var/www/www.example.com/web;

       if ($http_host != \"www.example.com\") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

I also tried. Both the second attempts give redirect loop errors.

if ($host = \'www.example.com\' ) {
rewrite ^ http://example.com$uri permanent;
}

My DNS is setup as standard:

site.com 192.192.6.8 A type at 300 seconds
www.site.com 192.192.6.8 A type at 300 seconds

(example IPs and folders have been used for examples and to help people in future). I use Ubuntu 11.

回答1:

HTTP Solution

From the documentation, \"the right way is to define a separate server for example.org\":

server {
    listen       80;
    server_name  example.com;
    return       301 http://www.example.com$request_uri;
}

server {
    listen       80;
    server_name  www.example.com;
    ...
}

HTTPS Solution

For those who want a solution including https://...

server {
        listen 80;
        server_name www.domain.com;
        # $scheme will get the http protocol
        # and 301 is best practice for tablet, phone, desktop and seo
        return 301 $scheme://domain.com$request_uri;
}

server {
        listen 80;
        server_name domain.com;
        # here goes the rest of your config file
        # example 
        location / {

            rewrite ^/cp/login?$ /cp/login.php last;
            # etc etc...

        }
}

Note: I have not originally included https:// in my solution since we use loadbalancers and our https:// server is a high-traffic SSL payment server: we do not mix https:// and http://.


To check the nginx version, use nginx -v.

Strip www from url with nginx redirect

server {
    server_name  www.domain.com;
    rewrite ^(.*) http://domain.com$1 permanent;
}

server {
    server_name  domain.com;
    #The rest of your configuration goes here#
}

So you need to have TWO server codes.

Add the www to the url with nginx redirect

If what you need is the opposite, to redirect from domain.com to www.domain.com, you can use this:

server {
    server_name  domain.com;
    rewrite ^(.*) http://www.domain.com$1 permanent;
}

server {
    server_name  www.domain.com;
    #The rest of your configuration goes here#
}

As you can imagine, this is just the opposite and works the same way the first example. This way, you don\'t get SEO marks down, as it is complete perm redirect and move. The no WWW is forced and the directory shown!

Some of my code shown below for a better view:

server {
    server_name  www.google.com;
    rewrite ^(.*) http://google.com$1 permanent;
}
server {
       listen 80;
       server_name google.com;
       index index.php index.html;
       ####
       # now pull the site from one directory #
       root /var/www/www.google.com/web;
       # done #
       location = /favicon.ico {
                log_not_found off;
                access_log off;
       }
}


回答2:

Actually you don\'t even need a rewrite.

server {
    #listen 80 is default
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
    #listen 80 is default
    server_name example.com;
    ## here goes the rest of your conf...
}

As my answer is getting more and more up votes but the above as well. You should never use a rewrite in this context. Why? Because nginx has to process and start a search. If you use return (which should be available in any nginx version) it directly stops execution. This is preferred in any context.

Redirect both, non-SSL and SSL to their non-www counterpart:

server {
    listen               80;
    listen               443 ssl;
    server_name          www.example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    return 301 $scheme://example.com$request_uri;
}

server {
    listen               80;
    listen               443 ssl;
    server_name          example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    # rest goes here...
}

The $scheme variable will only contain http if your server is only listening on port 80 (default) and the listen option does not contain the ssl keyword. Not using the variable will not gain you any performance.

Note that you need even more server blocks if you use HSTS, because the HSTS headers should not be sent over non-encrypted connections. Hence, you need unencrypted server blocks with redirects and encrypted server blocks with redirects and HSTS headers.

Redirect everything to SSL (personal config on UNIX with IPv4, IPv6, SPDY, ...):

#
# Redirect all www to non-www
#
server {
    server_name          www.example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:80;
    listen               *:443 ssl spdy;
    listen               [::]:80 ipv6only=on;
    listen               [::]:443 ssl spdy ipv6only=on;

    return 301 https://example.com$request_uri;
}

#
# Redirect all non-encrypted to encrypted
#
server {
    server_name          example.com;
    listen               *:80;
    listen               [::]:80;

    return 301 https://example.com$request_uri;
}

#
# There we go!
#
server {
    server_name          example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:443 ssl spdy;
    listen               [::]:443 ssl spdy;

    # rest goes here...
}

I guess you can imagine other compounds with this pattern now by yourself.

More of my configs? Go here and here.



回答3:

You may find out you want to use the same config for more domains.

Following snippet removes www before any domain:

if ($host ~* ^www\\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}


回答4:

You need two server blocks.

Put these into your config file eg /etc/nginx/sites-available/sitename

Let\'s say you decide to have http://example.com as the main address to use.

Your config file should look like this:

server {
        listen 80;
        listen [::]:80;
        server_name www.example.com;
        return 301 $scheme://example.com$request_uri;
}
server {
        listen 80;
        listen [::]:80;
        server_name example.com;

        # this is the main server block
        # insert ALL other config or settings in this server block
}

The first server block will hold the instructions to redirect any requests with the \'www\' prefix. It listens to requests for the URL with \'www\' prefix and redirects.

It does nothing else.

The second server block will hold your main address — the URL you want to use. All other settings go here like root, index, location, etc. Check the default file for these other settings you can include in the server block.

The server needs two DNS A records.

Name: @ IPAddress: your-ip-address (for the example.com URL)

Name: www IPAddress: your-ip-address (for the www.example.com URL)

For ipv6 create the pair of AAAA records using your-ipv6-address.



回答5:

Here\'s how to do it for multiple www to no-www server names (I used this for subdomains):

server {
        server_name 
             \"~^www\\.(sub1.example.com)$\"
             \"~^www\\.(sub2.example.com)$\"
             \"~^www\\.(sub3.example.com)$\";
         return 301 $scheme://$1$request_uri ;
}


回答6:

This solution comes from my personal experience. We used several Amazon S3 buckets and one server for redirecting non-www to www domain names to match S3 \"Host\" header policy.

I used the following configuration for nginx server:

server {
    listen 80;
    server_name ~^(?!www\\.)(?<domain>.+)$;
    return 301 $scheme://www.$domain$request_uri;
}

This matches all domain names pointed to the server starting with whatever but www. and redirects to www.<domain>. In the same manner you can do opposite redirect from www to non-www.



回答7:

try this

    if ($host !~* ^www\\.){
        rewrite ^(.*)$ https://www.yoursite.com$1;
    }

Other way: Nginx no-www to www

server {
  listen       80;
  server_name  yoursite.com;
  root /path/;
  index index.php;
  return       301 https://www.yoursite.com$request_uri;
}

and www to no-www

server {
  listen       80;
  server_name  www.yoursite.com;
  root /path/;
  index index.php;
  return       301 https://yoursite.com$request_uri;
}


回答8:

I combined the best of all the simple answers, without hard-coded domains.

301 permanent redirect from non-www to www (HTTP or HTTPS):

server {
    if ($host !~ ^www\\.) {
        rewrite ^ $scheme://www.$host$request_uri permanent;
    }

    # Regular location configs...
}

If you prefer non-HTTPS, non-www to HTTPS, www redirect at the same time:

server {
    listen 80;

    if ($host !~ ^www\\.) {
        rewrite ^ https://www.$host$request_uri permanent;
    }

    rewrite ^ https://$host$request_uri permanent;
}


回答9:

Redirect non-www to www

For Single Domain :

server {
        server_name example.com;
        return 301 $scheme://www.example.com$request_uri;
}

For All Domains :

server {
        server_name \"~^(?!www\\.).*\" ;
        return 301 $scheme://www.$host$request_uri;
}

Redirect www to non-www For Single Domain:

server {
        server_name www.example.com;
        return 301 $scheme://example.com$request_uri;
}

For All Domains :

server {
         server_name \"~^www\\.(.*)$\" ;
         return 301 $scheme://$1$request_uri ;
}


回答10:

Unique format:

server {
  listen 80;
  server_name \"~^www\\.(.*)$\" ;
  return 301 https://$1$request_uri ;
}


回答11:

location / { 
    if ($http_host !~ \"^www.domain.com\"){ 
        rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
    } 
}


回答12:

not sure if anyone notice it may be correct to return a 301 but browsers choke on it to doing

rewrite ^(.*)$ https://yoursite.com$1; 

is faster than:

return 301 $scheme://yoursite.com$request_uri;


回答13:

Ghost blog

in order to make nginx recommended method with return 301 $scheme://example.com$request_uri; work with Ghost you will need to add in your main server block:

proxy_set_header    X-Real-IP           $remote_addr;
proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
proxy_set_header    Host                $http_host;
proxy_set_header    X-Forwarded-Proto   $scheme;
proxy_set_header    X-NginX-Proxy       true;

proxy_pass_header   X-CSRF-TOKEN;
proxy_buffering     off;
proxy_redirect      off;  


回答14:

if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}


回答15:

If you are having trouble getting this working, you may need to add the IP address of your server. For example:

server {
listen XXX.XXX.XXX.XXX:80;
listen XXX.XXX.XXX.XXX:443 ssl;
ssl_certificate /var/www/example.com/web/ssl/example.com.crt;
ssl_certificate_key /var/www/example.com/web/ssl/example.com.key;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}

where XXX.XXX.XXX.XXX is the IP address (obviously).

Note: ssl crt and key location must be defined to properly redirect https requests

Don\'t forget to restart nginx after making the changes:

service nginx restart