NGINX HTTP to HTTPS and Non-WWW to WWW Redirect Configuration

While setting up LetsEncrypt to work with CloudFlare, I ran into a bunch of issues with my NginX config that caused me a bunch of downtime. Because I run multiple domains, I wanted to keep my non-www to www URL redirects and also redirect HTTP to HTTPS.

Before, I was using just:

server {
server_name "~^([^.]*\.[^.]*)$";
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
return 301 $scheme://www.$host$request_uri;
}

It’s an incredibly elegant redirect. But it didn’t work well with my HTTPS redirect. So, I changed it to be a bit easier to understand (and more time-consuming to set up), which looks like this:

# NGINX Server Block for:
# Redirect non-www base domain (domain.com) to www (www.domain.com)
# Redirect HTTP to HTTPS SSL (HTTP2)
# Supports multiple domains and subdomains
# Created by George Liu (www.georgeliu.me / Github:tgmgroup)
# STEP 1 - Base HTTPS Block
server {
#Listen only on HTTPS, use STEP 3 to redirect from HTTP
listen 443 ssl http2;
listen [::]:443 ssl http2;
# Put Includes Here
# Change .domain1.com and .domain2.com to your own domain
# The .domain1.com wildcard format (DOT domain) catches all domains and subdomains of domain1.com
server_name .domain1.com .domain2.com;
# Put Server Configs Here
# Put Other Configs Here
}
# STEP 2 -  Redirect base (non-www URL) to HTTPS www
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
# Catch only www subdomains on HTTP and HTTPS
server_name domain1.com domain2.com;
# Permanent redirect to HTTPS and www
return 301 https://www.$host$request_uri;
# Use the following if redirecting www to non-www URLs
#        server_name www.domain1.com www.domain2.com;
#        return 301 https://$host$request_uri;
# If using both HTTPS and HTTP (only www redirect), edit STEP 1 to include
#        listen 80;
#        listen [::]:80;
# and remove STEP 3
# and change the return 301 line to use "$scheme://" instead of "https://"
}
# STEP 3 -  Redirect all non- base-non-www HTTP to HTTPS
server {
listen 80;
listen [::]:80;
# Catch all base and subdomains on HTTP, including redirects from STEP 2
server_name .domain1.com .domain2.com;
# If user prefers, use "www.domain1.com *.domain1.com" combination instead of
# ".domain1.com" wildcard to avoid NGINX warnings
return 301 https://$host$request_uri;
}
view raw config hosted with ❤ by GitHub

Don’t forget the linux commands to edit and restart NginX

sudo nano /etc/nginx/sites-enabled/(config)
sudo nginx -t && sudo service nginx restart (OR) sudo systemctl restart nginx

And don’t forget to change your DNS settings at your DNS provider:

add a CNAME record: www as name and @ as hostname

Resources: 1, 2, 3, 4, 5, 6, 7, 8