.htaccess Syntax Checker
Paste the contents of an .htaccess file to instantly catch common mistakes: unclosed block tags, misspelled directive names, RewriteRule with too few arguments, and dangling RewriteCond lines.
Finding mistakes in a .htaccess file
A `.htaccess` is a file in which a single wrong character can bring down a whole site with a 500 error. Paste its contents in and this tool detects on the spot the typical mistakes: an unclosed block tag, a misspelt directive name, a `RewriteRule` short of arguments, a `RewriteCond` left stranded.
**What is checked here is the syntax, not whether the file does what you meant.** A rewrite rule may be perfectly well formed and still fail to send anyone to the URL you had in mind if the conditions come in the wrong order. Two details of the specification are worth knowing besides. The first is that **a `RewriteCond` applies only to the single `RewriteRule` that immediately follows it**, so listing several conditions and putting one rule at the end simply does not work. The second is that **if `AllowOverride` is disabled in the server configuration, the `.htaccess` is never read at all.** When nothing happens despite what you wrote, suspect the server configuration rather than the file.
How to use it
- Paste in the contents of your .htaccess Put in the whole file exactly as it stands.
- Try the samples first A valid example and one containing errors are both provided.
- Read the lines called out **Unclosed tags and missing arguments are reported with their line numbers.**
- Check the server configuration when nothing works **If `AllowOverride` is disabled, the file is never read.**
Tips for getting more out of it
- This checker is a heuristic, line-based static analysis — it is not a real Apache parser. Always test on a real server or staging environment before deploying.
- If you have shell access to the Apache server,
apachectl configtestis the most authoritative syntax check available. This tool is meant for quick pre-checks when that command is not accessible, such as on shared hosting. - The unrecognized-directive warning is a low-confidence guess based on a fixed allowlist. If you use a directive from a less common module, seeing this warning does not necessarily mean it is wrong.
- Stacking several RewriteCond lines in a row is normal usage (they act like AND conditions). This tool only warns when the very last RewriteCond in a chain is not followed by a RewriteRule.
- Before uploading to production, apply changes incrementally and verify each step, rather than pushing a large rewritten file all at once.
Where it comes in useful
Checking before it goes live
**A mistake in `.htaccess` takes the whole site down, which makes checking beforehand well worth the trouble.**
Adding to a set of rewrite rules
After adding a condition to existing rules, you can see whether the form has held together.
Making sense of an inherited configuration
In a file long added to, you can establish whether any of it has ceased to take effect.
Narrowing down a 500 error
**You can first establish whether the syntax is what stops the server starting.**
.htaccess terms
- RewriteEngine
- The directive enabling rewriting. **Unless it is set to `On`, none of the rules that follow has any effect.**
- RewriteCond
- A condition on a rewrite. **It applies only to the single `RewriteRule` that immediately follows**, which is worth keeping in mind.
- RewriteRule
- The rewriting rule itself, taking a pattern, a replacement and flags such as `[L,QSA]`.
- Flags
- The settings in square brackets after a rule. `L` stops processing here and `QSA` carries the query string over.
- Block tag
- An enclosure such as `
` or ` `. **Leaving one unclosed produces a 500 error.** - AllowOverride
- The server-side setting deciding which directives a `.htaccess` may use. **Where it is disabled, the file is never read.**
Frequently Asked Questions
AllowOverride None set for that directory, meaning .htaccess is ignored entirely. Ask your server administrator to confirm AllowOverride All (or at least the specific override categories you need, such as AuthConfig or FileInfo) is enabled. It is also worth checking whether a browser or CDN cache is serving a stale response.RewriteRule pattern substitution [flags]. The pattern is a regular expression matched against the requested URL path (without the leading slash), and the substitution can reference capture groups from the pattern using $1, $2, and so on. Flags go in square brackets, comma-separated, such as [L] (stop processing further rules) or [R=301] (permanent redirect).%{REQUEST_FILENAME} !-f (only apply the rule if the path is not already an existing file) so the rule stops once the target actually exists.
Side Note — Why is it called ".htaccess"?
The name ".htaccess" is short for "hypertext access", and its history traces back to the early versions of NCSA httpd and Apache around 1995. It was originally introduced to let directory owners configure password protection (Basic authentication) for their own space without needing to touch the server-wide configuration file (httpd.conf), which only the server administrator could edit.
What makes .htaccess powerful is that, as long as the Apache administrator has permitted it via the AllowOverride directive, changes take effect the moment the file is uploaded via FTP or a file manager — no server restart required. This lets users on shared hosting, who typically have no access to the main server configuration, control redirects, caching, and access restrictions on a per-directory basis.
That convenience comes at a cost, though. Apache's own documentation explicitly recommends putting directives in the main server configuration instead of .htaccess whenever you have access to do so. The reason is simple: Apache has to search for and re-read .htaccess files in every parent directory on every single request, which introduces a non-trivial performance overhead compared to configuration baked into the main config file.
A stray syntax error can also be costly: on many shared hosting setups, an invalid .htaccess turns every page under that directory into a blank "500 Internal Server Error", and tracking down the exact cause can eat up a surprising amount of time. Running a quick static check like this one, in addition to a careful read-through, helps catch careless mistakes before they cause an outage after deployment.