Common causes
- The site's <Directory> block lacks Require all granted (Apache 2.4 denies by default outside /var/www)
- Old Apache 2.2 Order allow,deny / Allow from all syntax without mod_access_compat
- A Require ip or Require host rule that excludes the visitor
- An .htaccess file with Require all denied or Deny from all in a parent folder
- A <Files> or <FilesMatch> rule blocking the requested file type
- The DocumentRoot was moved but the Directory block still points to the old path
How to fix it
- Find which rule applies. The path in the log line tells you which file or folder was denied. Search the vhost and every .htaccess from that folder up to the root for Require, Deny and Order lines.
- Grant access to the site root. In the virtual host, add a <Directory /home/user/public_html> block with Require all granted. Run sudo apachectl configtest and reload Apache.
- Convert 2.2 rules to 2.4 syntax. Replace Order allow,deny plus Allow from all with Require all granted. Replace Deny from all with Require all denied. Do not mix the two styles in one block.
- Check IP restrictions. If you use Require ip 198.51.100.10, make sure your current IP is on the list. Behind a proxy or CDN, Apache sees the proxy IP unless mod_remoteip is set up.
- Confirm the block is intentional. AH01630 on files like wp-config.php, .env or .git is often a correct security rule. Only change rules for paths that should be public.
Apache 2.4 Directory block for a site root
<VirtualHost *:80>
ServerName example.com
DocumentRoot /home/user/public_html
<Directory /home/user/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost> How to stop it happening again
- Use only Apache 2.4 Require syntax
- Update Directory blocks whenever you change DocumentRoot
- Set up mod_remoteip when behind a proxy or CDN
- Keep deny rules for sensitive files and test them on purpose