Web Server Advanced

Apache .htaccess Redirect Loop 500 Internal Server Error on Ubuntu 22.04 LTS

Fix Apache .htaccess redirect loop causing a 500 Internal Server Error on Ubuntu 22.04 LTS. Diagnose misconfigurations, mod_rewrite issues, and permissions for stable web hosting.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Fix Apache .htaccess redirect loop causing a 500 Internal Server Error on Ubuntu 22.04 LTS. Diagnose misconfigurations, mod_rewrite issues, and permissions for stable web hosting.

When your Apache web server throws a 500 Internal Server Error due to an .htaccess redirect loop on Ubuntu 22.04 LTS, it indicates a critical misconfiguration preventing your website from serving content. This guide provides a highly technical, step-by-step approach to diagnose and resolve such issues, ensuring your web applications remain accessible and performant. As experienced SysAdmins, we know these issues often stem from subtle errors in mod_rewrite rules or improper server configurations.

Symptom & Error Signature

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

  • A blank page with the text "500 Internal Server Error".
  • A browser error indicating "ERR_TOO_MANY_REDIRECTS" or similar, which eventually might lead to a 500 if the server exhausts resources or hits a recursion limit.

Crucially, the server's error logs will provide more specific details. You can usually find these logs at /var/log/apache2/error.log on Ubuntu systems.

Typical Apache error.log entries for this issue:

[Tue Nov 03 10:30:00.123456 2026] [core:alert] [pid 12345:tid 140000000000000] [client 192.168.1.100:54321] /var/www/html/.htaccess: RewriteRule: bad flag delimiters
[Tue Nov 03 10:30:01.654321 2026] [mod_rewrite:error] [pid 12346:tid 140000000000000] [client 192.168.1.101:54322] 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.
[Tue Nov 03 10:30:02.987654 2026] [mod_rewrite:error] [pid 12347:tid 140000000000000] [client 192.168.1.102:54323] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Last rule tried: # HTTP to HTTPS
[Tue Nov 03 10:30:03.111222 2026] [authz_core:error] [pid 12348:tid 140000000000000] [client 192.168.1.103:54324] AH01630: client denied by server configuration: /var/www/html/.htaccess

Root Cause Analysis

A 500 Internal Server Error triggered by an .htaccess redirect loop on Apache is almost always a direct consequence of mod_rewrite directives that are either syntactically incorrect, logically flawed, or encountering server-level permission/configuration restrictions. Common underlying causes include:

  1. Misconfigured RewriteRules: The most frequent culprit. Rules are defined in a way that causes an infinite redirection chain (e.g., redirecting http://example.com to https://example.com but applying the rule even when the request is already https, or www to non-www without proper conditions).
  2. Incorrect RewriteBase: If your application resides in a subdirectory, an improperly set or missing RewriteBase can lead to repeated path rewrites.
  3. Missing or Incorrect RewriteCond: RewriteCond directives are crucial for defining the conditions under which a RewriteRule should apply. Without them, a rule might repeatedly apply to its own rewritten output.
  4. AllowOverride None in Apache Configuration: If the main Apache configuration (e.g., apache2.conf or a VirtualHost file) has AllowOverride None for the directory containing the .htaccess file, Apache will completely ignore the .htaccess directives, which can lead to unexpected behavior or 500 errors if a required rewrite isn't happening.
  5. mod_rewrite Module Not Enabled: If the mod_rewrite module is not loaded and enabled in Apache, any RewriteRule or RewriteCond directives in .htaccess will result in a 500 Internal Server Error because Apache doesn't understand the syntax.
  6. Syntactic Errors in .htaccess: Even a simple typo, missing space, or incorrect flag delimiter ([R=301,L]) can cause a 500 error as Apache fails to parse the file.
  7. File Permissions or Ownership: Incorrect file permissions (e.g., not readable by the www-data user) or ownership for the .htaccess file can prevent Apache from processing it, leading to a 500 error.
  8. Server-Level vs. .htaccess Conflicts: Sometimes, a VirtualHost configuration might already handle redirects or URL rewriting, and conflicting rules in .htaccess can create a loop.

Step-by-Step Resolution

Follow these steps meticulously to diagnose and resolve your Apache .htaccess redirect loop and 500 Internal Server Error.

1. Temporarily Disable the .htaccess File

The quickest way to confirm if .htaccess is the source of the problem is to temporarily disable it.

cd /var/www/html/your_domain_root/ # Navigate to your web root
sudo mv .htaccess .htaccess.bak     # Rename the file

After renaming, try accessing your website. If the 500 Internal Server Error disappears (you might see a different error or the site loads partially), you've confirmed .htaccess is the culprit.

2. Check Apache Error Logs

Even after disabling, review the logs for any previous errors and to ensure Apache restarts cleanly.

sudo tail -f /var/log/apache2/error.log

Look for lines containing RewriteRule, AH00124, bad flag delimiters, or configuration error. This provides crucial clues.

3. Verify mod_rewrite Module Status

If mod_rewrite is not enabled, any RewriteRule will cause a 500 error.

sudo a2enmod rewrite               # Enable the rewrite module
sudo systemctl restart apache2     # Restart Apache to apply changes

Check the module status:

apache2ctl -M | grep rewrite

You should see rewrite_module (shared) in the output.

4. Examine Apache VirtualHost/Directory Configuration

Apache must be configured to allow .htaccess overrides. By default, AllowOverride None is often set for security.

  1. Locate your VirtualHost file: For most installations, this is in /etc/apache2/sites-available/your_domain.conf.

    sudo nano /etc/apache2/sites-available/your_domain.conf
    
  2. Ensure AllowOverride All: Inside the <VirtualHost> block, locate the <Directory> directive corresponding to your web root (/var/www/html/your_domain_root/ for example). Change AllowOverride None to AllowOverride All.

    <VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com
        DocumentRoot /var/www/html/your_domain_root
    
        ErrorLog ${APACHE_LOG_DIR}/your_domain_error.log
        CustomLog ${APACHE_LOG_DIR}/your_domain_access.log combined
    
        <Directory /var/www/html/your_domain_root>
            Options Indexes FollowSymLinks MultiViews
            AllowOverride All          # THIS MUST BE ALL FOR .htaccess to work
            Require all granted
        </Directory>
    </VirtualHost>
    
    # Repeat for HTTPS VirtualHost if applicable
    <VirtualHost *:443>
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com
        DocumentRoot /var/www/html/your_domain_root
    
        <Directory /var/www/html/your_domain_root>
            Options Indexes FollowSymLinks MultiViews
            AllowOverride All          # AND HERE!
            Require all granted
        </Directory>
        # ... SSL configuration ...
    </VirtualHost>
    

    Setting AllowOverride All allows .htaccess files to override almost all configuration directives. Use this judiciously; for production, consider more granular AllowOverride options if specific directives are not needed.

  3. Test and Restart Apache:

    sudo apache2ctl configtest         # Test configuration syntax
    sudo systemctl restart apache2     # Restart Apache
    

5. Debugging .htaccess RewriteRules

If the problem persists after verifying mod_rewrite and AllowOverride, the issue is almost certainly within the RewriteRules themselves. Re-enable your .htaccess (sudo mv .htaccess.bak .htaccess) and proceed.

  1. Isolate the Problematic Rule: Comment out (prefix with #) all RewriteRule and RewriteCond directives except RewriteEngine On. Then, uncomment them one by one, testing the site after each change, until the 500 error reappears. This helps pinpoint the exact rule causing the loop.

  2. Common Redirect Loop Scenarios and Fixes:

    • HTTP to HTTPS Redirect Loop: A common mistake is redirecting to HTTPS without checking if the connection is already HTTPS.

      Incorrect (causes loop):

      RewriteEngine On
      RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
      

      Correct:

      RewriteEngine On
      RewriteCond %{HTTPS} off
      RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
      

      The RewriteCond %{HTTPS} off ensures the rule only applies if the connection is not HTTPS.

    • WWW to Non-WWW (or vice-versa) Redirect Loop: Similar to HTTPS, failing to check the HTTP_HOST before redirecting can cause a loop.

      Incorrect (causes loop):

      RewriteEngine On
      # To non-WWW
      RewriteRule ^(.*)$ http://yourdomain.com/$1 [L,R=301]
      

      Correct (Non-WWW to WWW):

      RewriteEngine On
      RewriteCond %{HTTP_HOST} ^yourdomain.com [NC]
      RewriteRule ^(.*)$ http://www.yourdomain.com%{REQUEST_URI} [L,R=301]
      

      Correct (WWW to Non-WWW):

      RewriteEngine On
      RewriteCond %{HTTP_HOST} ^www.yourdomain.com [NC]
      RewriteRule ^(.*)$ http://yourdomain.com%{REQUEST_URI} [L,R=301]
      
    • Trailing Slash Issues: Redirecting to add/remove a trailing slash without proper conditions.

      Example (Add trailing slash):

      RewriteEngine On
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_URI} !(.[a-zA-Z0-9]{1,5}|/)$
      RewriteRule ^(.*)$ /$1/ [R=301,L]
      

      Ensure your application doesn't internally rewrite paths to remove the trailing slash, causing a conflict.

  3. Increase RewriteLogLevel (Debugging mod_rewrite): For Apache 2.4+, you can increase RewriteLogLevel within your VirtualHost or main Apache configuration (NOT in .htaccess for security and performance reasons) to get extremely detailed debugging output in error.log.

    # In /etc/apache2/sites-available/your_domain.conf or apache2.conf
    <VirtualHost *:80>
        # ... other configurations ...
        RewriteEngine On
        RewriteOptions Inherit
        RewriteLogLevel 3 # Set to 3 for moderate detail, 9 for maximum detail (very verbose!)
        RewriteLog ${APACHE_LOG_DIR}/rewrite.log # Optional: dedicated log for rewrites
    </VirtualHost>
    

    Using RewriteLogLevel levels 3-9 generates a significant amount of log data and can severely impact server performance. Only enable this temporarily for debugging and set it back to 0 or comment it out once done. Be mindful of sensitive data possibly appearing in logs at higher levels.

    After setting RewriteLogLevel, restart Apache:

    sudo systemctl restart apache2
    

    Now, check /var/log/apache2/error.log (or rewrite.log if specified) and you'll see every step of the mod_rewrite process, helping you trace where the loop occurs.

6. Check File Permissions and Ownership

Incorrect permissions can prevent Apache from even reading the .htaccess file, leading to a 500 error.

  1. Check current permissions:

    ls -la /var/www/html/your_domain_root/.htaccess
    

    Output example: -rw-r--r-- 1 root root 243 Nov 3 10:00 .htaccess

  2. Set correct permissions and ownership: The .htaccess file should typically be owned by the web server user (e.g., www-data on Ubuntu) or at least be readable by it. Permissions usually 644 or 640 are safe.

    sudo chown www-data:www-data /var/www/html/your_domain_root/.htaccess
    sudo chmod 644 /var/www/html/your_domain_root/.htaccess
    

    Never set .htaccess file permissions to 777. This is a significant security risk and is completely unnecessary for Apache to read the file. 644 (readable by owner, group, and others) or 640 (readable by owner and group) is standard and secure.

7. Clear Browser Cache

After making any changes, always clear your browser's cache or use an incognito/private browsing window to ensure you're not seeing a cached redirect.

Browsers aggressively cache 301 (Permanent) redirects. If you tested a faulty rule and it was cached, even fixing the server won't show immediate results without clearing the cache.

By systematically following these steps, you should be able to pinpoint and rectify the misconfiguration causing the Apache .htaccess redirect loop 500 Internal Server Error on your Ubuntu 22.04 LTS server. Remember to always test changes in a staging environment first if possible, and to back up configuration files before modification.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.