Nginx and Discourse is redirect looping with SSL

AI-generated summary

Semaphorism reported an SSL redirect loop (ERR_TOO_MANY_REDIRECTS) when running Discourse behind Nginx, using ports 5001 (HTTP) and 5002 (HTTPS), with a config based on a DigitalOcean tutorial. After initially claiming to have fixed it by updating the Nginx config to properly set proxy headers and use localhost instead of the domain, Semaphorism later clarified the issue persisted intermittently across devices and browsers. They discovered the root cause was Cloudflare’s proxying — disabling Cloudflare routing resolved the loop. mpalmer suggested notifying DigitalOcean to update their outdated article. Key takeaway: When using Cloudflare with Discourse + Nginx, proxying can interfere with SSL redirects; test by disabling Cloudflare or bypassing it via hosts file. Ensure Nginx correctly forwards headers like X-Forwarded-Proto to avoid misconfigured redirects.

I have Discourse on port 5001 (HTTP), and 5002 (HTTPS), but the problem is that its redirect looping, also known as ERR_TOO_MANY_REDIRECTS on Chrome.

My Nginx configuration, with SSL. I got this configuration from DigitalOcean, specifically this article
I changed the SSL certificates, as well as the domain, and the port that I use. The configuration is using Lets Encrypt.

(I replaced the real domain with example.com)

server {
        listen 80;
        server_name example.com;
        return 301 https://example.com$request_uri;
}
server {
        listen 443 ssl spdy; 
        server_name example.com;
        ssl_certificate *****;
        ssl_certificate_key *****;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        ssl_prefer_server_ciphers on;
        location / {
                proxy_pass      http://example.com:5001/;
                proxy_read_timeout      90;
                proxy_redirect  http://example.com:5001/ https://example.com;
        }
}

Help appreciated, I am not sure if I should enable SSL on discourse or not, but I would assume so.

I found a fix for it. Sorry for the post. took me a while to understand what is happening. The Digital Ocean article should probably be fixed up.

This is what I used for configuration, it works for me.

server {
    listen 80;
    location / {
      proxy_set_header        Host $host;
      proxy_set_header        X-Real-IP $remote_addr;
      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header        X-Forwarded-Proto $scheme;

      proxy_pass          http://localhost:5001;
      proxy_read_timeout  90;
    }
}

server {

    listen 443;
    server_name example.com;

	ssl_certificate /var/discourse/shared/standalone/ssl/example.com.cer;
	ssl_certificate_key /var/discourse/shared/standalone/ssl/example.com.key;

    ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    access_log            /var/log/nginx/example.com.access.log;

    location / {

      proxy_set_header        Host $host;
      proxy_set_header        X-Real-IP $remote_addr;
      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header        X-Forwarded-Proto $scheme;

      proxy_pass          https://localhost:5002;
      proxy_read_timeout  90;
    }
  }

5002 is my Discourse SSL port, and 5001 is regular HTTP on discourse.
nginx serves 443 and 80

You’ll probably want to let DigitalOcean know to fix their article, then. We don’t have any editorial control over what they have on their site.

Well, apparently I was wrong.

I am still having the redirect loop issue, but only on some of my devices, and some browsers. I am completely unsure what is happening now, and could use help from someone with good experience with nginx.

I should also mention the website is behind cloudflare, which may have a factor in this issue, or could be the issue itself, unsure.

Edit: I disabled routing through cloudflare, and it appears to have resolved my issue, so take note, if you have a redirect issue using when using cloudflare, try disabling the routing for a bit of time and see if it fixes it. If you can’t disable that, then try changing your DNS to your server manually via hosts file.