# Nginx 403 Forbidden Directory Access

You browse to a directory on your Nginx server and get a 403 Forbidden response. The error page is stark, and the logs confirm Nginx is actively denying access. This is one of the most common Nginx errors, and it almost always comes down to filesystem permissions, missing index files, or configuration restrictions.

Understanding the Error

A 403 Forbidden means Nginx understood the request but refuses to authorize it. Unlike a 404 where the resource doesn't exist, the resource is there - Nginx just won't let you see it.

Check the Nginx error log for the real reason:

bash
tail -f /var/log/nginx/error.log

Typical log entries look like:

bash
2026/04/04 10:15:32 [error] 1234#1234: *1 directory index of "/var/www/html/downloads/" is forbidden, client: 192.168.1.100, server: example.com, request: "GET /downloads/ HTTP/1.1"
bash
2026/04/04 10:16:45 [error] 1234#1234: *2 access forbidden by rule, client: 192.168.1.100, server: example.com, request: "GET /admin/ HTTP/1.1"

Common Cause 1: Missing Index File

When you request a directory (like /downloads/), Nginx looks for an index file. If none exists and directory listing is disabled, you get 403.

Diagnosis:

```bash # Check if index file exists ls -la /var/www/html/downloads/

# Check Nginx index configuration grep -r "index" /etc/nginx/sites-enabled/ ```

The error log confirms this: `` directory index of "/var/www/html/downloads/" is forbidden

Solution:

Option 1 - Add an index file: ``bash # Create a simple index.html echo "<h1>Downloads</h1>" > /var/www/html/downloads/index.html

Option 2 - Enable directory listing: ```nginx server { listen 80; server_name example.com;

location /downloads/ { autoindex on; autoindex_exact_size off; autoindex_localtime on; } } ```

Reload Nginx: ``bash sudo nginx -t && sudo systemctl reload nginx

Common Cause 2: Filesystem Permission Denied

Nginx runs as a specific user (usually www-data or nginx). If that user can't read the files, you get 403.

Diagnosis:

```bash # Find which user Nginx runs as ps aux | grep nginx # or grep -r "user" /etc/nginx/nginx.conf

# Check permissions on the directory ls -la /var/www/html/downloads/

# Test if Nginx user can access the path sudo -u www-data ls /var/www/html/downloads/ ```

Typical error log: `` 2026/04/04 10:20:15 [error] 1234#1234: *3 open() "/var/www/html/downloads/" failed (13: Permission denied), client: 192.168.1.100

Solution:

```bash # Fix directory permissions (directories need execute permission to traverse) sudo chmod 755 /var/www/html/downloads/

# Fix file permissions (files need read permission) sudo chmod 644 /var/www/html/downloads/*

# Fix ownership if needed sudo chown -R www-data:www-data /var/www/html/downloads/ ```

For the entire web root: ```bash # Set directory permissions find /var/www/html -type d -exec chmod 755 {} \;

# Set file permissions find /var/www/html -type f -exec chmod 644 {} \; ```

Common Cause 3: Parent Directory Execute Permission

Even if the target directory has correct permissions, every parent directory must have execute permission for the Nginx user.

Diagnosis:

bash
# Check each parent directory
namei -l /var/www/html/downloads/

Output shows permission at each level: `` f: /var/www/html/downloads/ drwxr-xr-x root root / drwxr-xr-x root root var drwxr-xr-x root root www drwx------ someuser someuser html <-- Problem: no execute for others drwxr-xr-x www-data www-data downloads

Solution:

bash
# Fix the problematic parent directory
sudo chmod 755 /var/www/html/

Common Cause 4: SELinux Restrictions (RHEL/CentOS)

On SELinux-enabled systems, even correct Unix permissions won't help if SELinux context is wrong.

Diagnosis:

```bash # Check SELinux status getenforce

# Check file context ls -Z /var/www/html/downloads/

# Check for SELinux denials ausearch -m AVC -ts recent | grep nginx ```

Solution:

```bash # Set correct SELinux context for web content sudo chcon -R -t httpd_sys_content_t /var/www/html/downloads/

# For directories that need write access sudo chcon -R -t httpd_sys_rw_content_t /var/www/html/uploads/

# Make changes permanent sudo restorecon -R /var/www/html/ ```

Or temporarily disable SELinux to test: ``bash sudo setenforce 0

Common Cause 5: Nginx Configuration Restrictions

Check for deny directives or missing allow rules.

Diagnosis:

```nginx # Check for access restrictions grep -r "deny|allow" /etc/nginx/

# Example problematic config location /admin/ { allow 10.0.0.0/8; deny all; # This denies everyone outside 10.x.x.x } ```

Solution:

Update the access rules: ``nginx location /admin/ { allow 192.168.1.0/24; # Your network allow 10.0.0.0/8; # Internal network deny all; }

Common Cause 6: Alias Directive Issues

When using alias, the trailing slash matters.

Problematic config: ``nginx location /images { alias /var/www/html/images; # Missing trailing slash }

Solution: ``nginx location /images/ { alias /var/www/html/images/; # Both have trailing slashes }

Or use root instead: ``nginx location /images/ { root /var/www/html; }

Verification Steps

  1. 1.Test Nginx configuration:
  2. 2.```bash
  3. 3.sudo nginx -t
  4. 4.`
  5. 5.Reload Nginx:
  6. 6.```bash
  7. 7.sudo systemctl reload nginx
  8. 8.`
  9. 9.Test access:
  10. 10.```bash
  11. 11.curl -I http://localhost/downloads/
  12. 12.`
  13. 13.Monitor logs:
  14. 14.```bash
  15. 15.tail -f /var/log/nginx/error.log
  16. 16.`

Quick Reference

Error Log MessageCauseSolution
directory index ... is forbiddenNo index file, autoindex offAdd index.html or enable autoindex
Permission deniedFilesystem permissionschmod/chown files and directories
access forbidden by ruleNginx allow/deny rulesUpdate access control directives
13: Permission deniedSELinux or filesystemCheck SELinux context or chmod
open() ... failed (13: ...)Execute permission missingchmod +x on parent directories

The 403 Forbidden error is almost always about permissions - either filesystem, SELinux, or Nginx configuration. Start with the error log, identify the specific denial reason, and apply the appropriate fix.