HTTPS www to non-www on NGINX

309 Views Asked by At

I'm having issues redirecting from www to non-www only for https/ssl. Any ideas why this might be happening? It works fine for non-secure URL's. Here's my config:

html {
    # Compression

    # Enable Gzip compressed.
    gzip on;

    # Enable compression both for HTTP/1.0 and HTTP/1.1.
    gzip_http_version 1.1;

    # Compression level (1-9).
    # 5 is a perfect compromise between size and cpu usage, offering about
    # 75% reduction for most ascii files (almost identical to level 9).
    gzip_comp_level 5;

    # Don't compress anything that's already small and unlikely to shrink much
    # if at all (the default is 20 bytes, which is bad as that usually leads to
    # larger files after gzipping).
    gzip_min_length 128;

    # Compress data even for clients that are connecting to us via proxies,
    # identified by the "Via" header (required for CloudFront).
    gzip_proxied any;

    # Tell proxies to cache both the gzipped and regular version of a resource
    # whenever the client's Accept-Encoding capabilities header varies;
    # Avoids the issue where a non-gzip capable client (which is extremely rare
    # today) would display gibberish if their proxy gave them the gzipped version.
    gzip_vary on;

    # Compress all output labeled with one of the following MIME-types.
    gzip_types application/atom+xml application/x-javascript application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component;
}

server {
    listen 80;
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen *:443 ssl;
    server_name www.example.com;
    return https://example.com$request_uri 301;
}

server {
    listen 443 ssl;
    server_name example.com;
    root /home/forge/default/public;

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/default-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_param DB_PASSWORD "password";
        fastcgi_param DB_USERNAME "user";
        fastcgi_param DB_NAME "db";
        fastcgi_param DB_HOST "localhost";
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    # Expire rules for static content

    # cache.appcache, your document html and data
    location ~* \.(?:manifest|appcache|html?|xml|json)$ {
      expires -1;
      # access_log logs/static.log; # I don't usually include a static log
    }

    # Feed
    location ~* \.(?:rss|atom)$ {
      expires 1h;
      add_header Cache-Control "public";
    }

    # Media: images, icons, video, audio, HTC
    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
      expires 1M;
      access_log off;
      add_header Cache-Control "public";
    }

    # CSS and Javascript
    location ~* \.(?:css|js)$ {
      expires 1y;
      access_log off;
      add_header Cache-Control "public";
    }
}
2

There are 2 best solutions below

1
On BEST ANSWER

OK, so I figured this out a while ago but forgot to post the answer, so here it is.

server {
    listen 80;
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;
    root /home/forge/default/public;

    if ($host = 'www.example.com') {
        rewrite ^/(.*)$ https://example.com/$1 permanent;
    }
}

How robust this is I'm not entirely sure but it works.

Essentially, you listen on port 80 for www and non-www and return a 301 redirect to the secure non-www URL. You then check in your SSL server block listening on port 443 if the host that has been requested matches the www version of the secure URL and if it does you permanently rewrite it to the secure non-www version.

0
On

nginx takes SSL-certificate from 'default_server' or from first described for the particular IP+port pair.

So, you should

  • swap SSL-enabled server blocks
  • or just add default_server parameter to listen directive in your second block.