When browsing a web application hosted on Apache HTTP Server 2.4, requests frequently fail with HTTP 403 Forbidden. In Apache's error logs, the rejection is accompanied by one of two core authorization errors:
[authz_core:error] [pid 1234:tid 5678] [client 203.0.113.10:54321] AH01630: client denied by server configuration: /var/www/html/index.php
[access_compat:error] [pid 1234:tid 5678] [client 203.0.113.10:54321] AH01797: client denied by server configuration: /var/www/html/.htaccess
The error message specifically states that access was denied by "server configuration", not the underlying filesystem. While Unix file permissions (chmod / chown) and SELinux contexts can prevent Apache from reading files on disk, AH01630 indicates that Apache's own authorization engine (mod_authz_core) evaluated the request and explicitly denied access.
This guide details the architectural authorization shift between Apache 2.2 and 2.4, provides step-by-step fixes for <Directory>, .htaccess, SELinux, and reverse proxies, and outlines automated monitoring workflows.
[!TIP] Free Diagnostic Tools for Webmasters & SREs:
- š Pingzo HTTP Header & Status Checker ā Inspect live server response headers, redirect chains, and HTTP 403 Forbidden status codes.
- š Pingzo HTTP Status Code Inspector ā Look up RFC definitions, browser implications, and debugging steps for 403 vs 401 vs 500 errors.
- ā” Pingzo Page Speed & TTFB Test ā Measure server response latency and Time to First Byte across global test locations.
- š” Pingzo Free Ping & Port Test ā Confirm whether port 80 and 443 listeners are accepting TCP connections.
1. Architectural Root Cause: The Apache 2.2 to 2.4 Migration
The most frequent trigger for AH01630 is deploying legacy Apache 2.2 access control syntax (Order, Allow, Deny) onto an Apache 2.4 server without configuring modern Require directives.
APACHE 2.4 AUTHORIZATION PIPELINE
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā 1. Inbound HTTP Request Received ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā 2. Match VirtualHost & Location Directives ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā 3. Evaluate <Directory> & .htaccess Authorization ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā mod_authz_core Decision? ā
āāāāāāāāāāāāāāā¬āāāāāāāāāāāāāā
ā ā
Require all granted Require all denied / No match
ā ā
ā¼ ā¼
āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Check OS / Unix ā ā ā ABORT: HTTP 403 Forbidden ā
ā Filesystem Perms ā ā Log: AH01630 client denied ā
āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
In Apache 2.4, access control is managed by mod_authz_core using provider-based Require rules. If an upgraded server lacks a matching Require all granted directive, Apache's secure default (Require all denied) halts the request before reading files on disk.
2. Comparative Matrix: Apache 2.2 vs Apache 2.4 Directives
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Authorization Scenario ā Legacy Apache 2.2 Syntax ā Modern Apache 2.4 Syntax ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Grant Access to Everyone ā Order allow,deny ā Require all granted ā
ā ā Allow from all ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Deny Access to Everyone ā Order deny,allow ā Require all denied ā
ā ā Deny from all ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Restrict by Single IP ā Order deny,allow ā Require ip 192.168.1.50 ā
ā ā Deny from all ā ā
ā ā Allow from 192.168.1.50 ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Restrict by Subnet / CIDR ā Allow from 10.0.0.0/24 ā Require ip 10.0.0.0/24 ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Combining Access Logic ā Complex Order mixing ā <RequireAll> / <RequireAny> ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Underlying Core Module ā mod_authz_host ā mod_authz_core ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Boolean Authorization Logic in Apache 2.4
Apache 2.4 allows complex combinatorial authorization logic using container directives:
$$\text{Access}{\text{RequireAll}} = \bigwedge{i=1}^n \text{Condition}_i \quad \text{(Logical AND: All conditions must pass)}$$
$$\text{Access}{\text{RequireAny}} = \bigvee{i=1}^n \text{Condition}_i \quad \text{(Logical OR: Any condition may pass)}$$
3. Step-by-Step Fixes for AH01630
1. Fix the <Directory> Block in VirtualHost Configuration
Open your site configuration file (e.g., /etc/apache2/sites-available/example.conf or /etc/httpd/conf.d/example.conf) and replace legacy 2.2 directives with Require all granted:
# ā BROKEN: Legacy Apache 2.2 syntax triggers AH01630 on Apache 2.4
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
<Directory /var/www/html>
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
# ā
FIXED: Production-ready Apache 2.4 configuration
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/html
<Directory /var/www/html>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example_error.log
CustomLog ${APACHE_LOG_DIR}/example_access.log combined
</VirtualHost>
2. Resolve Root Filesystem Lockdown Conflicts
Default Apache distributions (such as Debian's /etc/apache2/apache2.conf or RHEL's /etc/httpd/conf/httpd.conf) enforce root filesystem lockdown:
# Global root lockdown (DO NOT REMOVE)
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
[!CAUTION] Never change
<Directory />toRequire all granted. Doing so exposes system files like/etc/passwdto web exploits. Instead, explicitly declareRequire all grantedfor your specific document root (e.g.,<Directory /var/www/html>).
3. Fix Conflicting .htaccess Directives
If AllowOverride All is active, rules inside .htaccess can override your virtual host declarations:
-
Search for
.htaccessfiles:find /var/www/html -name ".htaccess" -
Inspect for legacy or explicit deny rules:
# ā BROKEN in .htaccess: Order deny,allow Deny from all # ā FIXED: Require all granted -
Protect Sensitive Files Safely:
# ā Securely block access to .env and config files only <FilesMatch "^\.(env|git|htaccess|ini)$"> Require all denied </FilesMatch>
4. Fix Linux Filesystem Permissions & Directory Traversal
Apache must have read (r) and execute (x) traversal permissions on every parent directory leading to the target file:
# 1. Audit path traversal permissions
namei -l /var/www/html/index.php
Ensure directories have 755 permissions and files have 644:
# 2. Fix directory and file permissions
sudo chown -R www-data:www-data /var/www/html # Debian / Ubuntu
# sudo chown -R apache:apache /var/www/html # RHEL / Rocky Linux
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
5. Fix SELinux Contexts (RHEL / Rocky / AlmaLinux / CentOS)
On SELinux-enforcing systems, Apache cannot read files if they lack the httpd_sys_content_t security context:
# 1. Inspect SELinux security labels
ls -laZ /var/www/html
# 2. Restore default httpd security contexts
sudo restorecon -Rv /var/www/html
# 3. For custom web directories outside /var/www:
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/myapp/public(/.*)?"
sudo restorecon -Rv /srv/myapp/public
6. Fix Reverse Proxy <Proxy> Authorization
When using Apache as a reverse proxy, mod_proxy requires authorization inside a <Proxy> container:
# ā
Production Reverse Proxy Authorization
<VirtualHost *:80>
ServerName api.example.com
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
<Proxy "*">
Require all granted
</Proxy>
</VirtualHost>
4. Validation Commands & Syntax Testing
Execute this verification sequence after updating your configuration:
# 1. Test Apache configuration syntax
sudo apachectl configtest
Expected Output: Syntax OK
# 2. Confirm authorization modules are loaded
apachectl -M | grep -E 'authz_core|authz_host'
# 3. Inspect virtual host bindings
sudo apachectl -S
# 4. Gracefully reload Apache
sudo systemctl reload apache2 # Debian / Ubuntu
# sudo systemctl reload httpd # RHEL / Rocky Linux
# 5. Test HTTP 200 response via cURL
curl -vI http://example.com/
flowchart TD
A["Client Request: HTTP 403 Forbidden"] --> B{"Check /var/log/apache2/error.log"}
B -- "AH01630: client denied" --> C{"Has 'Require all granted' in <Directory>?"}
C -- "No / Uses 2.2 syntax" --> D["Add 'Require all granted' & reload Apache"]
C -- "Yes" --> E{"Check .htaccess files"}
E -- "Deny rule present" --> F["Remove 'Require all denied' from .htaccess"]
E -- "Clean" --> G{"Check SELinux / Permissions"}
G -- "SELinux context wrong" --> H["Run: restorecon -Rv /var/www/html"]
G -- "Perms wrong" --> I["Run: chmod 755 for dirs, chmod 644 for files"]
5. Proactive HTTP Status & Endpoint Monitoring
Authorization regressions and 403 Forbidden errors commonly occur during automated deployments, CMS updates, or server migrations.
Continuous synthetic monitoring ensures your SRE team is instantly notified before users encounter broken authorization pages.
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Monitoring Check ā Operational Benefit ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā HTTP Status Code Validation ā Instantly catches 403 Forbidden errors ā
ā Multi-Region Uptime Checks ā Tests global access across 15+ nodes ā
ā Response Time Telemetry ā Tracks TTFB and server processing latency ā
ā Real-Time Alert Channels ā Instant notifications via WhatsApp/Slack ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Pingzo Monitoring Plans & Features
| Feature / Plan | Free | Starter ($5/mo) | Pro ($12/mo) | Agency ($29/mo) |
|---|---|---|---|---|
| Monitors Included | 1 Monitor | 10 Monitors | Unlimited | Unlimited |
| Check Frequency | 15 Minutes | 5 Minutes | 2 Minutes | 1 Minute |
| HTTP Status Code Checks | Included | Included | Included | Included |
| Alert Channels | WhatsApp, Slack, Telegram | WhatsApp, Slack, SMS | Multi-Team Routing | |
| Response Time Telemetry | 24 Hours | 30 Days | 90 Days | 365 Days |
| Custom Status Pages | Pingzo Branded | Branded | Custom Domain | White-Label |
Summary Troubleshooting Checklist
- Migrate 2.2 Directives: Replace
Order allow,deny/Allow from allwithRequire all granted. - Audit
.htaccess: Inspect for restrictiveRequire all deniedorDeny from allrules. - Verify Permissions: Ensure directories are
755(drwxr-xr-x) and owned bywww-dataorapache. - Fix SELinux: Run
restorecon -Rv /var/www/htmlto ensurehttpd_sys_content_tcontext. - Reload & Verify: Run
sudo apachectl configtest && sudo systemctl reload apache2.
š Monitor Your HTTP Endpoints & Response Codes with Pingzo ā Set up automated uptime and HTTP status monitors with instant WhatsApp alerts in under 3 minutes.
Stop Finding Out About Outages from Angry Users
Get instant WhatsApp & Discord alerts the second your API, website, or server goes down. Setup in 30 seconds with 60-second checks.