2

I'm developing a Django app with nginx reverse proxy and gunicorn application server. Being a newbie web developer, I need help with redirecting www traffic to no www at the webserver level. I'm currently doing the same at the middleware level inside the app, but need to improve performance.

Currently my nginx virtual host file is laid out as follows:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=100m inactive=6m;

upstream my_server {
    server unix:/home/myuser/myproject/myfolder/myproject.sock  fail_timeout=0;
}

server {
    listen 80;
    server_name example.com www.example.com;

    # a bunch of 'location' blocks e.g. 'location /' or 'location @http_proxy_to_app', etc. 

}

server {

    listen 443 ssl;
    server_name example.com www.example.com;

    # SSL related stuff

    # a bunch of 'location' blocks e.g. 'location /' or 'location @http_proxy_to_app', etc.

}

How would I redirect www to no-www in this scenario? Most of the examples I've seen explain that I need to add one more dedicated server block at the top like so:

server {
        server_name www.example.com;
        return 301 $scheme://example.com$request_uri;
}

Other suggestions have been to include something like the following inside my server blocks (inside location /). I'm unsure whether this would be compatible with reverse proxy related code:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}

Being a newbie, I wanted to confirm which practice to use (and why) given how my nginx file is currently laid out, hence this question.


Here's what my actual config looks like:

server {

server_name example.com;
listen 443 ssl;

#ssl_certificate /etc/ssl/certs/ssl-bundle.crt;
ssl_certificate /etc/nginx/ssl/cert_chain.crt;
#ssl_certificate_key /etc/ssl/myserver.key;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
#ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
#ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5; 
ssl_session_cache shared:SSL:1250m;
ssl_session_timeout 180m;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_stapling on;
ssl_stapling_verify on;
#ssl_trusted_certificate /etc/ssl/COMODO_DV_SHA-2_under_SHA-2root.crt;
ssl_trusted_certificate /etc/nginx/ssl/example_com.ca-bundle;

# write error log file for https errors:
error_log /var/log/nginx/https-error_log warn;

location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { root /home/myuser/myproj/myapp; expires 24h; add_header Vary Accept-Encoding; access_log off; }

.... more config to follow ...

}
2

The preferred setup for a web server handling http://example.com, https://example.com, http://www.example.com and https://www.example.com is the following when the example.com domain and https are preferred:

server {
    server_name example.com www.example.com;

    listen 80;

    return 301 https://example.com$request_uri;
}

server {
    server_name www.example.com;

    listen 443 ssl;

    return 301 https://example.com$request_uri;
}

server {
    server_name example.com;

    listen 443 ssl;

    ... actual server configuration ...
}

In this setup, there is only one actual URL https://example.com for reaching the site content, which is good for indexing. In your current setup, the same site content is available with all URLs, which causes duplicate issues with Google.

Defining a separate virtual host for the redirects is the preferred way, because evaluating the if statement causes duplicate work for requests already coming in to the correct virtual host block.

|improve this answer|||||
  • Question: my actual server config is currently two server blocks, one with listen 80 and another with listen 443 ssl;. If I were to keep that constant while first only introducing redirection in my set up, would I simply add the top two server blocks you've written in your answer. Yes I know it makes listen 80 redundant once it's functioning correctly, but I just want to do it one step at a time without breaking anything. I hope you get what I'm asking. – Hassan Baig Jul 27 '17 at 10:19
  • 1
    You should make an identical testing environment for your changes and verify configuration in that before making changes to the production environment. And no, you cannot simply add those two blocks to your configuration, because then you would have two definitions for example.com:80, www.example.com:80 and example.com:443. There can be only one configuration for each domain:port pair. – Tero Kilkanen Jul 27 '17 at 11:44
  • Actually the correct term here is FQDN, Fully Qualified Domain name. Those must be separate. Second block FQDN is www.example.com and third block FQDN is example.com. – Tero Kilkanen Jul 29 '17 at 16:41
  • Another follow up question: when I try this solution, it doesn't work and nginx's error log shows me *922862344 no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking, client: 69.171.225.149, server: 0.0.0.0:443. Do note that in my original nginx set up, SSL works perfectly. – Hassan Baig Sep 21 '17 at 20:45
  • 1
    You need the certificate configuration in every server block where you have listen 443 ssl;. – Tero Kilkanen Sep 21 '17 at 21:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.