Web Server Intermediate

Fixing Apache htaccess Redirect Loop: 500 Internal Server Error on Alpine Linux

Troubleshoot and resolve Apache 500 Internal Server Errors caused by misconfigured .htaccess redirect loops on Alpine Linux with this expert guide.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Troubleshoot and resolve Apache 500 Internal Server Errors caused by misconfigured .htaccess redirect loops on Alpine Linux with this expert guide.

Introduction

Encountering a "500 Internal Server Error" is a frustrating experience for any website owner or administrator, especially when it stems from an Apache .htaccess redirect loop on a lean Alpine Linux environment. This particular issue typically arises when your web server is configured to continuously redirect requests, creating an infinite loop that Apache eventually terminates with a server error. This guide provides a highly technical, accurate, and step-by-step resolution specifically tailored for Apache 2.4.x running on Alpine Linux 3.x.

Symptom & Error Signature

When an .htaccess redirect loop occurs, your browser will typically display a generic "500 Internal Server Error" page, or sometimes a "Too many redirects" error, though the 500 is more common when the server itself gives up.

On the server-side, the most critical information resides in your Apache error logs. On Alpine Linux, these are usually found at /var/log/apache2/error.log. You will observe entries similar to these:

[Wed Oct 07 10:30:01.123456 2026] [core:error] [pid 12345:tid 1234567890] [client 192.168.1.100:54321] 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' for more information.
[Wed Oct 07 10:30:01.123457 2026] [core:error] [pid 12345:tid 1234567890] [client 192.168.1.100:54321] 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' for more information.

If mod_rewrite debugging is enabled (which we'll cover later), you might see more verbose output indicating the specific rewrite rules being processed in a loop:

[Wed Oct 07 10:30:01.123458 2026] [rewrite:trace1] [pid 12345:tid 1234567890] [client 192.168.1.100:54321] Initial URI: /some-page
[Wed Oct 07 10:30:01.123459 2026] [rewrite:trace2] [pid 12345:tid 1234567890] [client 192.168.1.100:54321] RewriteCond: input '/some-page' pattern '^(.*)$' => matched
[Wed Oct 07 10:30:01.123460 2026] [rewrite:trace2] [pid 12345:tid 1234567890] [client 192.168.1.100:54321] RewriteRule: pattern '^(.*)$' => 'https://www.example.com/$1' [R=301,L]
[Wed Oct 07 10:30:01.123461 2026] [rewrite:trace1] [pid 12345:tid 1234567890] [client 192.168.1.100:54321] Initial URI: /some-page
... (repeatedly)

Root Cause Analysis

The 500 Internal Server Error in this context is a consequence of Apache hitting its LimitInternalRecursion directive, which defaults to 10 redirects. When mod_rewrite rules in an .htaccess file (or main server configuration) are improperly configured, they can cause a request to be rewritten repeatedly to a URI that still matches the same or another rewrite rule, leading to an infinite loop.

Common underlying reasons include:

  1. Missing RewriteCond: A RewriteRule is applied unconditionally, even to the rewritten URL itself, leading to infinite self-rewriting. For instance, redirecting HTTP to HTTPS without checking if the request is already HTTPS.
  2. Incorrect RewriteRule Flags: Misuse of flags like [R] (redirect), [L] (last), [QSA] (query string append), or missing flags can lead to unintended behavior.
  3. Conflicting Rules: Multiple .htaccess files in subdirectories, or rules in the main Apache configuration (httpd.conf or vhost files) conflicting with .htaccess rules.
  4. mod_rewrite Not Enabled or AllowOverride Not Permitted: While not directly a redirect loop cause, these can prevent .htaccess rules from being processed correctly, leading to unexpected behavior that might appear as a loop if other rules are present. On Alpine, mod_rewrite needs to be explicitly loaded, and AllowOverride All set for the directory containing the .htaccess file.
  5. Environment Variables Issues: Rules relying on server variables (e.g., %{HTTPS}, %{HTTP_HOST}) might behave unexpectedly if the server environment isn't correctly detected (less common but possible).
  6. Character Encoding or Syntax Errors: While often resulting in a direct 500 without a loop, subtle syntax errors can lead to unexpected rule matching.

Step-by-Step Resolution

Follow these steps to diagnose and resolve the Apache .htaccess redirect loop on your Alpine Linux server.

1. Backup and Disable .htaccess

The first step is to confirm that the .htaccess file is indeed the source of the problem.

  1. Access your server: Use SSH to connect to your Alpine Linux instance.

    ssh user@your_server_ip
    
  2. Navigate to your web root:

    cd /var/www/localhost/htdocs/your_website_root # Adjust path as needed
    
  3. Rename (effectively disable) the .htaccess file:

    mv .htaccess .htaccess_backup
    

    Renaming the .htaccess file will temporarily disable all its rules, which might affect your website's functionality (e.g., permalinks, security rules). This is a diagnostic step.

  4. Test your website: Try to access your website in a browser. If the 500 error disappears and your site loads (even if some functionality is broken), then the .htaccess file is definitely the culprit. If the 500 persists, the issue might be elsewhere (e.g., main Apache configuration, PHP error if using mod_php, or file permissions).

2. Verify Apache Configuration (Alpine Linux Specifics)

Ensure that Apache is configured to allow .htaccess files and that mod_rewrite is enabled.

  1. Check mod_rewrite module: On Alpine, Apache modules are usually enabled by symlinking them from mods-available to mods-enabled.

    ls -l /etc/apache2/mods-enabled/rewrite.load
    

    If rewrite.load is not present or not symlinked, you need to enable it. Edit /etc/apache2/httpd.conf or a configuration file in conf.d/ (e.g., 00_mod_rewrite.conf) and ensure the following line is uncommented or added:

    LoadModule rewrite_module modules/mod_rewrite.so
    

    If mod_rewrite.so is not found, you may need to install the Apache modules package.

    sudo apk add apache2-mod_rewrite
    

    And then ensure the LoadModule line is present and Apache restarted.

  2. Verify AllowOverride All: This is crucial. Your Apache configuration (usually /etc/apache2/httpd.conf or a virtual host file in /etc/apache2/conf.d/) must permit .htaccess overrides for your web directory. Open the main Apache configuration file:

    sudo vim /etc/apache2/httpd.conf
    

    Search for <Directory "/var/www/localhost/htdocs"> or your specific website root directory. Within this block, ensure AllowOverride All is set.

    <Directory "/var/www/localhost/htdocs">
        Options Indexes FollowSymLinks
        AllowOverride All  # <--- Ensure this is All, not None
        Require all granted
    </Directory>
    

    Setting AllowOverride All globally is generally discouraged for security and performance reasons on shared hosting. For dedicated servers, it's common. For specific virtual hosts or directories, limit AllowOverride to what's necessary (e.g., AllowOverride FileInfo AuthConfig).

  3. Restart Apache: After any changes to Apache's main configuration, you must restart the service.

    sudo rc-service apache2 restart
    # Or, if `service` is configured on your Alpine system:
    # sudo service apache2 restart
    

3. Review and Debug .htaccess Rules

Now that you've confirmed .htaccess is the source and Apache is ready for it, it's time to fix the rules.

  1. Restore .htaccess:

    mv .htaccess_backup .htaccess
    
  2. Enable mod_rewrite Debugging (Optional but Recommended): For detailed insight into how mod_rewrite processes requests, temporarily increase the LogLevel for mod_rewrite. Add or modify this line in your httpd.conf or a conf.d file:

    # In /etc/apache2/httpd.conf or a .conf file in /etc/apache2/conf.d/
    LogLevel alert rewrite:trace8
    

    trace8 is the highest level of debugging. This will produce a lot of output in /var/log/apache2/error.log. Remember to revert this after troubleshooting.

    Restart Apache after changing LogLevel: sudo rc-service apache2 restart

  3. Isolate Problematic Rules: Open your .htaccess file:

    vim .htaccess
    

    Comment out all RewriteRule and RewriteCond directives by prepending them with #.

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

    Save the file, test your site. If it loads, uncomment rules one by one, starting from the top, testing the site after each uncommented rule until the 500 error reappears. This helps pinpoint the problematic rule.

  4. Common Redirect Loop Fixes:

    • HTTP to HTTPS Redirect Loop: This is a very common cause. The rule redirects to HTTPS, but doesn't check if the request is already HTTPS. Incorrect (causes loop if applied to already HTTPS requests):

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

      Correct (checks if not HTTPS first):

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

      If you're behind a proxy/load balancer (e.g., Cloudflare, Nginx proxy), Apache might not see %{HTTPS} as 'on'. In such cases, the proxy might send a custom header (e.g., X-Forwarded-Proto). Correct for Proxied HTTPS:

      RewriteEngine On
      RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
      RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
      
    • WWW to Non-WWW / Non-WWW to WWW Loop: Similar to HTTPS, ensure you're checking the host name before rewriting. WWW to Non-WWW (Correct):

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

      Non-WWW to WWW (Correct):

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

      For production, combine HTTP to HTTPS with WWW/non-WWW rules, ensuring the HTTPS rule is applied last or carefully structured. Example:

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

      This example redirects both HTTP and WWW to HTTPS non-WWW in one go.

    • Trailing Slash Loop: Adding or removing trailing slashes can also cause loops if not handled carefully. Add Trailing Slash (Correct – excludes files and existing directories):

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

      Remove Trailing Slash (Correct – only for directories, not base URL):

      RewriteEngine On
      RewriteRule ^(.*)/$ /$1 [L,R=301]
      RewriteCond %{REQUEST_URI} !^/$
      

      The second example is risky and can break directory browsing. Usually, adding a trailing slash is preferred for canonical URLs.

  5. Review LimitInternalRecursion (Advanced): If your application genuinely requires more than 10 internal redirects (e.g., complex front controllers), you can increase this limit in httpd.conf or a virtual host configuration.

    # In /etc/apache2/httpd.conf or a .conf file
    LimitInternalRecursion 20
    

    Increasing LimitInternalRecursion should be a last resort after thoroughly debugging your rewrite rules. A high number of internal redirects usually indicates a design flaw in your rewrite logic or application.

4. Check File Permissions

Incorrect file permissions on .htaccess or the parent directory can sometimes cause Apache to fail to read the file, potentially leading to 500 errors or unexpected behavior.

  1. Verify permissions:
    ls -l .htaccess
    ls -ld /var/www/localhost/htdocs/your_website_root # Check directory permissions
    
    Typical safe permissions for .htaccess are 644 (read/write for owner, read-only for group/others). The directory should be 755.
    sudo chmod 644 .htaccess
    sudo chmod 755 /var/www/localhost/htdocs/your_website_root
    
    Ensure the apache user (or www-data on some systems, check your Apache configuration for User and Group directives) has read access to the .htaccess file and execute access to all parent directories.

5. Clean Browser Cache

After making changes to .htaccess and restarting Apache, clear your browser's cache and cookies for the affected domain. Browsers aggressively cache redirects (especially 301 Permanent Redirects), and an old cached redirect can make it seem like the loop persists even after the server-side fix.

  • Google Chrome: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (macOS) for hard refresh, or clear from Developer Tools (F12).
  • Mozilla Firefox: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (macOS) for hard refresh, or clear from Web Developer Tools (F12).

By following these detailed steps, you should be able to identify, correct, and resolve the Apache .htaccess redirect loop leading to a 500 Internal Server Error on your Alpine Linux server. Remember to revert LogLevel changes once troubleshooting is complete to avoid excessive log file growth.

👨‍💻

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.