Why is my website saying 403 Forbidden? How to find and fix the cause
A 403 Forbidden response means your server received the request, understood it, and decided not to serve it. On a site you own, that refusal almost always comes from something you can change: file permissions the web server cannot read, a folder with no index file, a deny rule in nginx or .htaccess, or a firewall such as Cloudflare or a security plugin. It matters because a 403 on a public page stops visitors and search engines alike, and pages Googlebot cannot fetch eventually drop out of the index. This guide shows how to read the error log to find the exact reason, the commands that check permissions along the whole path, the server and firewall rules that most often cause it, and how to confirm the fix from more than one network.
What a 403 Forbidden actually means
Every HTTP response carries a three-digit status code. A 403 Forbidden is a client error, but on your own site the word client is misleading: the server found, or could have found, the thing you asked for and has refused to hand it over. That is different from a 404 Not Found, where the server says nothing exists at that address, and from a 401 Unauthorized, where the server asks you to log in and will try again if you send credentials.
A 403 is the server saying no without offering a way in. The refusal comes from one of three layers, and knowing which layer answered is most of the fix:
- The operating system. The web server process asked to read a file or enter a folder and the system said permission denied. The server turns that into a 403.
- The web server configuration. A rule in nginx, Apache,
.htaccessor the Plesk panel says this path, this IP address or this kind of request is not allowed. - A security layer in front of or inside the site. Cloudflare, another CDN, ModSecurity, a hosting firewall or a WordPress security plugin decided the request looked dangerous.
The page that comes with the code often gives the layer away: a plain page with nginx or Apache underneath came from the web server, and a branded page with a Ray ID came from Cloudflare.
The common causes and what each one looks like
Most 403s on small business sites come from a short list. The table pairs each cause with the clue that usually points to it, so you can start with the most likely one.
| Cause | Typical clue | Who sees the 403 |
|---|---|---|
| File set to 600 or 640, or owned by root | Error log says permission denied, error 13 | Everyone, for those files only |
| A parent folder closed to the web server | Every file below one folder fails at once | Everyone, whole section or site |
| No index file and directory listing off | Folder address fails, files inside it load | Everyone, folder addresses only |
Wrong root or document root | Whole site fails right after a config change or move | Everyone |
deny all or Require all denied | Error log says access forbidden by rule or client denied by server configuration | Everyone, or everyone outside an allow list |
| Hotlink protection | Images fail when the page is opened from another domain, or for some apps and crawlers | Requests with a missing or foreign referrer |
| Cloudflare WAF, Bot Fight Mode, country or rate rules | Cloudflare-branded page, entry in security events | Certain countries, networks, bots or tools |
| ModSecurity or a security plugin | Log line naming a rule ID, or a plugin lockout notice | Requests with certain words, forms or user agents |
| Password or IP restriction on a folder | Only one area fails, often an admin or staging path | Anyone not on the list |
If the 403 only affects some visitors, the cause is almost never file permissions. Permissions apply to every request equally. A 403 that depends on who is asking, from where or with which tool points at a rule or a firewall.
How to diagnose it before changing anything
Start by reproducing the 403 with a tool that shows the raw response. curl works on every system and shows the headers the browser hides:
curl -sI https://www.example.com/about/
curl -sI -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://www.example.com/about/
Compare the two. If the normal request returns 200 and the Googlebot one returns 403, something is filtering on the user agent. Look at the server header too: cloudflare means the answer may have come from the edge, and a cf-mitigated: challenge header means Cloudflare served a challenge page, which also carries a 403 status.
Read the error log
The error log almost always names the reason. On a typical Linux server the logs live in /var/log/nginx/error.log or /var/log/apache2/error.log. On Plesk each domain has its own under /var/www/vhosts/system/example.com/logs/, with error_log for Apache and proxy_error_log for the nginx layer in front of it.
sudo tail -n 50 /var/log/nginx/error.log
sudo grep -i "forbidden\|denied" /var/www/vhosts/system/example.com/logs/error_log | tail -n 20
| Log message | Meaning |
|---|---|
open() "..." failed (13: Permission denied) | nginx cannot read the file or enter a folder above it |
directory index of "..." is forbidden | No index file in that folder and listing is off |
access forbidden by rule | An nginx deny line matched |
AH01630: client denied by server configuration | An Apache Require or Deny rule matched |
AH01276: Cannot serve directory | Apache found no DirectoryIndex file |
search permissions are missing on a component of the path | A parent folder lacks the execute bit |
ModSecurity: Access denied with code 403 | A ModSecurity rule fired; the line includes its ID |
Check permissions along the whole path
The web server needs execute permission on every folder from the root down, and read permission on the file. One closed folder blocks everything beneath it, so check the full chain rather than the file alone:
ls -l /var/www/example.com/public/
namei -l /var/www/example.com/public/about/index.html
namei -l prints the owner and mode of each component, which makes a drwx------ folder halfway up the path easy to spot. If the error log stays silent while visitors see a 403, the request never reached your server, and the firewall in front of it is the place to look. Our guide to 403 errors in audits covers the case where only an audit tool or crawler is blocked.
The server changes that fix it
Permissions and ownership
The safe default for a normal PHP or static site is 644 for files and 755 for folders, owned by the account the site runs as. Set them in two passes so folders and files get the right modes:
sudo chown -R siteuser:siteuser /var/www/example.com/public
sudo find /var/www/example.com/public -type d -exec chmod 755 {} \;
sudo find /var/www/example.com/public -type f -exec chmod 644 {} \;
Keep stricter modes on files that hold secrets, such as wp-config.php, which many hosts set to 600 or 640 when PHP runs as the site user. Never fix a 403 with 777. It hides the real problem and lets any process on the server change your files.
nginx
Check that root points at the folder that holds the site, that an index line lists the files you use, and that no broad deny catches public paths:
server {
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
# Blocks hidden files such as .git and .env, but not the /.well-known/ folder
location ~ /\.(?!well-known) {
deny all;
}
}
A rule written as location ~ /\. { deny all; } without that exception also blocks /.well-known/, which breaks certificate renewals and some verification files. After any edit, run sudo nginx -t before sudo systemctl reload nginx.
Apache and .htaccess
On Apache 2.4 the access rules are Require lines; older Order, Allow and Deny lines still appear in old files. A leftover block like this denies everything in its folder:
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
Rename .htaccess to .htaccess-off for a minute and reload the page. If the 403 disappears, put the file back and comment out blocks with # one at a time until you find the culprit. A missing DirectoryIndex index.php index.html line, or Options -Indexes on a folder with no index file, causes the folder-only 403. For redirect rules in the same file, see fixing redirects on Apache.
Cloudflare, ModSecurity and security plugins
If the origin log shows nothing, the 403 was decided before the request reached you. In Cloudflare, open the security events log for the domain (under Security, then Events, in most dashboard layouts) and filter by the path or your IP address. Each event names the service that acted, such as a custom rule, a managed rule, Bot Fight Mode, rate limiting or an IP access rule, along with the action taken.
- Custom rules and IP access rules. Country blocks and broad user agent blocks are the usual offenders. Narrow them to the paths that need protecting, such as a login page.
- Managed rules. A false positive on a form or a long query string can be handled with an exception for that one rule and path rather than switching the rule set off.
- Bot Fight Mode. It challenges traffic that looks automated, including monitoring services and some legitimate tools. On the free plan it cannot be bypassed per path, so turn it off if it is catching traffic you need.
- Search engines. Cloudflare treats verified crawlers such as Googlebot as known bots. A custom rule that skips or allows requests where
cf.client.botis true keeps them out of your own blocks.
On the server, ModSecurity writes the rule ID into the error log; in Plesk you can switch a single rule off under Web Application Firewall rather than disabling protection. WordPress plugins such as Wordfence or iThemes Security keep their own block lists and live traffic views, and a plugin lockout often names itself on the 403 page. For crawlers specifically, the AI crawler access guide shows how to let the bots you want through while still blocking the rest.
A worked example
A small agency moves a client's brochure site to a new VPS, uploads the files with a new FTP client while logged in as root, and the whole site starts returning 403. The home page, the CSS and the images all fail, and the page shows a plain 403 Forbidden with nginx underneath, so the firewall is ruled out straight away.
$ sudo tail -n 3 /var/log/nginx/error.log
... open() "/var/www/client/public/index.html" failed (13: Permission denied)
$ ls -l /var/www/client/public | head -n 4
-rw------- 1 root root 8412 Oct 17 09:12 index.html
drwx------ 2 root root 4096 Oct 17 09:12 images
The files are owned by root with mode 600, and the folders are 700, so the www-data user nginx runs as cannot read or enter anything. Running the chown and two find commands from the section above restores normal ownership and modes. The next request returns 200, and a fresh URL Inspection live test in Search Console confirms Google can fetch the home page again. The agency also sets the FTP client to upload as the site user, so the problem does not come back with the next upload.
The fix, step by step
Step 1
Reproduce the 403 with curl
Request the failing address with curl -sI from your own computer, then again with a Googlebot user agent string. Note the status code, the server header and whether a cf-mitigated header appears. A plain nginx or Apache 403 page points at the origin server, while a branded page with a Ray ID points at Cloudflare. Writing down which addresses fail and which work tells you whether the problem is one file, one folder, one kind of visitor or the whole site.
Step 2
Read the server error log
Open the error log on the server with sudo tail -n 50 on the nginx or Apache log, or the domain's own log in Plesk. Find the line for your failing request and read the reason: permission denied, directory index forbidden, access forbidden by rule, client denied by server configuration, or a ModSecurity rule ID. If no line appears at all for your request, the refusal happened before the server, so move straight to the firewall step instead of changing files.
Step 3
Correct ownership and permissions
If the log reports permission denied, run namei -l on the failing file to see every folder on the path. Set the site files to the site user with chown -R, then use find to set folders to 755 and files to 644. Leave secret files such as wp-config.php at the stricter mode your host recommends. Reload the page and confirm the status changes to 200. If it does not, check for an SELinux context problem with ls -Z.
Step 4
Add or fix the index file
If the log says the directory index is forbidden, open the folder by SFTP or the file manager and check that it contains index.html or index.php. If the file exists under another name, rename it, or add that name to the nginx index line or the Apache DirectoryIndex line. Do not switch directory listing on just to clear the error, because that exposes every file in the folder. Request the folder address again and confirm it returns 200.
Step 5
Remove the blocking server rule
If the log mentions a rule, search the server block or .htaccess for deny all, Require all denied, Deny from all and hotlink protection lines. Check that root points at the right folder. Comment out one suspect rule at a time, run sudo nginx -t before reloading nginx, and retest after each change. When the 403 stops, rewrite that rule so it only covers the paths that truly need protecting rather than deleting your security rules altogether.
Step 6
Check Cloudflare and other firewalls
When the origin log is silent, open Cloudflare's security events and filter by the failing path or your IP address. The event names the rule, such as a custom rule, a managed rule, Bot Fight Mode or rate limiting. Adjust or narrow that rule, or add an exception for verified bots using cf.client.bot. Then check ModSecurity in Plesk and any WordPress security plugin's block list. Retest from your browser and with curl after each change.
Step 7
Test from another network
Your own IP may be allowed or blocked differently from your visitors. Load the page on mobile data with Wi-Fi off, or ask someone in another location to try it. Check folder password protection, IP allow lists and admin-area rules if only some people are refused. A page that works for you but fails elsewhere usually points at a country rule, an IP rule or a firewall reputation score rather than anything inside the site files.
Step 8
Confirm Google can fetch the page
In Google Search Console, open URL Inspection for the fixed address and run a live test. The result should say the page is available to Google, with a fetch that succeeded. Then look in the Page indexing report for URLs under Blocked due to access forbidden (403) and use Validate fix once the cause is gone. If the page had dropped out of the index, request indexing for the most important URLs after the live test passes.
Edge cases worth knowing
- SELinux. On Red Hat style servers, files can have perfect permissions and still be denied because their security context is wrong, often after moving them from a home folder.
ls -Zshows the context, andrestorecon -Ron the web folder resets it. - Only POST requests fail. Contact forms or checkouts returning 403 while pages load fine usually point at a WAF rule or a security plugin reacting to the submitted content, or a failed security token in the application.
- Only one country fails. Check country rules in Cloudflare and in the hosting firewall. Remember that Googlebot mostly crawls from the United States, so blocking that country blocks most of Google's crawling.
- Admin area only. Plesk password-protected directories, an
.htpasswdrule or a plugin that limits/wp-admin/to certain IPs will refuse anyone outside the list, including you on mobile data. - Behind a CDN, a 403 from the origin can be cached. Purge the CDN cache after fixing the origin, or the edge may keep serving the old refusal.
Keeping it fixed
Most 403s come back for the same reasons they appeared: files uploaded as the wrong user, a copied server block, or a new firewall rule. A few habits stop that:
- Deploy as the site user, not root.
- Test new firewall and WAF rules in log or simulate mode before switching them to block, where the service offers that option.
- After any server move or configuration change, request the home page, one inner page, a CSS file and an image with
curl -I, both normally and with a crawler user agent. - Watch the Page indexing report in Search Console for Blocked due to access forbidden (403), which lists the URLs Google was refused.
- Run a regular crawl so that new 403s show up before visitors find them. The HTTP error audit guide explains how to read the results, and HTTP errors on Plesk covers that panel in detail.
1. What does 403 Forbidden mean on my own website?
It means your web server received the request and refused to serve it, usually because of file permissions, a missing index file, a deny rule or a firewall. The server is not broken and the page may exist; something has decided the request is not allowed. Because the same code comes from several layers, the fastest route to the cause is the server error log, which names the reason, followed by your firewall's event log if the server log shows nothing for that request.
2. Is a 403 error my fault or the visitor's?
On a site you run, a 403 is nearly always caused by the site's own setup, not by the visitor. It sits in the client error range of status codes, but the cause is usually a permission setting, a server rule, a security plugin or a firewall setting that you control. The exception is a page you deliberately restrict, such as an admin area, where refusing strangers is the intended behaviour and no fix is needed.
3. What permissions should my website files have?
For most sites, files should be 644 and folders 755, owned by the account the site runs as. That lets the web server read files and enter folders while only the owner can change them. Files that hold passwords, such as wp-config.php, can be stricter, often 600 or 640, depending on how your host runs PHP. Avoid 777 on anything, because it lets every process on the server change the file and does not solve the underlying ownership problem.
4. Why does Cloudflare show a 403 Forbidden page?
Cloudflare shows a 403 when one of its security features blocks or challenges the request, such as a custom rule, a managed WAF rule, Bot Fight Mode, an IP or country rule, or rate limiting. The block page includes a Ray ID, and the security events log in the dashboard shows which rule acted on that request. Your origin server never sees these requests, so its logs stay empty, which is a useful clue that the firewall rather than the server is responsible.
5. Can a 403 error hurt my SEO?
Yes, if it affects pages you want indexed or the files they need to render. Google cannot fetch a page that returns 403, so it will not index it, and pages already in the index are dropped after repeated failures. Blocking CSS, JavaScript or images with a 403 can also stop Google rendering the page properly. Search Console reports these URLs under Blocked due to access forbidden (403) in the Page indexing report, which is the best place to check for accidental blocks.
6. Why do I get a 403 but other people do not?
A 403 that depends on who is asking is caused by a rule, not by file permissions, which affect everyone equally. Your IP address may be on a block list, your country may be blocked, a security plugin may have locked you out after failed logins, or your network may have a poor reputation score with the firewall. Test on mobile data, check the plugin's lockout list, and search your firewall's event log for your IP address to find the rule responsible.
7. What is the difference between 401, 403 and 404?
A 401 asks for authentication, a 403 refuses access outright, and a 404 says nothing exists at that address. With a 401 the server is telling you to log in and try again. With a 403 the server knows what you asked for but will not provide it, and logging in would not help unless the rule depends on a login. With a 404 the server cannot find the resource. Some hosts return 403 for missing files to hide which paths exist.
The HTTP error audit on aiwebpageseo.com requests your pages the way a crawler does and lists every URL that answers 403, so you can see whether the block hits real pages, assets or only bots.
Open HTTP Error Fixes โ