Fixing Nginx + PHP-FPM Permission Denied (Error 13) on Linux: Complete Configuration Guide


2 views

The error message "stat() failed (13: Permission denied)" typically occurs when Nginx's worker process doesn't have proper access rights to the web directory. This can happen due to several configuration or permission issues between Nginx and PHP-FPM.

First, let's verify the essential configuration points that often cause this issue:

# Check directory permissions
ls -la /home/noisepages/

# Verify Nginx and PHP-FPM user settings
ps aux | grep nginx
ps aux | grep php-fpm

# Check socket permissions if using Unix socket
ls -la /dev/shm/php-fastcgi.sock

1. User/Group Mismatch

Make sure Nginx and PHP-FPM are running under users with proper permissions:

# In php-fpm.conf (or pool.d/www.conf)
user = www-data
group = www-data

# In nginx.conf
user www-data www-data;

2. Directory Permissions

Set correct permissions for your web root:

chown -R www-data:www-data /home/noisepages/www
chmod -R 755 /home/noisepages/www
find /home/noisepages/www -type f -exec chmod 644 {} \;

3. SELinux Context

On RHEL systems, SELinux might be blocking access:

# Temporary solution (not recommended for production)
setenforce 0

# Proper solution
chcon -R -t httpd_sys_content_t /home/noisepages/www
semanage fcontext -a -t httpd_sys_content_t "/home/noisepages/www(/.*)?"

Here's a corrected version of your configuration with important fixes:

server {
    listen       80;
    server_name  dev.noisepages.com;
    root   /home/noisepages/www;
    index  index.html index.htm index.php;

    access_log  logs/dev.access.log;
    error_log logs/dev.error.log;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \\.php$ {
        include        fastcgi_params;
        fastcgi_pass   unix:/dev/shm/php-fastcgi.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO $fastcgi_path_info;
    }
}

Ensure your PHP-FPM pool configuration matches these settings:

[www]
user = www-data
group = www-data
listen = /dev/shm/php-fastcgi.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

If issues persist, follow these debugging steps:

# Check effective permissions
namei -l /home/noisepages/www

# Verify PHP-FPM is running correctly
systemctl status php-fpm

# Test PHP-FPM directly
SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /dev/shm/php-fastcgi.sock

The stat() permission denied error (13) typically occurs when Nginx's worker process cannot access the requested directory or file. In your case, the error manifests when trying to access /home/noisepages/www/, indicating a filesystem permission issue rather than a pure PHP-FPM configuration problem.

# Check directory ownership and permissions
ls -la /home/noisepages/www
# Should show proper www-data or nginx user ownership

# Verify process ownership
ps aux | grep nginx
ps aux | grep php-fpm

Your configuration shows two potential issues:

  1. Mismatch between root directive and fastcgi_param SCRIPT_FILENAME
  2. Possible permission inheritance problems with home directories
# Incorrect:
fastcgi_param SCRIPT_FILENAME /home/dev/www/$fastcgi_script_name;

# Should match root:
fastcgi_param SCRIPT_FILENAME /home/noisepages/www/$fastcgi_script_name;

For RHEL systems using PHP-FPM pools:

# Set proper ownership
chown -R nginx:nginx /home/noisepages/www
find /home/noisepages/www -type d -exec chmod 755 {} \;
find /home/noisepages/www -type f -exec chmod 644 {} \;

# Ensure parent directory permissions
chmod 711 /home/noisepages

# SELinux context if applicable
chcon -R -t httpd_sys_content_t /home/noisepages/www

Ensure your pool matches Nginx user:

[www]
user = nginx
group = nginx
listen = /dev/shm/php-fastcgi.sock
listen.owner = nginx
listen.group = nginx

Check actual permissions being used:

strace -p $(pgrep nginx | head -1) 2>&1 | grep stat
namei -l /home/noisepages/www/index.php

Here's a verified working setup:

server {
    listen 80;
    server_name dev.noisepages.com;
    
    root /home/noisepages/www;
    index index.php;
    
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/dev/shm/php-fastcgi.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}