Website Checker - HTTP 403 Forbidden: Six Causes and How to Rule Each One Out

HTTP 403 Forbidden: Six Causes and How to Rule Each One Out

Aug 07, 2026 · HTTP Status Codes

Friday, 5:40 pm. A deploy script rsyncs a release to production and every page on the site starts answering HTTP 403 Forbidden. Nothing in the application logs, because the application never ran — the web server itself refused to read the files. The culprit: rsync ran as the wrong user and the new release directory landed with permissions the nginx worker couldn't traverse. One chmod later the site was back, and I've been suspicious of deploy-day 403s ever since.

That's the frustrating personality of the 403 status code: the server understood your request completely, has decided you can't have the resource, and is under no obligation to explain. Debugging one is a process of elimination — so here's the elimination order that's served me well.

What the 403 status code is really saying

A 403 means authorization failed, not authentication. The server may know exactly who you are (or not care); either way, the answer for this resource is no, and — unlike a 401 — re-sending credentials won't change it. Something between the request and the file said "denied": filesystem permissions, a server rule, a firewall, a security plugin. The whole job is figuring out which layer said it.

First five minutes: scoping the blast radius

Before touching any config, establish three facts. Is it every URL or one path? Is it every visitor or just some? Did anything change recently? Two commands get you most of the way. Check whether the 403 is site-wide:

curl -o /dev/null -s -w "%{http_code}\n" https://example.com/ https://example.com/some-page/ https://example.com/wp-admin/

Then check whether it's you specifically — request the same URL through a different network (phone hotspot works) or a different user agent:

curl -sI -A "Mozilla/5.0" https://example.com/ | head -1

Site-wide and everyone → permissions or a server-level rule. One path → a directory rule or missing index. Only some visitors → WAF, IP block, or geo rule. That triage tells you which rows of the table below to check first.

The six causes, and the fastest test for each

CauseTypical fingerprintHow to confirm
File permissions / ownershipSite-wide after a deploy or migrationError log says "Permission denied"; check with ls -l as the web server user
Directory listing disabled403 only on URLs ending in / with no index fileRequest /somedir/index.html directly — if that works, the dir just has no index
WAF or security plugin blockOnly some visitors, or only certain request patternsBlock page mentions the vendor; server logs show the request never reached the app
IP or geo restrictionWorks on one network, 403 on anotherCompare curl from two source IPs; look for deny rules or geo config
Hotlink protection misfiringImages/fonts 403 when loaded from your own pagescurl the asset with and without a Referer header
Explicit deny rulesOne path, all visitors, forevergrep the server config and .htaccess for deny/return 403 rules on that path

On the permissions case specifically: the web server user needs read on files, and execute (traverse) on every directory in the path above them. A perfectly readable file inside a 700 directory owned by the deploy user still yields 403. The error log states this plainly — tail -50 /var/log/nginx/error.log and look for "Permission denied" or "directory index of ... is forbidden."

The 403s only some people see

The hardest 403s to debug are the ones you can't reproduce. A WAF rule that triggers on a particular query string, a rate limiter that flags one office's shared IP, a geo block covering a country you never test from. Two habits make these tractable. First, get the request ID: most WAF block pages (Cloudflare, Sucuri, ModSecurity setups) print a ray or incident ID you can look up to see exactly which rule fired. Second, trust reports you can't reproduce — ask the affected user for the full URL, their IP, and a screenshot of the block page, then search your firewall logs for that combination. Loosen the specific rule rather than disabling the WAF; the rule usually fired for a reason, just too broadly.

Bots deserve the same attention: security plugins that challenge "suspicious" traffic sometimes classify Googlebot as suspicious. Verify by checking your logs for 403s served to crawler user agents.

What 403s do to your search presence

Google treats a persistent 403 roughly like a page that's gone: it can't fetch the content, and after repeated failed attempts the URL drops out of the index. A misconfigured rule that 403s your product pages for a week can undo months of ranking work. Subtler and more common: assets blocked by overzealous hotlink protection or WAF rules, so the page returns 200 but renders broken for Googlebot — missing CSS, missing images — and gets judged on the wreckage. If your 403s are on pages that genuinely shouldn't exist publicly, consider whether they'd be better served as a 404; a 403 confirms to the curious that something is there, while a 404 reveals nothing.

Finding the damage is straightforward: run a crawl of your site and filter for 403 responses, then sort by whether each URL is meant to be public. For WordPress sites — where security plugins cause a disproportionate share of accidental blocks — the hardening advice in our WordPress SEO guide covers which paths to protect without catching crawlers in the net.

Preventing the next one

Make deploys set permissions explicitly instead of inheriting whatever the deploy user's umask produces — an explicit chmod -R or the right rsync flags in the release script ends the Friday-evening class of 403 permanently. Put a post-deploy smoke test on your key pages that fails the pipeline on any non-200. And when you add a WAF or security plugin rule, test it from an incognito session and against your own crawler before trusting it — the rule you wrote for attackers shouldn't be the reason your traffic graph dips on Monday.

Frequently Asked Questions

Why am I getting a 403 Forbidden on my own website?

The most common causes are file permission problems after a deploy or migration, a security plugin or WAF rule blocking your IP, or a directory with listing disabled and no index file. Check the server error log first — permission failures are logged explicitly, which immediately separates filesystem causes from rule-based blocks.

Can a 403 error affect my Google rankings?

Yes. URLs that persistently return 403 get dropped from the index because Google can't fetch them, and assets blocked by security rules can make otherwise fine pages render broken for Googlebot. Audit which URLs serve 403 and confirm each one is intentionally private, and check your logs for 403s being served to crawler user agents.

How do I tell if a WAF is causing the 403?

WAF blocks typically show a vendor-branded block page with a ray or incident ID, and the request never appears in your application logs. Reproduce the request with curl from a different network — if one source IP gets 403 and another gets 200 for the identical request, a firewall or rate limiter is making the decision, and the incident ID will point to the exact rule.

Should a private page return 403 or 404?

A 403 confirms the resource exists but is off-limits, which is useful information for an attacker probing your site. Returning 404 for sensitive paths reveals nothing about what exists. Use 403 where the distinction helps legitimate users (like a logged-out members area) and 404 where secrecy matters more.

Try WebsiteChecker.Tech Free

Run a free technical SEO audit on any website. Get a client-ready report in minutes.

Start Free Scan