How to Fix “Primary script unknown” Error in Nginx When Configuring PHP with Userdir


4 views

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