Nginx: 403 Forbidden

Fix the Nginx 403 Forbidden error caused by missing index files, wrong file permissions, incorrect ownership, or restrictive access rules in nginx.conf.

Nginx returns a 403 Forbidden error when the server block configuration, file permissions, or ownership prevent the web server from serving the requested resource.

When Nginx Produces the 403 Forbidden Error

Nginx produces the 403 Forbidden error when a client requests a URL and the server refuses to serve it. This commonly happens when a user visits a directory that has no index file and directory listing is disabled. The Nginx error log shows directory index of "/var/www/example.com/" is forbidden in this case.

Nginx also returns 403 Forbidden when the Nginx worker process cannot read the requested file due to restrictive file system permissions. The error log shows open() "/var/www/example.com/index.html" failed (13: Permission denied) when this occurs.

What Causes the 403 Forbidden Error in Nginx

Nginx returns 403 when the index file is missing from the document root.Nginx tries to serve the files listed in the index directive when a client requests a directory. If none of the listed files exist in the directory and the autoindex directive is not enabled, Nginx returns 403 Forbidden.

Nginx returns 403 when file or directory permissions are too restrictive.Nginx needs read permission on the requested file and execute permission on every parent directory in the path. If any directory in the chain from / to the document root lacks execute permission for the Nginx user, Nginx cannot traverse the path and returns 403.

Nginx returns 403 when file ownership does not match the Nginx worker user.The Nginx worker process runs as a specific user (typically www-data on Debian/Ubuntu or nginx on CentOS/RHEL). If the web files are owned by a different user and the permissions do not grant read access to others, Nginx returns 403.

Nginx returns 403 when SELinux blocks access on CentOS, RHEL, or Fedora.SELinux enforces mandatory access control policies. Even when file permissions and ownership are correct, SELinux may block Nginx from reading files if the security context is wrong.

How to Fix the 403 Forbidden Error in Nginx

  1. Verify that the index file exists in the document root. Create an index.html file if the directory is empty.
ls -la /var/www/example.com/

If no index file exists, create one:

sudo touch /var/www/example.com/index.html
  1. Update the index directive in nginx.conf to list the correct index file names for the application. Nginx checks each file in order and serves the first match.
server {
    root /var/www/example.com;

    location / {
        index index.html index.htm index.php;
    }
}

For PHP frameworks such as WordPress or Laravel that use URL rewriting, add a try_files directive:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}
  1. Fix file and directory permissions. Set 755 for directories and 644 for files. Nginx requires execute permission on directories to traverse the path and read permission on files to serve content.
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo find /var/www/example.com -type f -exec chmod 644 {} \;
  1. Fix file ownership. Set the owner to the user that runs the Nginx worker process. Find the Nginx user first:
ps aux | grep nginx

Set ownership of the document root to the Nginx user:

sudo chown -R www-data:www-data /var/www/example.com

Replace www-data with the actual Nginx worker user shown in the ps output.

  1. Test the nginx.conf configuration and reload Nginx.
sudo nginx -t
sudo systemctl reload nginx

How to Verify the Fix

Nginx stops returning 403 Forbidden when it can read the requested file. Send a test request:

curl -I http://example.com/

A 200 OK status code confirms that Nginx serves the file correctly.

Edge Cases and Variations

Nginx returns 403 when the autoindex directive is off and no index file exists.Enabling autoindex on makes Nginx display a directory listing instead of returning 403. This setting exposes all files in the directory to visitors and should only be used for intentional file-sharing directories.

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

Nginx returns 403 when SELinux is enforcing on CentOS or RHEL.Check the SELinux status with getenforce. If it returns Enforcing, set the correct security context for the web root:

sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.com/

Nginx returns 403 after migrating from Apache HTTP Server.Apache .htaccess rules do not work in Nginx. Access control rules such as Require all granted must be converted to Nginx allow and deny directives in the server or location block.

Nginx: 502 Bad Gateway-- Nginx returns 502 when the upstream backend fails to respond, which is a different class of error from the 403 access denial.

Nginx downloads PHP files instead of executing them-- A missing fastcgi_pass directive may cause Nginx to attempt serving PHP files as static content, which can also trigger permission-related issues.