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

前端 未结 17 2199
予麋鹿
予麋鹿 2020-11-22 09:53

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

相关标签:
17条回答
  • 2020-11-22 10:05

    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.

    0 讨论(0)
  • 2020-11-22 10:05
    1. Best Practice: separate server w/ hardcoded server_name

    Best practice with nginx is to use a separate server for a redirect like this (not shared with the server of your main configuration), to hardcode everything, and not use regular expressions at all.

    It may also be necessary to hardcode the domains if you're using HTTPS, because you have to know upfront which certificates you'll be providing.

    server {
        server_name www.example.com;
        return  301 $scheme://example.com$request_uri;
    }
    server {
        server_name www.example.org;
        return  301 $scheme://example.org$request_uri;
    }
    server {
        server_name example.com example.org;
        # real configuration goes here
    }
    

    1. Using Regular Expressions within server_name

    If you have a number of sites, and don't care for the most ultimate performance, but want every single one of them to have the same policy in regards to the www. prefix, then you can use regular expressions. The best practice of using a separate server would still stand.

    Note that this solution gets tricky if you use https, as you must then have a single certificate to cover all of your domain names if you want this to work properly.


    non-www to www w/ regex in a dedicated single server for all sites:

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

    www to non-www w/ regex in a dedicated single server for all sites:

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

    www to non-www w/ regex in a dedicated server for some sites only:

    It may be necessary to restrict the regex to cover only a couple of domains, then you can use something like this to only match www.example.org, www.example.com and www.subdomain.example.net:

    server {
        server_name ~^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$;
        return  301 $scheme://$domain$request_uri;
    }
    

    Testing Regular Expressions w/ nginx

    You can test that the regex works as expected with pcretest on your system, which is the exact same pcre library that your nginx will be using for regular expressions:

    % pcretest 
    PCRE version 8.35 2014-04-04
    
      re> #^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$#
    data> test
    No match
    data> www.example.org
     0: www.example.org
     1: example.org
    data> www.test.example.org
    No match
    data> www.example.com
     0: www.example.com
     1: example.com
    data> www.subdomain.example.net
     0: www.subdomain.example.net
     1: subdomain.example.net
    data> subdomain.example.net
    No match
    data> www.subdomain.example.net.
    No match
    data> 
    

    Note that you don't have to worry about trailing dots or case, as nginx already takes care of it, as per nginx server name regex when "Host" header has a trailing dot.


    1. Sprinkle if within existing server / HTTPS:

    This final solution is generally not considered to be the best practice, however, it still works and does the job.

    In fact, if you're using HTTPS, then this final solution may end up easier to maintain, as you wouldn't have to copy-paste a whole bunch of ssl directives between the different server definitions, and could instead place the snippets only into the needed servers, making it easier to debug and maintain your sites.


    non-www to www:

    if ($host ~ ^(?!www\.)(?<domain>.+)$) {
        return  301 $scheme://www.$domain$request_uri;
    }
    

    www to non-www:

    if ($host ~ ^www\.(?<domain>.+)$) {
        return  301 $scheme://$domain$request_uri;
    }
    

    hardcoding a single preferred domain

    If you want a little bit more performance, as well as consistency between multiple domains a single server may use, it might still make sense to explicitly hardcode a single preferred domain:

    if ($host != "example.com") {
        return  301 $scheme://example.com$request_uri;
    }
    

    References:

    • http://nginx.org/r/server_name
    • http://nginx.org/r/return
    • http://nginx.org/en/docs/http/server_names.html
    0 讨论(0)
  • 2020-11-22 10:05

    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.

    0 讨论(0)
  • 2020-11-22 10:05
    location / { 
        if ($http_host !~ "^www.domain.com"){ 
            rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
        } 
    }
    
    0 讨论(0)
  • 2020-11-22 10:05
    if ($host ~* ^www.example.com$) {
        return 301 $scheme://example.com$request_uri;
    }
    
    0 讨论(0)
  • 2020-11-22 10:08

    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 ;
    }
    
    0 讨论(0)
提交回复
热议问题