Error fix · Server errors

Apache mod_rewrite Not Working: Rules Ignored or 404? Fix It

When RewriteRule seems to do nothing in Apache, check that mod_rewrite is enabled, AllowOverride permits .htaccess, and the rule matches. Includes debug logging.

Error messagemod_rewrite not working .htaccess RewriteRule ignored

By SiteDownCheck Editorial · Updated October 21, 2026 · 4 min read

Your .htaccess has RewriteEngine On and a few rules, yet pretty URLs return 404, redirects never fire, or the file seems to be ignored entirely. Apache will not tell you which of several different problems you have, so work through them in order. Most cases are solved in the first three steps.

If instead the whole site returns 500 after adding rules, go to Apache .htaccess 500 error.

Step 1: is mod_rewrite loaded?

apachectl -M | grep rewrite

You want rewrite_module (shared). If it is missing, on Debian and Ubuntu run sudo a2enmod rewrite and restart Apache. On RHEL-family systems check for a LoadModule rewrite_module modules/mod_rewrite.so line in /etc/httpd/conf.modules.d/. If the module is absent, you normally get a 500 with "Invalid command 'RewriteEngine'", see Invalid command in .htaccess. A silent no-op usually means the module is loaded and something else is wrong, or the rules sit inside an <IfModule mod_rewrite.c> block that never matched.

Step 2: is .htaccess being read at all?

Apache only honors .htaccess where AllowOverride permits it. On Ubuntu the default for /var/www/ is AllowOverride None, which makes every .htaccess file invisible.

<Directory /var/www/html>
    AllowOverride All
</Directory>

Put that in the virtual host (or a conf file), run apachectl configtest, and reload. To prove whether .htaccess is read, add a deliberate nonsense line such as ThisShouldBreak. If you still get 200, the file is ignored: wrong directory, wrong filename (it must be exactly .htaccess, with a leading dot and no .txt), AllowOverride None, or the request is served by a different vhost or by another server such as nginx in front. Remove the test line afterward.

Step 3: is the request even reaching this server?

Check the response headers with the HTTP Header Checker. A Server: nginx header, a CDN cache hit, or a cached 301 can mean Apache never sees your new rule. Browsers cache 301 redirects hard; test with curl -I or a private window.

If the log shows Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden, add Options +FollowSymLinks to the .htaccess (and make sure AllowOverride includes Options).

Step 5: understand how the pattern matches

This is where most "not working" reports end up.

  • In .htaccess, the pattern does not start with a slash. The per-directory path has the directory prefix stripped, so use ^about$, not ^/about$. In a virtual host context the path does start with /.
  • Query strings are not part of the pattern. To match them, use RewriteCond %{QUERY_STRING} ....
  • Conditions apply only to the next rule. A RewriteCond followed by two RewriteRule lines protects only the first.
  • Rule order matters. [L] stops processing in the current pass, but in .htaccess the engine restarts with the rewritten URL, so rules can run again. Add a guard condition to prevent loops.
  • Regex mistakes: unescaped dots, missing $ anchors, or a greedy .* capturing too much. Test patterns in the Regex Tester, keeping in mind Apache uses PCRE syntax.

A classic front-controller rule, which sends non-file requests to index.php, looks like this:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]

If this fails with 404, the usual cause is a wrong RewriteBase or the application living in a subdirectory. Add RewriteBase /subdir/ to match.

Step 6: turn on rewrite logging

Apache 2.4 replaced the old RewriteLog directive with a log level. Add this to the server or vhost config (it is not allowed in .htaccess):

LogLevel alert rewrite:trace3

Reload, request the URL, and watch the error log:

sudo tail -f /var/log/apache2/error.log | grep rewrite

Each line shows the pattern tested and whether it matched. Use trace6 for more detail. Remove or lower it afterward, because it is very verbose.

Step 7: check redirect behavior from outside

For redirect rules, confirm the final result with the Redirect Checker and the Redirect Debugger. They show each hop's status code and Location header, which tells you whether a rule fired and whether it used 301, 302 or something else (the R flag defaults to 302). For redirect loops, see ERR_TOO_MANY_REDIRECTS.

Next steps

FAQ

Why do my rules work locally but not on the host?

The host may have AllowOverride None, a different module set, or nginx in front that ignores .htaccess. Compare apachectl -M and the vhost config on both machines.

Do I need to restart Apache after editing .htaccess?

No. Apache re-reads .htaccess on every request. You only restart for changes to the main config, such as AllowOverride.

Why does my redirect keep returning the old destination?

Browsers cache 301 responses. Test with curl or a private window, and use a temporary 302 while you experiment.

Is the RewriteLog directive still available?

No. It was removed in Apache 2.4. Use LogLevel with the rewrite:traceN module setting instead.

Get notified when this fix updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.