Resolving Apache htaccess Redirect Loop 500 Internal Server Error on Ubuntu 20.04 LTS

Written by

in

Troubleshoot and fix Apache 500 Internal Server Errors caused by infinite redirect loops in .htaccess files on Ubuntu 20.04 LTS servers.

When managing web servers, few issues are as frustrating and immediately impactful as a "500 Internal Server Error" due to an Apache .htaccess redirect loop. This common problem indicates that your Apache server, specifically its mod_rewrite module, is caught in an endless cycle of redirecting requests, eventually hitting an internal limit and failing. This guide provides a highly technical, step-by-step approach to diagnose and resolve this issue on an Ubuntu 20.04 LTS server running Apache 2.4.

Symptom & Error Signature

Users attempting to access your website will typically encounter one of the following:

  • Browser Output (Common):
  • * "500 Internal Server Error"
  • * "ERRTOOMANY_REDIRECTS" (e.g., in Chrome)
  • * "The page isn't redirecting properly" (e.g., in Firefox)
  • * A blank white page, sometimes after a long loading time.
  • Apache Error Log Output (/var/log/apache2/error.log):
  • You will likely see recurring entries indicating a redirect limit being exceeded. The exact message may vary slightly but will be similar to this:
    [Timestamp] [proxy:error] [pid XXXX:tid YYYYYYYYYYY] (X) [client IP_ADDRESS:PORT] AH01144: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
    [Timestamp] [core:crit] [pid XXXX:tid YYYYYYYYYYY] [client IP_ADDRESS:PORT] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
    ```
    You might also see `mod_rewrite` related debug messages if `LogLevel` is increased:
    ```
    [Timestamp] [rewrite:trace1] [pid XXXX:tid YYYYYYYYYYY] [client IP_ADDRESS:PORT] AH00666: [client IP_ADDRESS:PORT] (3) [main/htaccess] applying pattern '^$' to uri '/index.php'
    [Timestamp] [rewrite:trace1] [pid XXXX:tid YYYYYYYYYYY] [client IP_ADDRESS:PORT] AH00669: [client IP_ADDRESS:PORT] (3) [main/htaccess] rewrite '/index.php' -> '/index.php'
    ```

Root Cause Analysis

A 500 Internal Server Error caused by a redirect loop in .htaccess primarily stems from mod_rewrite rules that inadvertently create an infinite chain of redirects or rewrites. The underlying reasons typically fall into these categories:

  1. Infinite Rewrite Loop: The most common culprit. A set of RewriteRule or RewriteCond directives are configured such that a request, after being processed by one rule, is then matched again by the same rule or another rule that effectively sends it back to a state where the first rule applies again. This cycle continues until Apache's internal redirect limit (defaulting to 10 for internal rewrites) is exceeded, leading to the 500 error.
  1. Incorrect RewriteBase Directive: When .htaccess files are used in subdirectories, RewriteBase is crucial for correctly calculating the path for internal rewrites. An incorrectly set or missing RewriteBase can cause mod_rewrite to append the subdirectory path repeatedly, leading to an infinite loop as the URI keeps growing.
  1. Missing or Misplaced [L] (Last) Flag: The [L] flag tells mod_rewrite to stop processing further RewriteRule directives for the current request after a match. If this flag is omitted where needed, subsequent rules might re-evaluate the already rewritten URI, potentially sending it into a loop.
  1. Conflicting or Poorly Ordered Rules: When combining multiple redirect types (e.g., HTTP to HTTPS, www to non-www, adding/removing trailing slashes), the order of the rules is paramount. If, for instance, a non-www to www rule redirects to HTTP, and an HTTP to HTTPS rule then redirects to HTTPS, but doesn't correctly handle the www/non-www part, a loop can form.
  1. Proxy/Load Balancer Awareness: If Apache is behind a reverse proxy or load balancer (e.g., Nginx, AWS ELB/ALB), the mod_rewrite rules for HTTPS detection (RewriteCond %{HTTPS} off) might fail. The proxy terminates SSL and forwards requests to Apache via HTTP, making %{HTTPS} always appear off. This causes Apache to continually redirect to HTTPS, even if the user is already on HTTPS externally, creating a loop. The X-Forwarded-Proto header is crucial here.
  1. Syntactic Errors in modrewrite Directives: While less common for a redirect loop and more for a general 500 error, malformed regular expressions or incorrect modrewrite syntax can lead to unpredictable behavior, including loops if the engine misinterprets the rules.

Step-by-Step Resolution

Follow these steps meticulously to diagnose and resolve your Apache .htaccess redirect loop.

1. Verify mod_rewrite is Enabled and AllowOverride is Set

First, ensure the mod_rewrite module is enabled and that Apache is configured to allow .htaccess overrides for your web directory.

  1. Check mod_rewrite status:
  2. `bash
  3. sudo apache2ctl -M | grep rewrite
  4. `
  5. If rewrite_module is not listed, enable it:
  6. `bash
  7. sudo a2enmod rewrite
  8. sudo systemctl restart apache2
  9. `
  1. Check AllowOverride directive:
  2. The Apache configuration for your virtual host or directory must permit .htaccess overrides. Open your virtual host configuration file, typically located at /etc/apache2/sites-available/your-domain.conf or the main Apache configuration /etc/apache2/apache2.conf.
  3. Locate the <Directory> block for your web root (e.g., /var/www/html/):
    <Directory /var/www/html/>
        Options Indexes FollowSymLinks
        AllowOverride All # This MUST be All
        Require all granted
    </Directory>
    ```
    > [!IMPORTANT]
    > `AllowOverride All` is crucial for `.htaccess` files to be processed. If it's set to `None` or not explicitly defined, your `.htaccess` rules will be ignored or could lead to other issues. After modification, restart Apache:
    ```bash
    sudo systemctl restart apache2

2. Inspect Apache Error Logs for Clues

The Apache error log is your primary source of diagnostic information. It will often explicitly state that a redirect limit has been exceeded.

  1. Monitor the error log in real-time:
  2. `bash
  3. sudo tail -f /var/log/apache2/error.log
  4. `
  5. Attempt to access the problematic URL in your browser.
  6. Observe the log output. Look for messages similar to Request exceeded the limit of 10 internal redirects. This confirms a rewrite loop. The log might also indicate the specific path being repeatedly rewritten.

3. Temporarily Disable the .htaccess File

To confirm that the .htaccess file is indeed the source of the problem, temporarily disable it.

  1. Navigate to your website's document root:
  2. `bash
  3. cd /var/www/html/your-domain.com/public_html/ # Adjust path as necessary
  4. `
  5. Rename the .htaccess file:
  6. `bash
  7. mv .htaccess .htaccess_bak
  8. `
  9. Clear your browser cache (Ctrl+Shift+R or Cmd+Shift+R) and try accessing your site again.
  10. * If the site now loads (even without intended redirects), then the .htaccess file is definitely the cause.
  11. * If the site still shows a 500 error or doesn't load, the issue might be elsewhere (e.g., PHP error, server misconfiguration), but for this guide, we assume the .htaccess is the culprit.
  12. Once confirmed, proceed to analyze the .htaccess contents. You can rename it back: mv .htaccessbak .htaccess before proceeding to the next step, or work on .htaccessbak directly and then rename it.

4. Analyze and Correct .htaccess Rules

This is the most critical step. You'll need to carefully review your .htaccess file for common misconfigurations that lead to redirect loops.

[!IMPORTANT] Always back up your .htaccess file before making any changes. A simple cp .htaccess .htaccessbackup$(date +%Y%m%d%H%M%S) will suffice.

Open your .htaccess file for editing: `bash nano .htaccess # Or your preferred editor `

Focus on RewriteEngine On, RewriteCond, and RewriteRule directives.

Common Pitfalls and Solutions:

a. HTTP to HTTPS Redirect Loop (Especially with Load Balancers/Proxies)

This is a very common loop, often occurring when Apache is behind a proxy that handles SSL termination. Apache then sees requests as HTTP, and the .htaccess repeatedly tries to redirect to HTTPS.

Incorrect (Common Error): `apacheconf # This can loop if Apache sees all requests as HTTP due to a proxy RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTPHOST}%{REQUESTURI} [L,R=301] `

Corrected using X-Forwarded-Proto (for proxy setups): If your proxy sets X-Forwarded-Proto (e.g., https), use this header to detect the original protocol. `apacheconf RewriteEngine On RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC] RewriteRule ^ https://%{HTTPHOST}%{REQUESTURI} [L,R=301] ` If not behind a proxy and direct SSL: `apacheconf RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTPHOST}%{REQUESTURI} [L,R=301] `

b. WWW to Non-WWW (or vice versa) Redirect Loop

Ensure your www/non-www rules are correctly ordered, especially when combined with HTTPS redirects.

Incorrect (Potential Loop/Conflict): `apacheconf # This rule might redirect to HTTP www, then HTTPS rule kicks in, then back to HTTP www… RewriteEngine On RewriteCond %{HTTP_HOST} ^www.(.*)$ [NC] RewriteRule ^(.*)$ http://example.com/$1 [L,R=301] `

Corrected (Non-WWW with HTTPS priority): It's generally best to redirect to HTTPS first, then handle www/non-www.

1. Redirect HTTP to HTTPS RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTPHOST}%{REQUESTURI} [L,R=301]

2. Redirect WWW to Non-WWW (only if the host starts with www.) RewriteCond %{HTTP_HOST} ^www.(.*)$ [NC] RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301] ` In this example: * The first rule ensures all traffic is HTTPS. The second rule assumes* the traffic is already HTTPS (or will be immediately redirected by the first rule) and then handles the www part. https://%1%{REQUEST_URI} ensures it stays on HTTPS while removing www..

c. Missing [L] (Last) Flag

Always ensure redirect rules that should terminate processing have the [L] flag. Without it, subsequent rules might apply to the already rewritten URI, leading to unintended behavior or loops.

Example: `apacheconf # Original rule potentially causing a loop if another rule re-processes the URI RewriteRule ^old-page.html$ /new-page.html [R=301]

Corrected with [L] flag RewriteRule ^old-page.html$ /new-page.html [L,R=301] `

d. Incorrect RewriteBase

If your .htaccess file is in a subdirectory (e.g., /var/www/html/blog/.htaccess), ensure RewriteBase is set correctly.

Example: For /var/www/html/blog/.htaccess: `apacheconf RewriteEngine On RewriteBase /blog/ # Important for correct path calculation RewriteRule ^index.php$ – [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /blog/index.php [L] ` If your .htaccess is in the document root (e.g., /var/www/html/.htaccess), RewriteBase / is usually appropriate, or it can often be omitted if rules are relative to the root.

e. Systematically Test Rules

If you have many rules, comment them out one by one (or in small groups) and test after each change to isolate the problematic rule(s). `apacheconf # RewriteEngine On # RewriteCond %{HTTPS} off # RewriteRule ^ https://%{HTTPHOST}%{REQUESTURI} [L,R=301]

This rule is currently active and being tested RewriteEngine On RewriteCond %{HTTP_HOST} ^www.(.*)$ [NC] RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301] ` After testing, uncomment other rules gradually.

5. Debug mod_rewrite with LogLevel (Advanced)

For deep debugging, you can temporarily increase Apache's LogLevel for mod_rewrite. This will produce extremely verbose output in your error log, showing how each rule is processed.

  1. Open your main Apache configuration file (/etc/apache2/apache2.conf) or your virtual host file (/etc/apache2/sites-available/your-domain.conf).
  2. Locate the LogLevel directive (usually LogLevel warn) and add or modify it to include rewrite:traceN, where N is a number from 1 to 6 (6 being the most verbose). For Apache 2.4, trace1 through trace8 are available. trace5 or trace6 is usually sufficient for detailed rewrite debugging.
    LogLevel warn rewrite:trace5

[!WARNING] > Enabling rewrite:trace generates an enormous amount of log data very quickly and can severely impact server performance and disk space. Do not use this on a production server for extended periods. Revert the LogLevel immediately after debugging.

  1. Restart Apache:
  2. `bash
  3. sudo systemctl restart apache2
  4. `
  5. Access the problematic URL.
  6. Monitor the error log (sudo tail -f /var/log/apache2/error.log). You will see detailed information about how mod_rewrite processes each condition and rule. Look for patterns where a URI is repeatedly matched and rewritten by the same or a cyclical set of rules.

Example log snippet you might see during a loop: ` [rewrite:trace2] [client 127.0.0.1:40830] rewrite 'index.php' -> 'index.php' [rewrite:trace2] [client 127.0.0.1:40830] add path info and hook 'index.php' to URI [rewrite:trace2] [client 127.0.0.1:40830] strip per-dir prefix: /var/www/html/index.php -> index.php [rewrite:trace2] [client 127.0.0.1:40830] applying pattern '^$' to uri 'index.php' [rewrite:trace2] [client 127.0.0.1:40830] rewrite 'index.php' -> 'index.php' [rewrite:trace2] [client 127.0.0.1:40830] add path info and hook 'index.php' to URI … repeated entries indicating a loop … `

  1. Once debugging is complete, revert the LogLevel to its original value (e.g., LogLevel warn) and restart Apache.

6. Restore Configuration and Test

After implementing your corrected .htaccess rules:

  1. Ensure LogLevel is reset in apache2.conf or your virtual host file.
  2. Rename your .htaccess_bak (if you used it for editing) back to .htaccess:
  3. `bash
  4. mv .htaccess_bak .htaccess
  5. `
  6. Restart Apache:
  7. `bash
  8. sudo systemctl restart apache2
  9. `
  10. Clear your browser cache and test your website thoroughly, including different URLs and sections.

By meticulously following these steps, you should be able to pinpoint and resolve the Apache .htaccess redirect loop causing your 500 Internal Server Error on Ubuntu 20.04 LTS.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *