In Apache httpd, what work does the server do on every single request when .htaccess files are enabled, and how does the AllowOverride directive change it?
answer
- config that must be read at request time
- checked in every parent directory
- no cache, re-parsed each hit
- AllowOverride gates the lookup and the directive set
- default flipped to None in 2.4
basics
~20 sApache httpd looks for an .htaccess file in every directory along the path to the requested file, on every request, and re-parses each one it finds. AllowOverride None removes that lookup entirely; any other value enables it.
solid answer
~40 sWhen AllowOverride is set to anything other than `None` for a directory tree, httpd performs a per-request directory walk: for a request mapped to `/var/www/html/a/b/page.html` it checks for `.htaccess` in `/`, `/var`, `/var/www`, `/var/www/html`, `/var/www/html/a` and `/var/www/html/a/b`. Every file it finds is read and parsed again on that request — there is no cache — and the directives are merged from the top down, so a deeper file overrides a shallower one. `AllowOverride` also gates *which* directives an .htaccess may contain, by group: `FileInfo` covers mod_rewrite and Redirect, `AuthConfig` covers Require and friends, plus `Indexes`, `Limit` and `Options`. Setting `AllowOverride None` — the default since 2.4 — means httpd never even stats for the files, which is why the docs recommend it and hoisting the rules into the server configuration instead.
code
apache · 17 lines# Rules read once at startup; no per-request .htaccess lookup in this tree.
<Directory "/var/www/html">
AllowOverride None
Require all granted
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.php [L]
</Directory>
# Delegated tree: httpd walks for .htaccess on every request,
# and only FileInfo directives (rewrite, Redirect, Header) are permitted.
<Directory "/var/www/customers">
AllowOverride FileInfo
Require all granted
</Directory>go deeper
Know that .htaccess is per-directory Apache config that takes effect without restarting the server, and that AllowOverride in the server config decides whether it is read at all.
Be ready to describe the walk concretely — every ancestor directory checked and every file found re-parsed per request — and to name the override groups, with FileInfo as the one mod_rewrite needs.
Show you would measure before declaring it a bottleneck, and argue the operational cost too: rules invisible to config review, untested by configtest, and a typo that becomes a live 500 instead of a failed reload.
Own the fleet-wide policy: where delegation genuinely buys autonomy versus where AllowOverride None plus reviewed server config is the standard, and how you migrate existing trees without breaking tenants.
## What an .htaccess file is An `.htaccess` file is a fragment of Apache configuration that lives in a content directory rather than in the server's own config files. Its directives apply to that directory and everything below it. Its point is delegation: a user who can write into a document tree but has no permission to edit `httpd.conf` and no permission to reload the server can still change behaviour for their own subtree — the classic shared-hosting arrangement. That delegation is the whole benefit, and the mechanism that provides it is also the whole cost. ## The per-request directory walk Server configuration is read once, at startup or reload, and held in memory. `.htaccess` cannot work that way, because the point is that it takes effect the moment somebody saves it, with no reload. So httpd must look for it while handling the request. The lookup is not a single check on the file's own directory. httpd walks the whole filesystem path. For a document root of `/var/www/html` and a request for `/a/b/page.html`, it will look for: ``` /.htaccess /var/.htaccess /var/www/.htaccess /var/www/html/.htaccess /var/www/html/a/.htaccess /var/www/html/a/b/.htaccess ``` Six filesystem lookups, most of which normally miss. Every file that *is* found is opened, read and parsed on that request; httpd 2.4 keeps no parsed cache of them. A directive block that appears in the server config is parsed once for the lifetime of the process; the same block in `.htaccess` is parsed once per hit. Merging runs top down: the shallowest file applies first, and directives in deeper files override it. Note that this merge is *directive*-level, not file-level — but mod_rewrite is a special case worth knowing: per-directory rewrite rules are **not** inherited by a child `.htaccess` that has its own `RewriteEngine On`, unless you ask for it with `RewriteOptions Inherit`. ## What AllowOverride actually controls `AllowOverride` is valid only inside a `<Directory>` section (since 2.3.9 it is rejected anywhere else, including in `.htaccess` itself — otherwise a user could grant themselves more power). It does two jobs at once: 1. **Whether the walk happens at all.** `AllowOverride None` for a tree means httpd does not go looking for `.htaccess` in it. 2. **Which directives are permitted** when it does. The value is a set of groups: `AuthConfig`, `FileInfo`, `Indexes`, `Limit`, `Options[=...]`, or `All`. `FileInfo` is the one that matters for this topic — `RewriteRule`, `RewriteCond`, `RewriteBase`, `Redirect`, `ErrorDocument` and `Header` live there. A `.htaccess` containing a directive the current `AllowOverride` does not permit does not get quietly ignored: the request fails with 500 and the error log records the offending directive as "not allowed here". `AllowOverrideList` (2.3.11 and later) is the escape hatch for the case where you want to permit two named directives without opening a whole group. The default changed: httpd 2.2 shipped `AllowOverride All`, and 2.4 changed it to `None`. That single line is behind a large share of "my rewrite rules stopped working after the upgrade" reports — the file is still there and still correct; the server has simply stopped reading it. ## Framing the cost honestly It is easy to overstate this. The stat calls hit the operating system's directory-entry cache after the first request, so the cost is a handful of cheap syscalls per hit, not disk seeks. On a low-traffic site it is invisible. What makes it worth caring about at scale is that it is paid on *every* request including cheap static ones, it scales with path depth, and — for any `.htaccess` that actually exists — it includes re-parsing a config fragment and, for mod_rewrite, re-compiling its regular expressions. The second cost is operational rather than measurable: rules in `.htaccess` are invisible to anyone reading the server config, are not covered by `apachectl configtest`, and a typo becomes a live 500 on the next request rather than a failed reload you catch before it ships. ## The decision that follows If you control the server config and can reload it, hoist the rules into a `<Directory>` block and set `AllowOverride None`. The directives are identical apart from per-directory path handling, and they are then parsed once, reviewable, and syntax-checked before they go live. Keep `.htaccess` where the delegation is the point: shared hosting, or an application whose deploy artifact legitimately carries its own routing rules and whose team has no way to reload httpd.
- A team upgraded from httpd 2.2 to 2.4 and all of their .htaccess rules silently stopped applying. What is the first thing you check?`AllowOverride` for that tree. The 2.2 default was `All`; 2.4 defaults to `None`, so unless the vhost or a `<Directory>` block explicitly grants an override group, httpd never reads the files. Nothing appears in the error log because there is no error — the server simply is not looking. Adding `AllowOverride FileInfo` (or `All`) to the enclosing `<Directory>` restores the old behaviour.
- If AllowOverride permits FileInfo only, what happens when someone puts a Require directive into their .htaccess?The request fails with 500 Internal Server Error and the error log names the directive as not allowed there — `Require` belongs to the `AuthConfig` group. It is a hard failure, not a silent skip, which is deliberate: quietly ignoring an access-control directive would be a security trap. Either widen the group or use `AllowOverrideList` to permit that one directive.
- Does an .htaccess file in a parent directory still apply if the child directory has its own?Yes for directives generally — httpd merges the files it finds from shallowest to deepest, and the deeper one wins on conflicts. mod_rewrite is the exception worth remembering: per-directory rewrite rules from a parent are not inherited once the child turns its own `RewriteEngine On`, unless the child sets `RewriteOptions Inherit` (or a variant such as `InheritBefore`).
Server config is a rulebook memorised once before the shift; .htaccess is a note that might be pinned to any door along the corridor, so staff must check every door on every trip.
saying these in an interview costs you the question
- Claims Apache reads .htaccess once and caches it
- Thinks AllowOverride All is the 2.4 default
- Says only the file's own directory is checked
- Believes an .htaccess edit needs a graceful restart
- Treats AllowOverride purely as a mod_rewrite on/off switch