A client's site says 403 Forbidden: what to do
Something answered, and the answer was no: the site's server, or a firewall or CDN in front of it, decided this request is not allowed. Here is the order we would work in.
1. What the code is telling you
- 403 Forbidden, or "Access Denied". The server understood the request and refuses it. Unlike a 401, it is not asking for a password; if you are already signed in, your account may simply not be allowed to see that page.
- 401 Unauthorized is different: the page wants a password. A staging site behind a browser password prompt (the small box the browser itself shows) answers 401 to everyone who has not signed in.
- 429 Too Many Requests means the server is limiting how often one visitor may ask. It usually clears by itself after a while.
- 404 Not Found means the server has no page at that address.
A page with 500, 502 or 503 on it is a fault on the server or in front of it, not a refusal: see what to do about a server error. If nothing answers at all, see what to do when a site times out.
2. Is it refusing everyone, or just some visitors?
This matters more than anything else, because a 403 is often aimed at somebody. Ask from a terminal:
curl -sSL -o /dev/null -w "%{http_code}\n" https://example.comOn Windows, type curl.exe rather than curl, and use NUL instead of /dev/null. Then try the site on your phone with Wi-Fi turned off, and ask the client to try it too.
- 403 everywhere, in every browser. The site itself is refusing. Go to step 3.
- 403 for you, fine on your phone. Your own address has been blocked, often after a few wrong passwords or too many page loads. It is usually a security plugin, the host's firewall or a CDN such as Cloudflare. Whichever did it keeps a list you can take the address off, or the host can.
- Fine in a browser, 403 from curl. A bot filter is refusing anything that does not look like a browser. Visitors are fine. Anything automated, such as a monitoring tool, a payment provider's callback or a search engine, may not be.
3. The usual causes
- A security plugin or firewall rule. Look at what changed: a new plugin, a stricter setting, a new rule. Most keep a log of what they blocked and why. If the domain uses Cloudflare and Cloudflare refused the request, its security events log shows which rule did it. A Cloudflare challenge page ("Just a moment..." or "Verify you are human") usually answers 403 too, so anything that cannot run the challenge, a monitor included, gets a 403 while people get through.
- A blocked country. A rule that refuses visitors from some countries refuses the client when they travel, and refuses any service that checks from there.
- File permissions after a move. If files were copied to a new host and every page is now 403, the web server may not be allowed to read them, because of their permissions or their owner. On most Linux hosting, folders are 755 and files are 644. The host can reset them.
- No home page file. If only the home page is 403, the web server may not find an index.php or index.html there, and is set, correctly, not to list the folder instead.
- A rule in .htaccess. On Apache and LiteSpeed hosting, a line such as
Require all deniedorDeny from all, outside a<Files>or<FilesMatch>block, refuses everyone for that folder and everything under it. To test, keep a copy, rename the file, and put it back straight away: it usually also holds the site's redirects and other security rules. If the page loads while it is renamed, the refusal is in it. On WordPress, other pages may show 404 during the test; that is expected.
4. Check the fix
Run the command from step 2 again. It should print 200. If the cause was a bot filter and you only allowed particular services through it, curl may still get 403; check in a browser, and from the service you allowed. If you changed a firewall or plugin rule, check from your phone on mobile data as well, so you know the change applies to everyone and not only to you.
5. Tell the client what happened
They may have seen the error themselves. For example:
The website was refusing some visitors because a security setting was stricter than it should have been. I have corrected it and checked the site loads normally again.
6. Next time, hear about it first
For Bionic Uptime, a 403 is a failed check, like any 400 or 500 code; so are 401, 404 and 429. When both of our locations, on two different companies' networks, and a retry agree within 45 seconds, while both locations are known to be working, it is confirmed as an outage and each person on that website's alert list gets one email. It names the code. When all three got a 403, it says: "Both checking locations received HTTP 403." If Cloudflare marked all three as its challenge page, it says so: "Both checking locations received a Cloudflare bot check page (HTTP 403) instead of the website." It is still counted as down, because we cannot see whether people get past it, but you know to look at the bot settings rather than the server. A failure that has cleared by the retry does not send an outage email. See the exact outage email.
The way we are most often wrong about a 403: a security rule that refuses our checks and lets visitors through. If it refuses both of our addresses, you get an outage email while the site works for everyone else. If it refuses only one, the site shows Status uncertain after five minutes and you get one email saying our two locations disagree, then one more when both can see it again. Never an outage alert. Our two addresses and the User-Agent every check sends are on the page about our checks, so the rule can allow them. A page behind a browser password prompt answers 401 to us every time, so monitor a public page of that site instead. A page behind a sign-in form usually loads the form, which tells you nothing about the page behind it.
3 websites are free, forever, with no card. Looking after several client sites?