How .htaccess Is Found

How Apache Finds .htaccess on Every Request

Apache 129 keeps no list of .htaccess files. After mapping the URL to a path, the core's directory walk visits it one component at a time from /, merging each level's <Directory> sections. If the merged AllowOverride or AllowOverrideList is not None, it tries to open the file there.

Where the directory walk sits in request processing
Where the directory walk sits in request processing

strace shows the walk. Attached to the Apache children during one request, with AllowOverride All on /var/www/example and, deliberately wrongly, on <Directory />:

Tracing the files one request touchesApache config
pids=$(pgrep -d' ' -P "$(systemctl show -p MainPID --value apache2)")
sudo strace -f -e trace=openat,newfstatat -o /tmp/walk.txt $(printf -- '-p %s ' $pids) &
sleep 1; curl -s -o /dev/null localhost:8104/blog/2026/post.html; sleep 1
sudo kill $!
grep -v resumed /tmp/walk.txt | sed 's/^[0-9]* *//; s/AT_FDCWD, //; s/, O_RDONLY|O_CLOEXEC//'
Output
newfstatat("/var/www/example/blog/2026/post.html", {st_mode=S_IFREG|0644, ...}, 0) = 0
openat("/.htaccess") = -1 ENOENT (No such file or directory)
openat("/var/.htaccess") = -1 ENOENT (No such file or directory)
openat("/var/www/example/.htaccess") = -1 ENOENT (No such file or directory)
openat("/var/www/example/blog/.htaccess") = -1 ENOENT (No such file or directory)
openat("/var/www/example/blog/2026/.htaccess") = -1 ENOENT (No such file or directory)
openat("/var/www/example/blog/2026/post.html/.htaccess") = -1 ENOTDIR (Not a directory)
openat("/var/www/example/blog/2026/post.html") = 12

Six opens fail before the real file is read. /var/www/.htaccess is skipped because Ubuntu 225 's <Directory /var/www/> sets AllowOverride None at that level, and the last miss treats post.html as a directory. With None throughout, the request makes one stat and one open.