About .htaccess analysis
What is a .htaccess file?
A .htaccess file is a per-directory configuration file for the Apache HTTP Server. Placed in a website's folder, it changes how Apache behaves for that folder and everything beneath it, without touching the main server configuration - which is why it is so common on shared hosting and in CMS installs.
It is typically used for URL rewriting and redirects, access control and password protection, custom HTTP headers, browser caching, compression, custom error pages, MIME types and PHP settings.
Two properties explain most .htaccess surprises. Apache reads the file on every request, so a mistake takes effect immediately and a syntax error usually produces a 500 error. And the file only works when the server's AllowOverride setting permits the directives you use and the required modules (mod_rewrite, mod_headers, mod_expires...) are loaded.
What does a .htaccess analyzer check?
This tool is a static analysis workspace: it parses your configuration into directives, sections, rules and conditions and reasons about them without running Apache. It looks at:
- Syntax: unbalanced sections, bad argument counts, malformed flags, unterminated quotes, inline comments
- RewriteRule and RewriteCond logic, flags, regular expressions and backreferences
- Redirect status codes, chains and loops, and HTTP to HTTPS handling
- www and non-www canonicalization, trailing slashes and extension removal
- Rule order: unreachable, duplicate and conflicting rules
- Front controllers and WordPress, Laravel, Symfony, CodeIgniter and Drupal patterns
- Directory listing, Options, MultiViews and FollowSymLinks
- Sensitive-file protection for .env, .git, backups, dumps, logs and keys
- Access control (Require and legacy Order/Allow/Deny), IP ranges and Basic authentication
- Security headers, CORS and Cache-Control
- Caching with mod_expires, ETags, compression with mod_deflate and Brotli
- MIME types, handlers, ErrorDocument and hotlink or user-agent rules
- Apache 2.2 and 2.4 compatibility, required modules, allowed contexts and AllowOverride classes
It reports what static analysis can establish and says so when something depends on your server. It does not execute the file, connect to your server, or fetch URLs, so it cannot confirm that a module is installed or that a redirect returns a particular status at runtime. Results also come with an optional JSON export that you can pretty-print with the JSON Formatter.
Common .htaccess problems
- Redirect loops. Opposing rules (www versus non-www, adding versus removing a slash), unconditional catch-all redirects, or an HTTPS redirect that cannot see the original protocol behind a proxy.
- Incorrect RewriteRule patterns. In .htaccess the pattern is matched against the path without a leading slash, so
^/blognever matches, and the pattern never sees the query string. - Missing RewriteEngine On. Without it, mod_rewrite rules are ignored unless a parent configuration enabled it.
- Conflicting or unreachable rules. An earlier rule with [L] or a catch-all pattern ends processing before later rules run; rules placed after a CMS front controller are skipped for non-file URLs.
- Directory listing.
Options Indexesexposes the file list of directories without an index file. - WordPress rewrite issues. Edits inside the generated block get overwritten, a missing
/index.phpfallback breaks permalinks, and duplicated blocks pile up. - Apache version compatibility. Apache 2.4 uses
Require; Order/Allow/Deny only works through mod_access_compat. Flags such as [END] need 2.4. - Missing modules. Header needs mod_headers, ExpiresActive needs mod_expires, RewriteRule needs mod_rewrite. Without an
<IfModule>guard a missing module produces a 500 error; with one the rules are silently skipped.
.htaccess security best practices
- Disable directory listings with
Options -Indexesunless you intentionally publish a file index. - Deny web access to sensitive files:
.env, version-control folders, backups (.bak .old .orig), database dumps, logs and private keys. - Serve the site over HTTPS and redirect plain HTTP with a permanent redirect; confirm the redirect works behind any proxy.
- Add response headers such as X-Content-Type-Options, Referrer-Policy and a tailored Content-Security-Policy. The HTTP Security Headers Analyzer checks real responses in more depth, and the security headers guide explains each header.
- Use
Requirefor access control and restrict by IP carefully - the CIDR Calculator helps with ranges such as192.168.1.0/24. - Use Basic authentication only over HTTPS, keep the password file outside the web root, and make sure a Require line actually enforces the login.
- Avoid blanket CORS wildcards on private responses and never combine a wildcard or reflected origin with credentials.
- Keep PHP execution out of upload directories and review any
auto_prepend_fileor unusual AddHandler lines you did not add yourself.
When you share error-log excerpts or access logs while debugging, remove IP addresses, tokens and personal data first - the Log Sanitizer does that locally in your browser.
.htaccess RewriteRule examples
Permanent redirect of one URL
RewriteEngine On RewriteRule ^old-page$ /new-page [R=301,L]
Redirect a section and keep the rest of the path
RewriteRule ^blog-old/(.*)$ /blog/$1 [R=301,L]
Front controller: send non-file URLs to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]!-f and !-d mean "not an existing file" and "not an existing directory", so CSS, JavaScript, images and uploads are served directly.
Redirect based on the query string
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^product\.php$ /product/%1? [R=301,L]The trailing ? drops the old query string; use [QSA] to keep it.
Block hotlinking of images
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteRule \.(jpe?g|png|gif|webp)$ - [NC,F,L]How to troubleshoot .htaccess
- Back up the current file, then paste it into the analyzer and fix syntax errors first - they cause 500 responses for the whole directory.
- Read the Apache error log (often
error.log) for the exact directive and line Apache rejected; look for "Invalid command" (missing module or wrong context) and "not allowed here" (AllowOverride). - Confirm the server uses .htaccess at all: AllowOverride must permit the directive classes, and nginx servers ignore the file.
- Check that the required modules are enabled (for example
apachectl -Mor the hosting panel) and that rewrites haveRewriteEngine Onand FollowSymLinks. - Bisect: comment out blocks until the problem disappears, then re-enable them one at a time. Use a 302 instead of 301 while testing so browsers do not cache the result.
- Review rule order - redirects, HTTPS and canonical-host rules go before front-controller rules - and look at the analyzer's loop, chain and unreachable-rule findings.
- Inspect the real response with your browser's network tab or
curl -I, test in a private window, and then test on a staging copy before deploying.