/ โ† HTTP Error Fixes / 403 Forbidden on your site
In this guide
  1. What a 403 Forbidden actually means
  2. The common causes and what each one looks like
  3. How to diagnose it before changing anything
  4. The server changes that fix it
  5. Cloudflare, ModSecurity and security plugins
  6. A worked example
  7. The fix, step by step
  8. Edge cases worth knowing
  9. Keeping it fixed
  10. Questions and answers

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 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.

๐Ÿ’ก Search engines treat a 403 on a page much like a 404: the page cannot be fetched, so it will not be indexed, and a page that was indexed is eventually dropped. Google does not see a 403 as a signal to slow down crawling. If you want crawlers to back off because the server is busy, the right codes are 503 or 429.

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.

CauseTypical clueWho sees the 403
File set to 600 or 640, or owned by rootError log says permission denied, error 13Everyone, for those files only
A parent folder closed to the web serverEvery file below one folder fails at onceEveryone, whole section or site
No index file and directory listing offFolder address fails, files inside it loadEveryone, folder addresses only
Wrong root or document rootWhole site fails right after a config change or moveEveryone
deny all or Require all deniedError log says access forbidden by rule or client denied by server configurationEveryone, or everyone outside an allow list
Hotlink protectionImages fail when the page is opened from another domain, or for some apps and crawlersRequests with a missing or foreign referrer
Cloudflare WAF, Bot Fight Mode, country or rate rulesCloudflare-branded page, entry in security eventsCertain countries, networks, bots or tools
ModSecurity or a security pluginLog line naming a rule ID, or a plugin lockout noticeRequests with certain words, forms or user agents
Password or IP restriction on a folderOnly one area fails, often an admin or staging pathAnyone 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 messageMeaning
open() "..." failed (13: Permission denied)nginx cannot read the file or enter a folder above it
directory index of "..." is forbiddenNo index file in that folder and listing is off
access forbidden by ruleAn nginx deny line matched
AH01630: client denied by server configurationAn Apache Require or Deny rule matched
AH01276: Cannot serve directoryApache found no DirectoryIndex file
search permissions are missing on a component of the pathA parent folder lacks the execute bit
ModSecurity: Access denied with code 403A 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.

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.

โš ๏ธ Do not allow Googlebot by user agent alone. Anyone can send that user agent string. Use the firewall's verified bot field, or check the IP with a reverse DNS lookup that resolves to googlebot.com or google.com and back again.

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

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:

Questions and answers

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.

Find every 403 on your site

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 โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All HTTP Error Fixes  ·  How to fix 403 errors in audits  ·  Why is my website showing 404 errors  ·  How to fix 500 errors  ·  How to fix AI crawler access  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.