How to Properly Redirect HTTPS WWW to Non-WWW in Nginx with SSL Certificate


2 views

When your SSL certificate is issued for mydomain.com but not for www.mydomain.com, browsers will show security warnings for HTTPS requests to the www version. This happens because the certificate doesn't cover the www subdomain.

Here's the proper way to handle all redirects while maintaining SSL security:

# HTTP to HTTPS redirect for both www and non-www
server {
    listen 80;
    server_name www.mydomain.com mydomain.com;
    return 301 https://mydomain.com$request_uri;
}

# HTTPS www to non-www redirect
server {
    listen 443 ssl;
    server_name www.mydomain.com;
    
    ssl_certificate /usr/local/nginx/conf/public.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
    
    return 301 https://mydomain.com$request_uri;
}

# Main HTTPS server block
server {
    listen 443 ssl;
    server_name mydomain.com;
    
    ssl_certificate /usr/local/nginx/conf/public.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
    
    root /var/www/mysite;
    index index.php;
    client_max_body_size 100M;
    
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
  • Used return 301 instead of rewrite for better performance
  • Properly separated the SSL configuration for www and non-www versions
  • Fixed the SCRIPT_FILENAME parameter to use $document_root
  • Added proper try_files directive for better URI handling

After implementing these changes, test all possible combinations:

curl -I http://www.mydomain.com
curl -I http://mydomain.com
curl -I https://www.mydomain.com
curl -I https://mydomain.com

All www requests should return 301 redirect status to the non-www HTTPS version.


When your SSL certificate only covers the base domain (mydomain.com) but not the www subdomain (www.mydomain.com), browsers will throw security warnings for HTTPS requests to the www version. This occurs because:

  • The certificate doesn't validate www.mydomain.com
  • Nginx is attempting to serve HTTPS content for an unvalidated domain
  • The redirect happens after the SSL handshake, which is too late

Here's the proper way to configure this in Nginx:

# HTTP server block - handles both www and non-www
server {
    listen 80;
    server_name www.mydomain.com mydomain.com;
    return 301 https://mydomain.com$request_uri;
}

# HTTPS server block for www - ONLY for redirect
server {
    listen 443 ssl;
    server_name www.mydomain.com;
    
    ssl_certificate /usr/local/nginx/conf/public.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
    
    return 301 https://mydomain.com$request_uri;
}

# Main HTTPS server block
server {
    listen 443 ssl;
    server_name mydomain.com;
    
    ssl_certificate /usr/local/nginx/conf/public.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
    
    root /var/www/mysite;
    index index.php;
    client_max_body_size 100M;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_index index.php;
    }
}

The original configuration had several issues that we've fixed:

  1. Separate SSL server block specifically for www redirect
  2. Using return 301 instead of rewrite for better performance
  3. Proper use of $request_uri instead of regex capture groups
  4. Correct fastcgi_param SCRIPT_FILENAME using $document_root

After implementing these changes, verify the redirects work correctly:

curl -I http://www.mydomain.com
curl -I http://mydomain.com 
curl -I https://www.mydomain.com
curl -I https://mydomain.com

All www requests should return 301 status code pointing to the non-www HTTPS version.

For future certificates, consider:

  • Getting a wildcard certificate (*.mydomain.com)
  • Using Let's Encrypt with DNS-01 challenge
  • Adding Subject Alternative Names (SANs) for both domains