The server returns 403 Forbidden, but you're sure the file is on the host and you've entered the path correctly. The access log also only shows the 403 code and gives no clue as to the reason. This situation is frustrating because, unlike the 500 error which almost always means a code error, the 403 error can come from four completely different places, each with its own separate solution. Until you've identified the origin, any change to the files is just guesswork.
The first thing you should do is figure out whether the 403 is coming from the web server or from the application. If you see the default Apache or Nginx HTML response, the problem is in the web server layer. If your own custom page returns the 403 code, the application (PHP, WordPress, framework) is probably generating this code, and you should look for it in the code or plugins.
Origin One: File and Directory Permissions in Linux
The most common cause of 403 on shared hosting is incorrect permissions on a file or directory. The web server runs as a user such as www-data or nobody, and if that user doesn't have permission to read the file, you'll get a 403 response. With a simple command you can see the status:
ls -la /home/user/public_html/index.php
find /home/user/public_html -type d -not -perm 755
find /home/user/public_html -type f -not -perm 644
The output of the first command shows the permissions column; something like -rw------- means only the owner can read it and the web server has no access. The standard rule is: directories 755 and files 644. To fix:
find /home/user/public_html -type d -exec chmod 755 {} \;
find /home/user/public_html -type f -exec chmod 644 {} \;
Here's where people make a mistake: many set everything to 777 to fix the problem quickly. The site comes up, but now any script on the server can rewrite your files. The sign of it also shows up late; usually you find out when an unknown PHP file appears in the upload directory or the site's homepage changes without your involvement. Permission 777 is never a solution, it only hides the problem from view.
Origin Two: Missing Index in the Directory
When you open a directory's address and there's no index.php or index.html file inside it, the web server has two choices: display the file list or return a 403. Most hosts choose the second option for security reasons. So if you enter the address example.com/blog/ and get a 403, first check whether there's actually a file named index inside that directory:
ls -la /home/user/public_html/blog/
If it's empty or only has auxiliary files, that's the problem. You either need to create an index file, or redirect the path to another file in .htaccess:
DirectoryIndex index.php index.html home.php
A point that's less often noticed: sometimes the index file exists but its name starts with a capital letter, like Index.php. On Linux servers, file names are case-sensitive and the web server won't find it. This case never happens on Windows, and that's why when you migrate a site from a Windows host, you suddenly encounter a 403.
Origin Three: htaccess Rules and IP Restrictions
The .htaccess file can explicitly deny access. Two common patterns:
# Apache 2.4
Require all denied
# Apache 2.2 (old)
Order deny,allow
Deny from all
If these lines are in the file, all requests get a 403. The subtler case is when you have an IP-based rule and your IP has changed:
Require ip 185.55.10.20
Require ip 91.98.0.0/16
Here only the listed IPs are allowed in and everyone else gets a 403. If your IP has changed, you lock yourself out too. To test, temporarily rename the .htaccess file to .htaccess.bak and reopen the page. If the problem is solved, this file was the culprit and you need to review it line by line. Remember to restore the file after testing.
A practical note: if your IP is dynamic and keeps changing, IP-based restriction is a bad choice for the admin panel. A better alternative is two-factor authentication on the panel itself so you're not dependent on IP.
Origin Four: ModSecurity and the Web Application Firewall
This one is the most confusing of all, because the files and permissions are all fine and .htaccess has no problem either, but your request is blocked before reaching the site. ModSecurity is a web application firewall that inspects requests based on security rules, and if it detects a suspicious pattern, it responds with a 403 code.
The sign is this: a particular form doesn't work, or addresses with a specific parameter get a 403, but the rest of the site is fine. For example, sending a query with the word union select in the parameter, or uploading a file whose extension is on the blacklist. To see the exact reason, you need to look at the ModSecurity log:
tail -f /var/log/modsec_audit.log
grep "403" /var/log/apache2/error.log | tail -20
In the log, look for the rule ID; something like [id "942100"] which refers to SQL Injection. If you're sure your request is legitimate, you can disable that specific rule, but do this only for the specific rule, not all of ModSecurity. Turning off the firewall completely leaves the site defenseless against real attacks.
How to Quickly Determine Which Origin It Is
Don't change the order of checking. First, look at the response headers with curl:
curl -I https://example.com/blog/
If the header was Server: Apache or Server: nginx and the default 403 page was returned, the problem is in the web server layer. If you saw application-specific headers (like X-Powered-By: PHP), the problem is in the code. Then check in order: file permissions, presence of index, htaccess rules, and finally ModSecurity. This order goes from simple to complex and usually gets solved in the first two steps.
| Origin | Sign | Solution |
|---|---|---|
| File permissions | All pages 403, even simple files | chmod 644 and 755 |
| Missing index | Only directory addresses give 403 | Create index or DirectoryIndex |
| htaccess | Occurred after a recent change | Check Require and Deny |
| ModSecurity | Only specific requests are blocked | Check log and disable rule |
If you're working on Linux hosting and don't have access to the ModSecurity log, ask support to extract the rule ID for you; this information is usually not displayed at the user level. To check network and DNS issues, you can also use the DNS and network lookup tool to make sure the request reaches the server correctly.
A point I run into a lot in practice: if you've just migrated the site from another server and get a 403, there's a high chance the old .htaccess file with the previous server's settings is causing a problem on the new server. Before anything else, temporarily disable this file. Also, if you use content management systems, check the wp-admin directory or its equivalent, because some security plugins add a rule themselves that, after an update, locks out admin access.
To troubleshoot issues related to site slowness after fixing the 403, see the diagnosing a slow website guide. And if you're setting up a test environment, the staging environment setup guide helps you test changes without touching the main site.
Frequently Asked Questions
What's the difference between a 403 and 401 error?
A 401 error means authentication hasn't been done or the username and password are wrong; the server says identify yourself first. A 403 error means your identity is known but you don't have permission to access that resource. In practice, if a page returns a 401 you usually see a login prompt, but a 403 is rejected outright.
Can a 403 error come from a CDN?
Yes. Some CDNs block requests based on their own security rules and return a 403 code. To determine this, check the response headers with curl -I; if you see the CDN's server name rather than the main web server, you need to check that service's rules.
Why do only I get a 403 and other users don't have a problem?
An IP-based restriction has probably been applied, or your user account has been placed on the blocklist. Test with another internet connection or a VPN. If the problem is solved, the culprit is an IP-based rule in .htaccess or the server firewall.
Does changing file permissions to 777 solve the problem?
It might bring the site up temporarily, but this severely lowers security and isn't the correct solution. The correct permission is 644 for files and 755 for directories. If you still get a 403 with these values, the problem is elsewhere and you need to find it.
The next step is to grab the response headers right now with curl -I and determine which layer the 403 is coming from. Until you know this, any change to the files is just wasting time.
Comments 0
No comments yet — be the first!