jefarrell
By:
jefarrell

Nginx not redirecting to www

July 21, 2016 910 views
Nginx DNS Ubuntu

I've read the similar posts here but still not having any luck. I want to redirect any non-www traffic to www (example.com -> www.example.com), and keep the domain name in the address bar, not the IP address..

The DNS is on dreamhost, pointed to my DO droplet running Ubuntu 14.04.4. Right now both www.example.com and example.com go to my site, and keep the domain in the address bar. But it's not inserting 'www'.

It's a node app running on port 3000. I have an A record (@ droplet.ip.add.ress) and a CNAME (www "example.com."). I've also tried that with two A records doing (@ droplet.ip.add.ress) & (www my.ip.address).

My Nginx sites-available default looks like this:

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

server {
        listen                  80;
        server_name     $scheme://www.example.com;

        location / {
                proxy_pass                      http://localhost:3000;
                proxy_http_version         1.1;
                proxy_set_header           Upgrade $http_upgrade;
                proxy_set_header           Connection 'upgrade';
                proxy_set_header           Host $host;
                proxy_cache_bypass      $http_upgrade;
        }
}

Running "nginx -t" says my syntax and is fine and .conf test is successful. Oddly, trying to ping them or curl -I tells me it can't resolve the host... But the site works on my phone, on different browsers, on incognito etc.

Pretty stuck but seemingly really close so any help is really appreciated!

3 Answers

Your config looks fine assuming you changed example.com to your actual domain. But if your app is running on port 3000, you need to change listen 80 to listen 3000.

  • I may be misunderstanding it, but isn't that the point of the proxy pass, to have traffic on port 80 passed to port 3000? That is actually the part that is working fine.

Hi!

You need to replace server_name $scheme://www.example.com; with server_name www.example.com;. server_name takes only the hostname, not the actual URL. Your DNS records look correct.

Also—please add proxy_set_header Proxy ""; after the other proxy_set_header lines in order to protect your server against the HTTPoxy Vulnerability.

Make sure you reload/restart nginx so that the changes take effect.

On July 18th, 2016, a CGI application vulnerability, referred to as "HTTPoxy", was disclosed. By passing an HTTP Proxy header with a request, an attacker can exploit vulnerable deployments by causing HTTP requests to backing services to be redirected to an arbitrary web...
  • No errors, reloaded nginx, but no luck. Current default:

    server {
            listen          80;
            server_name     example.com;
            return          301 www.example.com$request_uri;
    }
    
    server {
            listen          80;
            server_name     www.example.com;
    
            location / {
                    proxy_pass              http://localhost:3000;
                    proxy_http_version      1.1;
                    proxy_set_header        Upgrade $http_upgrade;
                    proxy_set_header        Connection 'upgrade';
                    proxy_set_header        Host $host;
                    proxy_set_header        Proxy "";
                    proxy_cache_bypass      $http_upgrade;
            }
    }
    
    
    • Try adding scheme to the return url

      return 301 $scheme://www.example.com$request_uri;

      Also one other tip is to test it on incognito mode because browsers will cache redirects.

I had a similar problem. I wanted to redirect all traffic to only the https://www version of my website.
I had this kind of config in my site-available/example.com :

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

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

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    root /var/www/example.com/html;

    index index.html;

    server_name www.example.com;

    ---------------
    various SSL configs

}

But it wouldn't redirect example.com to https://www.example.com, it would redirect to https://example.com.
I also tried to use $scheme but it didn't fix it.

What fixed it was to change the order of the servers, starting with my https://www like this:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    root /var/www/example.com/html;

    index index.html;

    server_name www.example.com;

    ---------------
    various SSL configs

}

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

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

I am still new to linux and server management so I don't know much why it is working with this config and not with the config I found everywhere on the web, but at least it is working.

  • Just did some checks on ssllabs.com and get A+ on www.example.com site and A on example.com. I'm not sure why either but it should be good enough for hosting simple static websites.

    If anyone here got an explanation about this behavior I'd be glad to listen.
    There is so much stuff I need to learn about!

Have another answer? Share your knowledge.