574

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.example to go to mysite.example 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.example 192.192.6.8 A type at 300 seconds
www.site.example 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.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
TheBlackBenzKid
  • 26,324
  • 41
  • 139
  • 209
  • 1
    I feel compelled to comment that if you're working with a WordPress website, check the `Dashboard > Settings > General Settings` and make sure that there is no `www` in the WordPress Address / Site Address URLs. No matter how you configure your nginx, if you have a www in these URLs it would get redirected to the one with www in it. – Abhinav Sood Nov 29 '18 at 15:05
  • **make sure both domains are DNS resolved to the IP**, or u will be like me, trying those config all day, did not apply at all, when I access my top domain without www server shell did not even have a pop up pid. – Weilory May 14 '23 at 12:48

19 Answers19

847

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.example;
        # $scheme will get the http protocol
        # and 301 is best practice for tablet, phone, desktop and seo
        return 301 $scheme://domain.example$request_uri;
}

server {
        listen 80;
        server_name domain.example;
        # 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.example;
    rewrite ^(.*) http://domain.example$1 permanent;
}

server {
    server_name  domain.example;
    #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.example to www.domain.example, you can use this:

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

server {
    server_name  www.domain.example;
    #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;
       }
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
TheBlackBenzKid
  • 26,324
  • 41
  • 139
  • 209
  • 4
    @puk appreciate it. Nginx is amazing, but good documentation that stays up to date with server version and OS and server hardware changes is quite tiresome. The best resource that serves me is howtoforge.com as it supports the RackSpace cloud versions. Some of the commands above won't work in later versions. But this nginx/0.8.54 - is believe me, the best nginx server) no need to upgrade or update. Works fine. 100,000 unique hits a day with 4200 transactions average a day. Nginx is RAPID. like using a site with no traffic. – TheBlackBenzKid Nov 30 '11 at 18:11
  • 20
    Your rewrites should become returns, as in `return 301 $scheme://domain.com$request_uri;`. There is no need to capture any patterns, see [Nginx pitfalls](http://wiki.nginx.org/Pitfalls#Multiple_Index_Directives) – Roberto Oct 10 '12 at 20:08
  • your solution will only work for http, not https. See what other people have suggested here re "return 301 $scheme" – Art Apr 19 '13 at 02:27
  • 4
    @TheBlackBenzKid Sorry, maybe I have missed something, but updated solution is not working. It's because listen 80 - with that, you are saying that only HTTP is matching this. There should be more ports to listen if same configuration is used for HTTP and HTTPS... Or? But definitelly helped me, +1. Thanks for reply. Cheers. – tomis May 14 '13 at 21:02
  • @tomis It is an example really and the solution works with latest nginx.. better to post another question for specifics. Thanks – TheBlackBenzKid May 15 '13 at 07:50
  • 3
    @TheBlackBenzKid It was just note. I have found out working solution. In your example, only Listen 443 should be added and complete working. – tomis May 15 '13 at 11:33
  • "To check the nginx version, use nginx -v. Here is a solution for older nginx versions..." older than what? – pcarvalho Mar 20 '14 at 18:43
  • 1
    @peteroak does not matter as that command works through out http://wiki.nginx.org/CommandLine – TheBlackBenzKid Mar 21 '14 at 09:41
  • 1
    solution work, but there is only a problem with comments, nginx does not recognize '//' for comments, '#' should be used instead – romanlv May 26 '14 at 16:29
  • I've been doing it for a while i was falling in a redirect loop, i just noticed that there are two server blocks now and it worked, thank you. – Rami GB Jun 03 '14 at 19:09
  • I had to fix a bunch of these in site-based NGINX config files, so wrote a little python script to do it, posted at: https://gist.github.com/DrPaulBrewer/61b6ba76de31df22722c – Paul Jun 26 '14 at 18:33
  • @TheBlackBenzKid is there any different in redirecting subdomains? for example www.blog.google.com to blog.google.com – parisssss Oct 02 '14 at 17:18
  • Best nginx answer ever, gz and ty – sospedra Nov 12 '14 at 14:53
  • 4
    answer is wrong. it redirects all subdomains to www. – r3wt Dec 22 '15 at 21:10
  • 1
    I'm not following why there are apparently two approaches here, out of the blue it says "To check the nginx version, use nginx -v." and then goes onto an alternative approach. Is this supposed to be for a specific version of nginx? Am I just missing something? – Nathan Hornby Jan 28 '16 at 15:12
  • @NathanHornby There is one solution. It works for http and https. NGINX has also configuration power for loadbalancers and using it as a proxy. This page has a wealth of information for you to get setup. The nginx -v is only to check the version, it was just a reference for future. This should work through out all versions. Thanks – TheBlackBenzKid Jan 31 '16 at 10:36
  • 1
    Is it possible to make it generic? I mean make it work with every domain instead of www.domain.com (or in your example www.google.com) – Ostad Apr 01 '16 at 12:28
  • if you're just listening on port 80 how can you listen for https which is port 443? – João Pimentel Ferreira Aug 24 '19 at 21:53
  • i tried all those things you mentioned and didn't work. after a long time pulling my hair, problem was i forgot to create A record in dns (route53 in my case). i felt so stupid now. – Laurence Dec 18 '20 at 22:38
  • A really bad example. For the performance considerations instead of `rewrite ^(.*) http://www.example.com$1 permanent;` you should use `return 301 http://www.example.com$request_uri;` to eliminate unnecessary and expensive PCRE library call. – Ivan Shatsky Jun 14 '22 at 09:27
438

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.

Fleshgrinder
  • 15,703
  • 4
  • 47
  • 56
  • Is there a need for the $scheme variable? – Chuan Ma Mar 25 '13 at 10:24
  • What do you want to do? Normally you use an absolute URL but to be honest I never tried a protocol relative URL in the location block (e.g. ``//example.com$request_uri``). Of course you can use a absolute URL without any host (e.g. ``/new_uri``) but that doesn't make sense in this context. – Fleshgrinder Mar 30 '13 at 01:16
  • @Fleshgrinder I used your setup and keep getting problems with www won't work... keep getting a HSTS failure in chrome. Any idea on that? – chuck reynolds Aug 09 '14 at 02:15
  • 4
    Your Chrome shouldn't be able to go to the http://www domain of yours if you're using HSTS. Please open a new question with as many details as possible and I'll help you (you can post the URL to the question as a comment here). – Fleshgrinder Aug 09 '14 at 06:26
  • 1
    @Fleshgrinder I'm trying to implement your setup but getting the following issue at http://stackoverflow.com/questions/29451409/nginx-www-to-non-www-redirect-not-working Any ideas on how to make it work? – YPCrumble Apr 04 '15 at 21:08
  • 5
    In the 2nd block "Redirect both, non-SSL and SSL to their non-www counterpart:", both server blocks should have the SSL directives, as the browser needs to verify the cert for www.example.com before it redirects to example.com. – Jeff Tsay Aug 20 '15 at 20:37
  • 1
    Of course, I added that as well as a short info about HSTS. – Fleshgrinder Aug 22 '15 at 12:39
  • so what if you have only 1 cert? for no-www. will https://www.example.com still redirect to https://example.com . suppose not, why (guess nginx serves only with correct cert?) should there be an error log about this (failed connection attempt to non-served ... well, I can see a problem here...) in nginx somewhere? – n611x007 Oct 27 '15 at 09:18
  • A `www.example.com` certificate is always valid for `example.com` as well. No problem there. Of course such a non-wildcard certificate is not valid for e.g. `www2.example.com` and you would need a different certificate. Nginx does not log an error in such a case if you either have not configured that domain or if you have configured it with a self-signed certificate. Simply because the validation fails on the client side and not on the server side. Hope this answers your question, otherwise create a real one. – Fleshgrinder Oct 27 '15 at 18:21
  • `return 301` is a true 301 HTTP redirect with the location and everything set. – Fleshgrinder Oct 10 '16 at 12:50
  • @Fleshgrinder is there a reason you use multiple server blocks rather than one server block listening at both 80 and 443, with example.com and www.example.com as server_name directives, and then include redirects like `if ($host ~* ^www\.(.*)) { return 301 https://$1$request_uri; } if ($scheme != "https") { return 301 https://$host$request_uri; }` (sorry if poorly formatted)? – YPCrumble Jan 02 '18 at 20:38
  • 1
    @YPCrumble yes, it's MUCH faster this way because we are not performing regular expression matching on each request. We only redirect if we know that we have to redirect. No checks, no validation, nothing: just redirect. =) – Fleshgrinder Jan 09 '18 at 18:43
  • I found that after changing specific configurations in nginx, `nginx -s reload` doesn't seem to be enough. Restarting the nginx service was the only the solution for me to make things work. – A.Essam Jan 10 '18 at 11:41
  • _You should never use a `rewrite` in this context. Why? Because nginx has to process and start a search._ Actually when you use a `permanent` or `redirect` flag on a rewrite directive, or the scheme/domain name get changed via the rewrite rule, nginx won't search a new location to handle the request but issue a redirect immediately. `return` should be preferred over `rewrite` because of performance considerations since it won't require a (kind of expensive) PCRE library call. – Ivan Shatsky Jun 14 '22 at 18:51
  • Three server blocks should be preferred over any other solution (like anything using additional `if` conditions) for the same performance reason; I just give an explanation why it is the most effective way [here](https://stackoverflow.com/a/72615689/7121513). – Ivan Shatsky Jun 14 '22 at 18:52
72
  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:

Community
  • 1
  • 1
cnst
  • 25,870
  • 6
  • 90
  • 122
46

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;
}
Martin Höger
  • 804
  • 7
  • 6
  • 7
    I like this way better than dedicated server blocks. Change `http` to `$scheme` – ck_ Aug 25 '15 at 15:09
  • 3
    Much better, can't believe so many would hardcode domains into configs for this task. – MrYellow Oct 27 '15 at 20:17
  • 1
    @Oli That link does not (as of today) mention performance but rather that they're not 100% safe. It does say "The only 100% safe things which may be done inside if in a location context are: `return ...` and `rewrite ... last`". Any updated links to performance issues? – Adam Jul 27 '16 at 09:53
  • Indeed, `rewrite... last` and `return` seem to be safe on **server level**. [Here's](https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/#what-to-do-instead) from the Nginx website: `In some cases, it’s also possible to move ifs to server level (where it’s safe as only other rewrite module directives are allowed within it).` No reference to having an impact on performance. – nunop Sep 23 '16 at 16:05
  • 1
    This didn't work for me. Kept getting an error on the browser saying invalid response. – Nico Brenner Feb 14 '18 at 07:48
  • Official Nginx documentation states that [If is evil](https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/). – pozitron57 Jun 18 '18 at 19:44
  • 2
    Unfortunately, I didn't find a way without "if". I use the same config for many domains, hardcoding the domain names is not an option. Any suggestion/comment is appreciated! – Martin Höger Jul 10 '18 at 13:34
30

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.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
pyfork
  • 3,747
  • 2
  • 21
  • 18
23

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 ;
}
Eric Johnson
  • 1,084
  • 13
  • 24
19

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;
}
Matt Janssen
  • 1,505
  • 13
  • 14
16

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.

VisioN
  • 143,310
  • 32
  • 282
  • 281
  • what about https? note: https _NEED_ the certificate – Toskan Aug 10 '17 at 17:04
  • There is absolutely no problem with HTTPS here. After `listen 80` you need to add `listen 443 ssl` and then `ssl_certificate` and `ssl_certificate_key` directives. – VisioN Aug 11 '17 at 08:05
  • nobody uses http nowadays. I was reading a top listed guide in google that showed your example just with the added line `listen 443 ssl` with missing certficate. That _wont_ work and is causing some serious headache. – Toskan Aug 11 '17 at 19:44
  • I don't know what guide you are talking about. I have this configuration successfully working for nearly three years. Last year I added support for SSL and it works as expected. And of course you need to have a certificate with a private key in hand. – VisioN Aug 11 '17 at 20:06
  • so this will clobber all subdomains except www, correct? – Metagrapher Jan 23 '18 at 07:43
12

try this

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

Other way: Nginx no-www to www

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

and www to no-www

server {
  listen       80;
  server_name  www.yoursite.example;
  root /path/;
  index index.php;
  return       301 https://yoursite.example$request_uri;
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Kevin Nguyen
  • 1,759
  • 2
  • 16
  • 14
  • Why did the authors provide an if-statement in nginx and then tell people to avoid it? Sounds flippant to me. – Greg Smethells Mar 30 '15 at 18:06
  • 4
    There is stated "IF in location is evil". You can safely put if into your server block – Kukunin Apr 01 '15 at 19:56
  • Direct quote from the above link...The only 100% safe things which may be done inside if in location context are: return ...; rewrite ... last; – Justin E Oct 02 '15 at 20:27
11

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 ;
}
Ravindra Bhalothia
  • 1,720
  • 2
  • 13
  • 16
9

Unique format:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}
Andriyun
  • 506
  • 6
  • 9
  • 1
    You can make it generic by writing it this way: `server {` `server_name "~^www\.(.*)$" ;` `return 301 $scheme://$1$request_uri ;` `}` – Ramast Jul 29 '15 at 10:36
8

If you don't want to hardcode the domain name, you can use this redirect block. The domain without the leading www is saved as variable $domain which can be reused in the redirect statement.

server {
    ...
    # Redirect www to non-www
    if ( $host ~ ^www\.(?<domain>.+) ) {
       rewrite ^/(.*)$ $scheme://$domain/$1;
    }
}

REF: Redirecting a subdomain with a regular expression in nginx

Drakes
  • 23,254
  • 3
  • 51
  • 94
5
location / {
    if ($http_host !~ "^www.domain.example"){
        rewrite ^(.*)$ $scheme://www.domain.example$1 redirect;
    }
}
Maoz Zadok
  • 4,871
  • 3
  • 33
  • 43
3

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

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

is faster than:

return 301 $scheme://yoursite.example$request_uri;
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
steven
  • 662
  • 1
  • 6
  • 13
  • 1
    No, its not: https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#taxing-rewrites – Ricardo Feb 04 '16 at 18:47
  • 1
    my comment was directed to the browser not to efficiency on nginx side! with a redirect the browser makes 2 requests vs 1 request when rewiting – steven Apr 04 '17 at 20:54
2

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;  
Stephan Kristyn
  • 15,015
  • 14
  • 88
  • 147
1

my configuration was - Nginx + tomcat 9 + Ubuntu 20.04 + spring boot app all answers above not working for me - also not work upstream notation in Nginx file - so I change my settings on this

thanks God for certbot - this util very helpful, it's generate base file for your site and then I added my changes - to redirect https://www.example.com, http://www.example.com to only one https://example.com

server {
if ($host = www.example.com) {
    return 301 https://example.com$request_uri;
}
    root /var/www/example.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example.com www.example.com;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_pass http://127.0.0.1:8080; # This is upstream name, note the variable $scheme in it
      proxy_redirect off;
    }
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = www.example.com) {
        return 301 https://example.com$request_uri;
    } # managed by Certbot
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
        listen 80;
        listen [::]:80;
        server_name example.com www.example.com;
    return 404; # managed by Certbot
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Baatr
  • 21
  • 5
0
if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}
karadayi
  • 2,212
  • 2
  • 21
  • 36
0

Add CNAME with cloudflare and use this format as conf file.

server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
    proxy_pass "http://localhost:3000/";
}}
eRevolute
  • 9
  • 3
-6

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
undoIT
  • 611
  • 1
  • 7
  • 13