How to Fix Nginx “13: Permission denied” Error When Serving Files from /home/user/public_html


4 views

When configuring Nginx to serve websites from user home directories (/home/username/public_html), the "13: Permission denied" error typically occurs because the Nginx worker process (running as user nginx) doesn't have proper access permissions to the user's home directory structure.

On CentOS/RHEL systems, user home directories typically have 700 permissions by default:


drwx------. 5 website website 4096 Jan  2 19:45 /home/website

This means only the owner (website) can access the directory, while Nginx runs as user nginx.

Here's how to properly configure this setup:


# Set correct permissions for the home directory
sudo chmod 711 /home/website

# Set permissions for the public_html directory
sudo chmod 755 /home/website/public_html

# Ensure files are readable by Nginx
sudo chown -R website:nginx /home/website/public_html
find /home/website/public_html -type f -exec chmod 644 {} \;
find /home/website/public_html -type d -exec chmod 755 {} \;

Even with getenforce showing "Disabled", you might need to set proper contexts if SELinux was previously enabled:


# Check current SELinux context
ls -Z /home/website/public_html

# Set proper context if needed
sudo chcon -R -t httpd_sys_content_t /home/website/public_html

Your server block looks good, but we can enhance it for better security:


server {
    listen 80;
    listen [::]:80;
    server_name website.com www.website.com;
    
    root /home/website/public_html;
    index index.html index.htm index.php;
    
    access_log /var/log/nginx/website.access.log;
    error_log /var/log/nginx/website.error.log;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php-fpm/website.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_param PHP_VALUE "open_basedir=/home/website/public_html:/tmp";
    }

    location ~ /\.ht {
        deny all;
    }
}

Create a dedicated PHP-FPM pool for better isolation:


[website]
user = website
group = nginx
listen = /var/run/php-fpm/website.sock
listen.owner = nginx
listen.group = nginx
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
php_admin_value[open_basedir] = /home/website/public_html:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
php_admin_value[upload_tmp_dir] = /home/website/tmp

After making these changes:


# Test Nginx configuration
sudo nginx -t

# Restart services
sudo systemctl restart nginx php-fpm

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

# Check directory permissions
namei -l /home/website/public_html/index.html

The key to solving Nginx permission issues lies in understanding Linux's file permission system. When Nginx tries to access /home/website/public_html, it needs both:


execute (x) permission on /home
execute (x) permission on /home/website
read (r) permission on public_html/

First, verify the current permissions structure:


ls -ld /home
ls -ld /home/website
ls -ld /home/website/public_html

Typical output showing the problem might look like:


drwx------ 5 website website 4096 Jan 2 19:45 /home/website

The most secure solution involves setting correct permissions while maintaining security:


sudo chmod 711 /home
sudo chmod 711 /home/website
sudo chown -R website:nginx /home/website/public_html
sudo chmod 750 /home/website/public_html

Even with SELinux disabled, it's good practice to know the proper contexts:


sudo chcon -R -t httpd_sys_content_t /home/website/public_html

Edit /etc/nginx/nginx.conf to ensure the worker process runs with proper permissions:


user nginx;
worker_processes auto;

For PHP processing, ensure your PHP-FPM pool matches:


[website]
user = website
group = nginx
listen.owner = nginx
listen.group = nginx

After making changes, always test:


sudo nginx -t
sudo systemctl restart nginx
sudo systemctl restart php-fpm

For more security, consider symlinking to avoid home directory access:


sudo mkdir -p /var/www/website.com
sudo ln -s /home/website/public_html /var/www/website.com/html

Then update your Nginx config to point to /var/www/website.com/html