The Problem
You set up Nginx, open the browser, and get a blank 403 Forbidden. No stack trace, no helpful message. It almost always comes from one of two causes: Nginx can't read your files because of permission issues, or it's looking for an index file that isn't there.
Nine times out of ten, it happens right after a fresh server setup, after deploying files as root, or after changing the document root in your config.
Debug First: Read the Error Log
Don't touch anything yet. Check what Nginx is actually complaining about:
sudo tail -f /var/log/nginx/error.log
You'll see one of these two patterns:
# Case 1 โ permission denied reading a file
2024/01/15 10:23:45 [error] 1234#0: *1 open() "/var/www/html/index.html" failed (13: Permission denied)
# Case 2 โ no index file found in the directory
2024/01/15 10:23:45 [error] 1234#0: *1 directory index of "/var/www/html/" is forbidden
Different cause, different fix. Knowing which one you're dealing with saves you from chasing the wrong solution.
Fix 1: Wrong File or Directory Permissions
The Permission denied message means Nginx's worker process can't read your files. The worker runs as a specific user โ www-data on Debian/Ubuntu, nginx on CentOS/RHEL.
Check current permissions
ls -la /var/www/html/
Two numbers cover almost every case:
- Directories:
755โ must be executable (traversable) - Files:
644โ readable by everyone, writable only by owner
Fix permissions recursively
# Fix all directories
sudo find /var/www/html -type d -exec chmod 755 {} \;
# Fix all files
sudo find /var/www/html -type f -exec chmod 644 {} \;
Fix ownership
Even with correct permissions, if the files are owned by root and Nginx runs as www-data, access still fails:
# Confirm which user the worker runs as
ps aux | grep nginx | grep worker
# Fix ownership (swap www-data for nginx on CentOS/RHEL)
sudo chown -R www-data:www-data /var/www/html/
Don't forget the parent directories โ Nginx needs execute permission on every directory in the path, not just the web root itself:
ls -la /var/
ls -la /var/www/
Fix 2: Missing Index File
Got directory index is forbidden? Nginx found the directory just fine โ it simply has no matching index file to serve, and it won't list directory contents because autoindex is off by default.
Check what index files Nginx expects
grep -r "index" /etc/nginx/sites-enabled/
# or check the http block default
grep "index" /etc/nginx/nginx.conf
Default is usually index index.html index.htm or index index.php index.html for PHP stacks.
Check if the file exists
ls -la /var/www/html/
If you only have a home.html but Nginx is looking for index.html, pick one of these fixes:
Option A โ Create or rename the index file:
mv /var/www/html/home.html /var/www/html/index.html
Option B โ Update your Nginx server block to include your actual filename:
server {
listen 80;
server_name example.com;
root /var/www/html;
index home.html index.html index.htm;
}
Need directory listing instead?
server {
location /files/ {
autoindex on;
}
}
Only enable this for non-sensitive paths. Never on your web root.
Fix 3: SELinux Blocking Access (CentOS/RHEL)
On RHEL-based systems, SELinux can silently block Nginx even when permissions and ownership look correct:
# Check audit log for Nginx denials
sudo audit2why -a | grep nginx
# Restore the correct SELinux context
sudo restorecon -Rv /var/www/html/
# Or set it manually
sudo chcon -Rt httpd_sys_content_t /var/www/html/
Verify the Fix
# Test the config, then reload without downtime
sudo nginx -t && sudo systemctl reload nginx
# Confirm the response
curl -I http://localhost
# Expected: HTTP/1.1 200 OK
# Check the error log is now clean
sudo tail -20 /var/log/nginx/error.log
Quick Checklist
- Error log says Permission denied โ fix
chmodandchown - Error log says directory index is forbidden โ add or point to the index file
- Directories are
755, files are644 - Owner matches Nginx worker user (
www-dataornginx) - Parent directories are also traversable
- SELinux context set correctly on RHEL/CentOS
Tip: Calculate Permissions Without Guessing
If you ever need something other than 644 or 755 and aren't sure of the octal value, the Unix Permissions Calculator on ToolCraft is handy โ click the checkboxes for owner/group/other and it shows the number. Useful when setting up upload directories or CGI scripts with non-standard permission requirements.
Lessons Learned
Most 403 errors trace back to two habits: deploying files as root without fixing ownership afterward, and not checking whether the index filename matches the Nginx config. The error log is blunt about it โ it names the exact file and the exact reason. Start there, not from the browser message, and you'll usually have a fix in under two minutes.

