nginx returns 404 on a site that is clearly built, the /var/www traverse trap
June 12, 2026
The problem. A site is built, the files are in place, the nginx config points
at the correct public folder, and nginx still returns 404. Everything below the
docroot is world readable, so it makes no sense, until you look at the directories
above it.
The fix.
nginx runs as the www-data user. To serve a file, www-data has to traverse
every directory in the path, all the way down. If any directory along the way is
drwx------ (700), or otherwise blocks others, www-data can not pass through it,
and you get a 404 even though the file itself is perfectly readable.
Check the whole path at once:
namei -l /var/www/html/yoursite/public/index.html
Look for any component owned by your user with no execute bit for others. It is
very often /var/www itself, sitting at 700. Grant traverse, which is the execute
bit for others, not read:
chmod o+x /var/www
If your user owns /var/www, you can do this without sudo. www-data only needs to
pass through the directory, not list it, so o+x is the minimal and correct fix.
Nothing to reload, the next request just works.