When setting up Nginx with PHP-FPM, the 403 Forbidden error typically stems from permission issues or misconfigured server blocks. Let's examine a real-world case where /srv/www/test/index.php
returns 403 despite 777 permissions.
# Verify directory ownership
ls -la /srv/www/
# Should show nginx:nginx ownership for test directory
# Check SELinux context if applicable
ls -Z /srv/www/test/
The most common culprit is mismatched user/group between Nginx and PHP-FPM:
; /etc/php-fpm.d/www.conf
user = nginx
group = nginx
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
Your location block for PHP needs crucial additions:
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
}
Instead of 777 permissions, use proper ownership:
chown -R nginx:nginx /srv/www/test
find /srv/www/test -type d -exec chmod 755 {} \;
find /srv/www/test -type f -exec chmod 644 {} \;
When logs aren't clear, trace system calls:
strace -p $(pgrep nginx) -f -e open,stat 2>&1 | grep test
strace -p $(pgrep php-fpm) -f -e open,stat 2>&1 | grep test
After fixing 403 errors, implement proper security:
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~* \.(engine|inc|install|module|profile|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(code-style\.pl|Entries.*|Repository|Root|Tag|Template)$ {
deny all;
}
When configuring Nginx with PHP-FPM, one of the most frustrating errors developers encounter is the 403 Forbidden response. This typically occurs even with correct file permissions and seemingly proper configuration. Let's dive deep into solving this.
The error log entry access forbidden by rule
suggests Nginx is actively rejecting access based on security rules. Even with files set to 777 permissions, the problem persists because:
- Nginx's security rules might be blocking access
- PHP-FPM pool configuration might have wrong user/group settings
- SELinux or AppArmor might be enforcing additional restrictions
First, verify these critical components in your setup:
# Check running processes
ps aux | grep nginx
ps aux | grep php-fpm
# Verify file ownership
ls -la /srv/www/test/
# Check Nginx error logs
tail -f /var/log/nginx/example-error.log
Here's a corrected server block configuration that properly handles PHP files:
server {
listen 80;
server_name example.com;
root /srv/www/test;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
Ensure your PHP-FPM pool (typically in /etc/php/8.1/fpm/pool.d/www.conf
) has matching user/group:
user = nginx
group = nginx
listen.owner = nginx
listen.group = nginx
The ideal permission setup should be:
chown -R nginx:nginx /srv/www/test
find /srv/www/test -type d -exec chmod 755 {} \;
find /srv/www/test -type f -exec chmod 644 {} \;
If using SELinux, you might need to adjust context:
chcon -R -t httpd_sys_content_t /srv/www/test
semanage fcontext -a -t httpd_sys_content_t "/srv/www/test(/.*)?"
restorecon -Rv /srv/www/test
Create a simple test file /srv/www/test/info.php
:
After applying all fixes, visiting http://example.com/info.php
should now display the PHP information page instead of 403 error.
If issues persist, enable debug logging in Nginx:
error_log /var/log/nginx/error.log debug;
Check for these specific patterns in logs:
- "*1 access forbidden by rule" - indicates security rule blocking
- "*1 Primary script unknown" - suggests PHP-FPM cannot access the script
- "*13 Permission denied" - shows filesystem permission issues