Many developers encounter this frustrating error when setting up PHP in user directories with Nginx. The "Primary script unknown" message indicates Nginx can't properly resolve the PHP script path when passed to FastCGI. Let's break down why this happens and how to fix it permanently.
The issue stems from path resolution between the alias directive and FastCGI parameters. When using:
alias /home/$1/public_html$2;
Nginx doesn't automatically update $document_root
to match the aliased path. The SCRIPT_FILENAME
parameter in fastcgi.conf then points to the wrong location.
Here's the corrected version that properly handles PHP in user directories:
location ~ ^/~(.+?)(/.*)?$ {
autoindex on;
autoindex_exact_size off;
alias /home/$1/public_html$2;
if (!-f $request_filename) {
return 404;
}
location ~ \.php$ {
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass 127.0.0.1:9000;
# Critical fix - rebuild the script path
fastcgi_param SCRIPT_FILENAME /home/$1/public_html$fastcgi_script_name;
# Security recommendation
fastcgi_param DOCUMENT_ROOT /home/$1/public_html;
}
}
1. The fastcgi_param SCRIPT_FILENAME
now explicitly uses the full path construction
2. We added document root specification for proper path resolution
3. The file existence check prevents attempts to execute non-existent scripts
When enabling user directories, consider these additional security measures:
location ~ ^/~(.+?)(/.*\.php)$ {
deny all;
return 403;
}
location ~* ^/~(.+?)(/.*\.(ini|log|conf|env|git))$ {
deny all;
return 403;
}
Create a test PHP file in your user directory:
echo "" > ~/public_html/test.php
Then verify with:
curl -I http://localhost/~yourusername/test.php
Check Nginx error logs if issues persist:
tail -f /var/log/nginx/error.log
For better performance with PHP-FPM in user directories:
location ~ \.php$ {
fastcgi_keep_conn on;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
Remember to reload Nginx after configuration changes:
sudo nginx -t && sudo systemctl reload nginx
When setting up PHP execution in user directories (~user/public_html) with Nginx, many developers encounter the frustrating "Primary script unknown" error. The configuration seems straightforward, but something breaks between Nginx and PHP-FPM.
Here's the typical setup that causes issues:
location ~ ^/~(.+?)(/.*)?$ {
autoindex on;
autoindex_exact_size off;
alias /home/$1/public_html$2;
location ~ \.php {
include /etc/nginx/fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
}
The core issue lies in how Nginx handles the alias
directive with PHP-FPM. When using alias inside a regex location block, Nginx doesn't properly set the SCRIPT_FILENAME
that PHP-FPM expects.
Here's the corrected configuration that properly handles PHP execution in user directories:
location ~ ^/~(.+?)(/.*)?$ {
alias /home/$1/public_html$2;
if (!-e $request_filename) {
rewrite ^ /~$1/index.php last;
}
location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi.conf;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
1. Explicit SCRIPT_FILENAME: We override the default to use $request_filename
instead of relying on the combination of $document_root$fastcgi_script_name
2. try_files directive: Ensures Nginx checks file existence before passing to PHP-FPM
3. Proper location matching: The \.php$
is more precise than \.php
For production environments, consider adding these security measures:
location ~ ^/~(.+?)(/.*)?$ {
# ... previous configuration ...
location ~ \.php$ {
# ... previous PHP configuration ...
fastcgi_param PHP_ADMIN_VALUE "open_basedir=/home/$1/public_html:/tmp";
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
}
}
Create a simple test file in your user's public_html:
echo "" > ~/public_html/test.php
Then access it via http://yourserver/~yourusername/test.php
If you still encounter issues:
1. Check Nginx error log: tail -f /var/log/nginx/error.log
2. Verify PHP-FPM is running: systemctl status php-fpm
3. Test PHP-FPM directly: SCRIPT_NAME=/test.php SCRIPT_FILENAME=/home/user/public_html/test.php php-cgi