Nginx ERR_TOO_MANY_REDIRECTS – Fix WordPress Permalinks 301 Error on Ubuntu 18.04

301-redirectnginxpermalinksubuntu-18.04Wordpress

  • OS: Ubuntu 18.04.5 LTS (having my own VPS)
  • WebServer: Nginx/1.18.0
  • MySQL: mysql Ver 8.0.22 for Linux on x86_64 (MySQL Community Server – GPL)
  • WordPress: 5.6

When I change the Permalinks option in WordPress (ScreenShot: /wp-admin/options-permalink.php) from the default (?p=123) to /%postname%/ (the last option on the page) I get the following error: "ERR_TOO_MANY_REDIRECTS" with status code 301 only for the Homepage (so directly example.com), all other pages working perfect, even the new permalink option is working right such that the default blog is accessible by: /hello-world/ directly.

Any idea why? This was the last thing to do such that my Server was finished, spent more time on this small bug than everything else lol. Note: I have disabled every plugin and except nginx cache which I use to clear the server-side caching. Also I visit the website incognito.

I followed this tutorial: SpinUp WP (I did everything till and including CH6).
Hereby my NGINX Settings:

NGINX Config File (I have changed username to omar, for privacy reasons):

user omar;
worker_processes 6;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 1024;
        multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        keepalive_timeout 15;
        types_hash_max_size 2048;
        server_tokens off;
        client_max_body_size 64m;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;


        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 5;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Cache Settings
        ##
        fastcgi_cache_key "$scheme$request_method$host$request_uri";
        add_header Fastcgi-Cache $upstream_cache_status;


        ##
        # Security
        ##
        add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always;
        add_header X-Xss-Protection "1; mode=block" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "origin-when-cross-origin" always;



        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
        server {
            listen 80 default_server;
            listen [::]:80 default_server;
            server_name _;
            return 444;
        }
}

Config file of example.com (I have changed username to omar and domain to example.com, privacy reasons):

fastcgi_cache_path /home/omar/example.com/cache levels=1:2 keys_zone=example.com:100m inactive=60m;

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

server_name example.com;

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

access_log /home/omar/example.com/logs/access.log;
error_log /home/omar/example.com/logs/error.log;

root /home/omar/example.com/public/;
index index.php;

set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}

# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}

if ($request_uri ~* "/(cart|checkout|my-account)/*$")
{
set $skip_cache 1;
}

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

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache example.com;
fastcgi_cache_valid 60m;
}
}

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

server_name www.example.com;;

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

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

server {
listen 80;
listen [::]:80;

server_name example.com www.example.com;;

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

If I need more things to show just tell me, I will show more.

Best Answer

Alhamdulillah, I found the answer. It was all due to trying to be perfectionist Muslim, I had capital letters in the URL inside: /wp-admin/options-general.php. All praises to God (Alhamdulillah), solved, by making all the letters lowercase. With God his will (in shaa Allah) it will help you brothers and non-brothers.