0

Before adding ssl_certificate, my nginx.conf is very simple:

server {
    listen 80 default_server;

    index index.php index.html index.htm;

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info  ^(.+\.php)(/.+)$;
        fastcgi_index            index.php;
        fastcgi_pass             php:9000;
        include                  fastcgi_params;
        fastcgi_read_timeout     1200s;
        fastcgi_param   PATH_INFO       $fastcgi_path_info;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Then I followed here to set Up letsencrypt with Nginx (replacing [domain-name] throughout), and now my nginx.conf looks like:

server {
    listen 80 default_server;

    server_name [domain-name] www.[domain-name];
    server_tokens off;

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

    location / {
        return 301 https://[domain-name]$request_uri;
    }
}

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

    server_name [domain-name];

    ssl_certificate /etc/nginx/ssl/live/[domain-name]/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/[domain-name]/privkey.pem;
    
    location / {
        proxy_pass http://[domain-name];
    }

    index index.php index.html index.htm;

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info  ^(.+\.php)(/.+)$;
        fastcgi_index            index.php;
        fastcgi_pass             php:9000;
        include                  fastcgi_params;
        fastcgi_read_timeout     1200s;
        fastcgi_param   PATH_INFO       $fastcgi_path_info;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

See the changes here -- https://www.diffchecker.com/bAfVjewE/,

enter image description here

which I think is very simple, straightforward, and reasonable.

However, my php site is completely broken -- My chrome browse says it gets into endless redirect ("redirected you too many times"), see Notes 2.

What might be the cause, and fix?

Notes,

  1. The adding of ssl_certificate is fine, but the endless redirect is there even when I tested with an empty site.
  2. When endless redirect happens, the nginx logs kept printing nothing but ...[08/Aug/2024:15:xx:yy +0000] "GET / HTTP/1.1" 301 162 "-" "Mozilla/5.0 (X11; Linux x86_64)..., even thought I've seen that the protocol on my browser has changed from http to https.

If I visit it with curl, I'm getting:

$ curl -i https://my.site.name:443/
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 08 Aug 2024 15:42:45 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Location: https://my.site.name/

<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>

and the server log is:

[08/Aug/2024:15:42:45 +0000] "GET / HTTP/1.1" 301 162 "-" "curl/8.5.0" "my.ip"
[08/Aug/2024:15:42:45 +0000] "GET / HTTP/1.1" 301 162 "-" "curl/8.5.0" "-"

And the error log is empty, as this is how my ngix logging is configed:

cd /var/log/nginx/

root@5b6a9033cb31:/var/log/nginx# ls -l
total 0
lrwxrwxrwx 1 root root 11 Jul 23 07:14 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 Jul 23 07:14 error.log -> /dev/stderr
9
  • 1
    Add the contents of the Nginx log when this is happening. Commented Aug 8, 2024 at 6:06
  • 1
    I don't understand where location / { proxy_pass http://[domain-name]; } suddenly came from. Commented Aug 8, 2024 at 7:42
  • See my updated "Notes" section please, @NasirRiley. Commented Aug 8, 2024 at 15:45
  • There should be a /var/log/nginx/error_log. Add that Commented Aug 8, 2024 at 17:31
  • Ah, might it be the combination effect of both return 301 https:// and proxy_pass http://? error log is empty, see my updated OP, @NasirRiley. Commented Aug 8, 2024 at 17:35

1 Answer 1

2

The problem is the first server block listens on port 80 (HTTP) and redirects all traffic to HTTPS (https://[domain-name]$request_uri).

The second server block listens on port 443 (HTTPS) and proxies traffic back to the same domain (proxy_pass http://[domain-name];).

That creates a redirect loop.

User requests http://my.site.name

The server redirects to https://my.site.name

The HTTPS server proxies the request back to http://my.site.name

The HTTP server redirects to https://my.site.name

And the loop continues....

To fix it, you must make sure that the HTTPS server is not proxying back to the HTTP server. Instead, it should serve the content directly.

Like this:

server {
    listen 80 default_server;
    server_name [domain-name] www.[domain-name];
    server_tokens off;

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

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

server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;
    server_name [domain-name];

    ssl_certificate /etc/nginx/ssl/live/[domain-name]/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/[domain-name]/privkey.pem;

    root /var/www/html;  # Adjust this path to your web root if needed

    index index.php index.html index.htm;

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

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

So, try_files $uri $uri/ /index.php?$query_string; in the HTTPS block ensures that requests are served correctly without needing to proxy back to HTTP.

The location ~ .php$ { ... } block is set to handle PHP files directly in the HTTPS server.

The return 301 https://$host$request_uri; in the HTTP block ensures all HTTP requests are redirected to HTTPS.

Correct the code, then run nginx -s reload and it should work.

############### EDITED ################

You don't need to remove the Nginx reverse proxy to fix the issue. You can still benefit from the reverse proxy by ensuring the proxying occurs within the same protocol (i.e., HTTPS).

One approach is to adjust the proxy_pass directive in the HTTPS server block to use https:// instead of http://. This ensures that once traffic is redirected to HTTPS, it stays within the HTTPS context, preventing the loop:

location / {
    proxy_pass https://[domain-name];
    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;
}

This way, you can still leverage the benefits of Nginx's reverse proxy while resolving the redirect loop issue. If you need any further assistance with this setup, feel free to reach out!

2
  • 1
    Ahh, I thought it's "the combination effect of both return 301 https:// and proxy_pass http://", but don't understand why people still ask irrelevant questions even afterwards. Thanks for the confirmation, but I don't think removing the nginx reverse proxy is a good answer, as I want it for the benefit of it. Still, thanks for the answer, upvoting! Commented Aug 9, 2024 at 15:20
  • Thanks, I have added the code to keep the reverse proxy. Commented Aug 9, 2024 at 23:10

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.