Troubleshooting guide · http-status · Published 2026-08-15 · 4 min read
HTTP 403 forbidden
HTTP 403 forbidden guide: permissions, .htaccess rules, WAF false positives, index files and IP blocks, with an ordered fix sequence and prevention.
- ·Symptoms
- ·Common causes
- ·Fix order
Symptoms
The browser shows "403 Forbidden", "You don't have permission to access this resource", or "Access denied". The page may be the whole site, a single directory, or just the login URL. The server is up and answering, so a ping or even the home page works; only the protected or misconfigured resource refuses. A 403 has a precise meaning: the server understood the request but registered you, possibly for the wrong publicly listed reason, as barred from it.
Common causes
- File permissions block the web process. For example 000 or 600 on a file the server must read, or a directory with no execute bit. The classic WordPress case:
wp-config.phpreadable by the owner but not by the process that serves the request. - A
.htaccessor per-directory rule denies the path. ADeny from all, anOrdermistake, or a rule scoped to the IP of the visitor. - A security plugin or WordPress firewall rule flags the URL, the user agent, or the request header.
- Cloudflare or a WAF returns 403 before the origin ever sees the request (challenge verdict or a Managed Rule match).
- The request targets a file type the server refuses to serve, like a
.env,.git, or a PHP file outside an allowed directory. - An IP block or country rule includes the visitor or your own testing IP.
- A hotlink rule or a header that the CMS expects, e.g. a custom referrer or an authenticated cookie, is missing.
The fix order
- Split the scope. Load the failing URL in a private window. If it 403s again, the root is server-side, not the browser cache. Now test with the resource disabled, e.g. temporarily turn off the security plugin, then retest to pin down the suspect.
- Check file permissions. On shared hosting use your file manager or shell. Files should be 644, directories 755. A good test: if the site works after
chmod 644on the exact PHP file, the server could not read it. - Rename the
.htaccessif Apache is in play. A.htaccesswith a badDeny from allreproduces exactly this error. Rename it, reload the page, and if the page returns, re-add clean rules. - Check Cloudflare. If the origin works when you request the IP briefly, or the 403 page shows the Cloudflare branding, the block is at the edge. Look for the security level (Managed Challenge is usually a 403/block), the WAF or Firewall Rule match, and a possible IP or ASN rule. Disable any
Blockaction that matches your path and retest. - Check the web server error log. A 403 records the reason line such as "client denied by server configuration" or "File does not exist", which tells you which of the above families it belongs to.
- Fix the request, not the block. If the site is behind a login or a CDN, verify the request goes through the runner that sets the cookie or header; a direct origin call can look exactly like an attacker.
Verify
curl -I https://example.com/wp-admin/
HTTP/2 403
The status is 403 and not a 404, so the resource exists on disk. The log file holds the intended reason.
Prevention
- Set permissions at deploy time from a template (files 644, folders 755, config read-only to the process user).
- Keep security rules explicit and narrow: block by path prefix, not site-wide deny, and always allow your own IP range and search engine user agents.
- Test every WAF and security rule change in a staging environment before production.
- Store the expected 403 reasons in your runbook so a future change does not guess.
When to involve a professional
If the 403 is new site-wide after a domain or hosting move, or the log shows a rule you do not understand, back up and reinstall rules one at a time. A responsible host can review the log for you, but the cause chain is usually yours to unpick.