in

How to Fix File Permission Errors (403 Forbidden) on Linux Web Hosting

I once spent a genuinely embarrassing amount of time chasing a 403 error that turned out to be a single folder set to 700 by an overzealous deploy script. Everything else on the server was fine. If you’re staring at a 403 Forbidden error on Linux hosting right now, odds are good it’s something equally small — permissions, ownership, or a broken .htaccess rule are responsible for most cases, not a hack or a dying server.

Quick Answer

  • Folders should be 755, files should be 644 — that’s the standard baseline on almost every Linux web host
  • Check ownership too, not just permissions — a file can have the right permission bits and still be owned by the wrong user
  • A missing index file in a directory with directory listing disabled also throws 403, not just permission issues
  • Rename .htaccess temporarily to rule out a bad rewrite rule
  • SELinux (on RHEL-based systems) can block access even when standard Linux permissions look completely correct

Why This Happens

There’s rarely one single cause here, and that’s what makes 403 errors annoying to diagnose blind. A handful of things show up constantly:

Permissions set too restrictively. The web server process (usually running as www-data, apache, or nginx) needs read access to files and read-plus-execute access to directories to serve anything. If a folder ends up at 700 or a file at 600, the web server literally can’t reach it, regardless of who owns it.

Wrong ownership. This one trips people up constantly on VPS setups. So you can have perfectly correct permission bits — 755, 644, exactly right — but if the files are owned by your personal SSH user instead of the web server’s user (or group), the server still can’t read them depending on how the permission bits are structured for “other.”

A missing index file with directory listing disabled. If someone requests a folder path directly and there’s no index.html or index.php inside it, and the server’s configured to block directory listing (which is the sane, secure default), you get a 403 instead of a helpful file listing.

A broken or malicious .htaccess file. On Apache, .htaccess controls a lot of access behavior. A bad rewrite rule, or in worse cases a .htaccess file altered by malware injecting deny rules, can block legitimate requests outright.

SELinux context mismatches. This is the one that catches even fairly experienced admins off guard on RHEL-based distros — CentOS, Rocky, AlmaLinux. Standard Unix permissions can look completely fine, ls -la shows exactly what you’d expect, and you still get 403 because SELinux is enforcing a security context on top of the regular permission system.

Common Scenarios

  • Shared hosting via cPanel/hPanel — usually a permissions issue fixable through the file manager’s “File Attributes” or “Fix Permissions” tool, no shell access needed
  • VPS with manual deploys — ownership drift is common here, especially if a deploy script runs as root and leaves files owned by root instead of the web server user
  • After a server reboot — sometimes ownership or SELinux context resets to defaults that don’t match your actual application setup, which is a specific and annoying pattern worth checking for
  • Right after installing a security plugin or CDN — hotlink protection or overly aggressive firewall rules occasionally block legitimate requests as a side effect

Step-by-Step Fixes

Step 1: Check the actual permissions

Connect via SSH and run:

ls -la /var/www/yoursite/

Folders should show drwxr-xr-x (755) and files -rw-r--r-- (644). Anything more restrictive than that on the “other” column is a likely culprit, assuming the web server isn’t running as the file’s owner or group.

Step 2: Fix permissions recursively

find /var/www/yoursite/ -type d -exec chmod 755 {} \;
find /var/www/yoursite/ -type f -exec chmod 644 {} \;

This applies 755 to every directory and 644 to every file, which is the standard baseline for a typical web app. Note: this is a starting point, not a universal rule — some specific files (like a private config file with database credentials) are sometimes deliberately kept tighter, so don’t blanket-apply this without a second thought if your setup has files intentionally locked down.

Step 3: Check ownership

ls -la /var/www/yoursite/ | head

Compare the owner and group against whatever user your web server process actually runs as. On Ubuntu/Debian with Apache or Nginx, that’s usually www-data. On many RHEL-based setups, it’s apache or nginx.

chown -R www-data:www-data /var/www/yoursite/

Swap in the correct user and group for your setup — running this with the wrong values makes things worse, not better.

Step 4: Check for a missing index file

ls /var/www/yoursite/some-folder/

If there’s genuinely no index.php or index.html in a directory someone’s hitting directly, that’s your answer, and it’s not really a permissions bug at all — it’s the server doing exactly what it’s configured to do.

Step 5: Test by renaming .htaccess

mv .htaccess .htaccess-backup

Reload the page. If the 403 disappears, the .htaccess file has a rule causing it. Rename it back, then go through it line by line, or regenerate a clean default one if you’re on WordPress and don’t have custom rules you need to preserve.

Step 6: Check the actual error log

tail -n 50 /var/log/apache2/error.log

(or /var/log/httpd/error_log on RHEL-based systems). This is the step people skip too often, and it’s usually the fastest path to an answer — the log will often say exactly which file or directory triggered the denial, which turns guesswork into a five-minute fix.

How to Fix File Permission Errors

What Actually Worked For Me

The 700-folder story from the intro — here’s the actual sequence, because the clean version doesn’t really capture how it went. A client’s site started throwing 403 on one specific upload directory, nothing else. My first move was the obvious one: checked permissions on the whole site, everything looked fine at the root and most subfolders. So I moved on assuming it had to be .htaccess, since that’s usually my second guess. Renamed it, tested, 403 still there. Not .htaccess.

I checked SELinux status next, since the box was CentOS, and figured that was probably it given how often it catches people off guard. getenforce came back as Disabled. So, not that either. At that point I was mildly annoyed and just started running ls -la on every subdirectory individually instead of trusting a top-level glance, which is what I should have done first honestly. That’s when I found it — one specific uploads subfolder sitting at 700, created recently by an automated backup script that had briefly run as root and left odd permissions behind on its way out.

chmod 755 on that one folder fixed it in about ten seconds, after probably twenty minutes of checking things that weren’t the problem. Not a clean, methodical diagnostic story — more a case of checking the big obvious things first and only getting granular once those didn’t pan out.

Advanced Fixes and Edge Cases

SELinux context restoration. If you’re on a RHEL-based system and standard permissions check out but 403 persists, check SELinux with getenforce, and if it’s enforcing, try restorecon -Rv /var/www/yoursite/ to reset the security context to its expected default. This is a genuinely different problem from standard Unix permissions and gets missed constantly because the symptoms look identical.

Nginx-specific config checks. Unlike Apache, Nginx doesn’t read .htaccess at all by default — if you’re troubleshooting 403 on Nginx and keep checking .htaccess, that’s a wasted step. Check the actual server block config for a misplaced deny all; or an incorrect try_files directive instead.

Ownership drift after automated processes. Deploy scripts, backup tools, or cron jobs running under a different user than expected are a quieter but frequent cause. Worth checking stat filename on a file that’s misbehaving to confirm both owner and group, not just permission bits — a permission bit of 644 still fails if group ownership doesn’t match what the web server expects and the “other” bit isn’t permissive enough to compensate.

CDN or WAF-layer blocking, not server-layer at all. If you’re behind Cloudflare or a similar CDN/WAF and permissions and .htaccess both look completely correct, check the CDN’s security event log before assuming it’s a server-side issue — some firewall rules return 403 upstream of your actual server entirely.

Prevention Tips

  • Don’t run deploy or backup scripts as root without explicitly setting ownership back to the web server user afterward
  • Keep sensitive config files (database credentials, API keys) more restrictive than the general 644/755 baseline — but do it deliberately, not by accident
  • Check SELinux status early if you’re on a RHEL-based distro and something behaves inconsistently with what standard permissions suggest
  • Keep a clean backup of a working .htaccess file so you’re not reconstructing rewrite rules from memory during an outage

FAQ

Is 403 the same thing as 404? No. 404 means the resource doesn’t exist. 403 means the server found it but is refusing to serve it — a meaningful difference for troubleshooting, since they point in completely different directions.

Can a 403 error mean my site was hacked? It’s possible, particularly if .htaccess shows unfamiliar rules you didn’t add, but most 403 errors are permission or ownership issues, not compromise. Worth a malware scan if nothing else explains it, not the first assumption.

Why did this happen after a server reboot with nothing else changing? Ownership or SELinux context sometimes resets on reboot if it wasn’t persisted correctly, especially on cloud VPS setups with certain provisioning tools. Annoying, but a known pattern.

Do I need root access to fix this? Usually you need at least sudo access to change ownership properly. Basic permission changes on your own files sometimes work without it, depending on how the hosting account is set up.

Will chmod 777 just fix it faster? Technically, yes, and please don’t. That opens write access to literally anyone on the system, which is a security problem waiting to happen. Use 755/644 and fix the actual ownership issue instead.

Editor’s Opinion

403 errors are almost never as dramatic as the wording makes them sound. nine times out of ten it’s permissions, ownership, or a broken htaccess rule, in roughly that order of likelihood. the selinux thing genuinely deserves more attention than it gets in most guides though, since it fails completely silently from a standard permissions point of view and just wrecks your afternoon if you don’t know to check for it separately.

Written by ugur

Ugur is an editor and writer at (NSF Tech), specializing in technology and Windows. He produces in-depth, well-researched, and reliable stories with a strong focus on Windows, emerging technologies, digital culture, cybersecurity, AI developments, and innovative solutions shaping the future. His work aims to inform, inspire, and engage readers worldwide with accurate reporting and a clear editorial voice.

Contact: [email protected]