How to redirect non-www to www HTTP / TLS /SSL traffic on Nginx

Posted on in Categories , , last updated June 17, 2017

I want ALL cyberciti.biz to go to www.cyberciti.biz for SEO and other reasons. I want ALL HTTP traffic to go to HTTPS. How do I redirect all HTTP/HTTPS non-www (e.g. domain name cyberciti.biz) traffic to www (e.g. domain name www.cyberciti.biz) when using Nginx web server?

It is suggested that you do the redirection with the HTTP response status code 301 Moved Permanently. It is used for persistent URL redirection, meaning current links using the URL that the response is received for should be refreshed by both search engines and manually made bookmarks.
How To Redirect www to Non-www with Nginx
This tutorial shows you how to redirect a non-www URL to a www with Nginx web-server running in Linux or Unix-like system.

Update your virtual domain config file as follows for HTTP redirection

You need to define two virtual hosts as follows in your config file:

## redirect http://cyberciti.biz to http://www.cyberciti.biz/
server {
    listen       80;
    access_log  off;
    error_log   off;
    server_name  cyberciti.biz;
    return       301 http://www.cyberciti.biz$request_uri;
}
## Continue below for www.cyberciti.biz
server {
    listen       80;
    access_log  off;
    error_log   off;
    server_name  www.cyberciti.biz;
    ## rest of config below ##
}

Keep in mind if you are using ‘HTTP Strict Transport Security‘, you need to redirect ALL http traffic to HTTPS/TLS domain. So edit the nginx.conf or one of virtual hosting file stored in /etc/nginx/sites-enabled/ for your domain:
$ sudo vi /etc/nginx/sites-enabled/cyberciti.biz.conf
Update it as follows:

## redirect http://cyberciti.biz to https://cyberciti.biz ##
server {
    listen      80;
    access_log  off;
    error_log   off;
    server_name cyberciti.biz;
    return      301 https://$server_name$request_uri;
}
## redirect www.cyberciti.biz to https://www.cyberciti.biz/
server {
    listen      80;
    access_log  off;
    error_log   off;
    server_name www.cyberciti.biz;
    return      301 https://$server_name$request_uri;
}

Save and close the file. You must reload the nginx server after testing for syntax errors using the -t option:
$ sudo nginx -t && systemctl reload nginx
OR
$ sudo nginx -t && service nginx reload

See how to configure Nginx with a free Let’s Encrypt SSL/TLS certificate

Update your virtual domain config file as follows for HTTPS/TLS redirection

Again edit your nginx.conf or one of virtual hosting file stored in /etc/nginx/sites-enabled/ for your domain as follows using the vi command/vim command:

## redirect all https://cyberciti.biz/ to https://www.cyberciti.biz/
server {
        listen 443 ssl http2;
        access_log  off;
        error_log   off;
        server_name cyberciti.biz;
        return 301 https://www.cyberciti.biz$request_uri;
}
## define our https://www.cyberciti.biz/ ##
server {
    listen 443 ssl http2;
    access_log  /var/log/nginx/www.cyberciti.biz_access.log;
    error_log  /var/log/nginx/www.cyberciti.biz_error.log;
    ## server name and root
    server_name  www.cyberciti.biz;
    root        /home/lighttpd/cyberciti.biz/http;
 
    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /etc/nginx/ssl/letsencrypt/cyberciti.biz/cyberciti.biz.crt;
    ssl_certificate_key /etc/nginx/ssl/letsencrypt/cyberciti.biz/cyberciti.biz.key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/nginx/ssl/letsencrypt/cyberciti.biz/dhparams.pem;
 
    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;
 
  # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security "max-age=15768000" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Xss-Protection "1";
    add_header X-Whome "l-cbz02";
    # OCSP Stapling 
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;
    ## Improves TTFB by using a smaller SSL buffer than the nginx default
    ssl_buffer_size 8k;
 
    # Directives to send expires headers and turn off 404 error logging.
    location ~* ^.+\.(css|js|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
          access_log off; log_not_found off; expires max;
    }
 
    # Pass all .php files onto a php-fpm/php-fcgi server.
     index index.php;
     location ~ [^/]\.php(/|$) {
     fastcgi_split_path_info ^(.+?\.php)(/.*)$;
            if (!-f $document_root$fastcgi_script_name) {
                     return 404;
     }
 
    # This is a robust solution for path info security issue and works with "cgi.fix_pathinfo = 1" in /etc/php.ini (default)
    include /etc/nginx/fastcgi_params;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass php;
 }
}

Save and close the file. Again, you need to reload the nginx server after testing for syntax errors using the -t option:
$ sudo nginx -t && service nginx reload

Test it

Use the curl command as follows:
$ curl -I cyberciti.biz

HTTP/1.1 301 Moved Permanently
Date: Sat, 17 Jun 2017 18:02:16 GMT
Content-Type: text/html
Connection: keep-alive
Location: https://cyberciti.biz/
X-Whome: l-cbz01
X-Content-Type-Options: nosniff
Server: cloudflare-nginx
CF-RAY: 3707eb3d507d2ee1-DEL

OR
$ curl -I https://cyberciti.biz
Sample outputs:

HTTP/1.1 301 Moved Permanently
Date: Sat, 17 Jun 2017 18:03:10 GMT
Content-Type: text/html
Connection: keep-alive
Location: https://www.cyberciti.biz/
X-Whome: l-cbz02
Strict-Transport-Security: max-age=15552000
X-Content-Type-Options: nosniff
Server: cloudflare-nginx
CF-RAY: 3707ec8e7c612f23-DEL

See how redirection works:
$ curl -ILa cyberciti.biz
Sample outputs:

HTTP/1.1 301 Moved Permanently
Date: Sat, 17 Jun 2017 18:04:20 GMT
Content-Type: text/html
Connection: keep-alive
Location: https://cyberciti.biz/
X-Whome: l-cbz01
X-Content-Type-Options: nosniff


HTTP/1.1 301 Moved Permanently
Date: Sat, 17 Jun 2017 18:04:21 GMT
Content-Type: text/html
Connection: keep-alive
Location: https://www.cyberciti.biz/
X-Whome: l-cbz02
Strict-Transport-Security: max-age=15552000
X-Content-Type-Options: nosniff


HTTP/1.1 200 OK
Date: Sat, 17 Jun 2017 18:04:21 GMT
Content-Type: text/html;charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: public, max-age=1800
Expires: Sat, 17 Jun 2017 18:34:21 GMT
Last-Modified: Sat, 03 Jun 2017 08:24:57 GMT
Strict-Transport-Security: max-age=15552000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1
X-Whome: l-cbz02
CF-Cache-Status: HIT

See also

  1. Nginx Force (Redirect) WWW.Domain.COM To Domain.COM
  2. How To: Nginx Redirect All HTTP Request To HTTPS Rewrite 301 Rules

And there you have Nginx doinng a non-www to www redirection on Linux or Unix-like system.

Posted by: Vivek Gite

The author is the creator of nixCraft and a seasoned sysadmin and a trainer for the Linux operating system/Unix shell scripting. He has worked with global clients and in various industries, including IT, education, defense and space research, and the nonprofit sector. Follow him on Twitter, Facebook, Google+.

Share this on (or read 11 comments/add one below):

11 comment

  1. www redirection should be done by contacting your ISP (GoDaddy, etc.)
    HTTPS redirection can also be done with your provider with a paid SSL certificate or a free one available from https://letsencrypt.org/. The free one is not as secure as the paid one since the paid one uses the payment transaction itself to verify identity.

    1. Just switch domain names. That is all

      ## redirect http://www.cyberciti.biz to http://cyberciti.biz/
      server {
          listen       80;
          access_log  off;
          error_log   off;
          server_name  www.cyberciti.biz
          return       301 http://cyberciti.biz$request_uri;
      }
      ## Continue below for cyberciti.biz
      server {
          listen       80;
          access_log  off;
          error_log   off;
          server_name  cyberciti.biz;
          ## rest of config below ##
      }
      ## ssl config ##
      server {
              listen 443 ssl http2;
              access_log  off;
              error_log   off;
              server_name www.cyberciti.biz;
              return 301 https://cyberciti.biz$request_uri;
      }
      ## define our https://cyberciti.biz/ ##
      server {
          listen 443 ssl http2;
          access_log  /var/log/nginx/www.cyberciti.biz_access.log;
          error_log  /var/log/nginx/www.cyberciti.biz_error.log;
          ## server name and root
          server_name  cyberciti.biz;
          root        /home/lighttpd/cyberciti.biz/http;
       
          # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
          ssl_certificate /etc/nginx/ssl/letsencrypt/cyberciti.biz/cyberciti.biz.crt;
          ssl_certificate_key /etc/nginx/ssl/letsencrypt/cyberciti.biz/cyberciti.biz.key;
          ssl_session_timeout 1d;
          ssl_session_cache shared:SSL:50m;
          ssl_session_tickets off;
          # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
          ssl_dhparam /etc/nginx/ssl/letsencrypt/cyberciti.biz/dhparams.pem;
       
          # intermediate configuration. tweak to your needs.
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_ciphers 'ECDHE-ECDSA-CHACHA20
          ## rest of config
      
  2. you can reduce this a little, ie for your two port 80 sections, you can use one:

    ## redirect www.cyberciti.biz to https://www.cyberciti.biz/
    server {
        listen      80;
        access_log  off;
        error_log   off;
        server_name www.cyberciti.biz cyberciti.biz;
        return      301 https://www.cyberciti.biz$request_uri;
    }

    But, I might suggest this is even better:

    ## redirect www.cyberciti.biz to https://www.cyberciti.biz/
    server {
        listen      80;
        access_log  off;
        error_log   off;
        server_name www.cyberciti.biz cyberciti.biz;
        location ~ /.well-known/acme-challenge/(.*) {
           allow all ; 
           root /var/nginx/letsencrypt;
       }
       location / {
          return      301 https://www.cyberciti.biz$request_uri;
      }
    }

    This way you get to use the acme challenge for letsencrypt on port 80 without messing around. The final redirect might as well rewrite the servername to “www” as well, there’s nothing gained by using the servername in functionaility or readability.

  3. Could you do the config below to redirect http://www.cyberciti.biz and http://cyberciti.biz and https://cyberciti.biz to https://www.cyberciti.biz/

    server {
    ## this redirects these 2 http://www.cyberciti.biz and http://cyberciti.biz 
        listen 80;
        server_name www.cyberciti.biz cyberciti.biz;
        return 301 https://www.cyberciti.biz$request_uri;
    }
     
    server {
    ## this redirects this one https://cyberciti.biz
        listen 443 ssl;
        server_name www.cyberciti.biz cyberciti.biz;
        return 301 https://www.cyberciti.biz$request_uri;
    ## add ssl and the rest of your server config info here
    }
  4. Sorry I for got to do the code tag so it messed up the server_names.

    Could you do the config below to redirect http://www.cyberciti.biz and http://cyberciti.biz and https://cyberciti.biz to https://www.cyberciti.biz/

    server {
        ## this redirects these 2 http://www.cyberciti.biz and http://cyberciti.biz
        listen 80;
        server_name www.cyberciti.biz cyberciti.biz;
        return 301 https://www.cyberciti.biz$request_uri;
    }
     
    server {
        ## this redirects this one https://cyberciti.biz
        listen 443 ssl;
        server_name www.cyberciti.biz cyberciti.biz;
        return 301 https://www.cyberciti.biz$request_uri;
     
        ## add ssl and the rest of your server config info here
    }

Leave a Comment