Why are my 301 redirects not working? IPv6 Users also show as localhost


#1

I’ve seen some other topics about this but can’t get it working for the life of me. Discourse was installed following the official documentation. All the plugins are official.

Users coming from an IPv6 connection were having their IP displayed as 127.0.0.1 all of a sudden (forum had been in active use for a few days just fine, I had only added the official Discourse plugins. Rebuilds made no difference). I assumed this was something that could be fixed with the X-Forwarded-For header. I knew properly configured Nginx would probably fix this, and I’d been meaning to set up a maintanence page anyway, so I downloaded, set up, and installed it as outlined here: Adding an offline page when rebuilding

IPs now started displaying correctly, and of course the offline page works fine. However, my 301 rules are being mishandled somehow (not redirecting from non-www to www, and not redirecting IP at all).
Running `curl -I example com/’ returns a status code of 301, and the location points to the http subdomain (that’s fine, all of my http requests are being redirected to https correctly) but visiting the root domain in a browser won’t cause you to be redirected. This causes SSL errors when trying to connect through any other domain - the certificate is invalid obviously, and I only want users coming to my www subdomain anyway.

How do I set up redirection in my Nginx configuration to redirect all requests to my IP and example .com to www.example .com? Below is my Nginx configuration file. I think I’m missing something obvious, coming from Apache I’m not quite sure what it is, though. On the other hand, if I could fix the problem of IPv6 users showing up as localhost, I wouldn’t bother with this.

Nginx conf
server {
        listen 80; listen [::]:80;
        server_name  www.example.com;  # <-- forum domain

        location /.well-known/acme-challenge/ {
                root /var/www;
        }

        location / {
                return 301 https://$host$request_uri;
        }
}

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

server {
  listen 443 ssl http2;  listen [::]:443 ssl http2;
  server_name  www.example.com;  

  ssl on;
  ssl_certificate      /etc/letsencrypt/live/www.example.com/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/www.example.com/privkey.pem;

  ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES12$
  ssl_protocols TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  add_header Strict-Transport-Security "max-age=63072000;";
  ssl_stapling on;
  ssl_stapling_verify on;

  client_max_body_size 0;

  location / {
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    error_page 502 =502 /errorpages/discourse_offline.html;
    proxy_intercept_errors on;
  }

  location /errorpages/ {
    alias /var/www/errorpages/;
  }
}

(Matt Palmer) #2

In order to do a redirect over SSL, you need to have a valid certificate for the name you’re redirecting from.


#3

Alright, I can set up certificates and server blocks for the root domain, which sounds like it will fix the main issue (will do so shortly).

However, how do I redirect from my IP to the forums URL, seeing as you can’t cert my IP anyway? This is where I feel like I’m really missing some piece of information.


(Matt Palmer) #4

You can get a certificate for an IP address. But what kind of weirdo is typing IP addresses into HTTPS URLs and expecting sensible results?


#5

Added certificate for my root domain through certbot. Root domain now functions as you would expect, but does not redirect to www still (wondering, how do I fix that now? Www redirects seem OK to me in that configuration. My Nginx configuration didn’t change at all, I just added the domain to the cert.

And uh, you know, good point… probably nobody sane and nothing to worry about. Just something I noticed

Thank you for pointing out my main error here


(Felix Freiberger) #6

You don’t have a server block listening on port 443 that covers example.com. That means that Nginx will have to fall back to some other server block, most likely the www.example.com one.

Personally, I always make sure I have a single server block for port 80 that handles acme-challenge and redirects to HTTPS, independent of the server_name. Then, for each domain, add one server block for HTTPS with appropriate handling (redirect or proxy_pass).


#7

I understand what you’re saying here, and have gotten the request to redirect to my www. subdomain. But it raises the error of “Too many redirects” on Chrome - no matter how I try to implement it. That means regardless of whether or not I am using a separate server block for HTTPS with handling for redirection, I’m always ending up in a redirect loop. I’m almost positive I have the regular port 80 domain down and into one block correctly (removed the second block you see in the OP, first block now handles port 80).

Can you show me an example of a working non-www to www redirect in a server block for external Nginx listening on port 443 for Discourse? I’m sure I’ll be able to land on the right configuration eventually, but I think I’m confusing myself unintentionally.


(Felix Freiberger) #8

Are you sure this isn’t due to a cached 301 redirect?

I don’t have such a configuration lying around here, but if you post yours, I can take another look :slight_smile:


#9

Turned out to be a bad configuration for the new server block handling the redirection on port 443 for example.com, forgot to specify http2 (and a couple minor changes). Not entirely sure that was the cause of the loop, but it has been working correctly now. Thank you both very much, @fefrei and @mpalmer!

One thing I would be very curious to know is why IPv6 connections were showing up as 127.0.0.1? This was only when not using external Nginx. I didn’t change anything inside the Docker container. Just using the default templates in app.yml for networking. We are not on a private network, but the VPS has private networking, though I don’t see that being relevant.