When running Apache with event or worker MPMs, the standard approach for PHP execution is offloading it to PHP-FPM via mod_proxy_fcgi. This architecture provides massive performance benefits over mod_php, but it inherently creates a separation between the web server and the PHP processor.
One of the most frustrating and ubiquitous errors system administrators face in this setup is the notorious AH01071 error found in Apache’s error_log:
[proxy_fcgi:error] [pid 12345:tid 140123456789] [client 192.168.1.50:54321] AH01071: Got error 'Primary script unknown'
At its core, this error means Apache successfully proxied the request to the PHP-FPM socket, but PHP-FPM could not find or access the .php file it was told to execute. Below is a deep-dive diagnostic guide to identifying and fixing the root causes.
1. The Requested File Does Not Exist (Bot Scans)
The most common reason for this error isn’t actually a server misconfiguration, but rather malicious bots scanning your server for vulnerable plugins or old scripts (e.g., wp-login.php, xmlrpc.php, test.php).
Because Apache is usually configured to send all requests ending in .php directly to PHP-FPM, Apache blindly passes the request for the non-existent file. PHP-FPM checks the disk, realizes the file isn’t there, and throws the Primary script unknown error.
The Fix: Pre-check File Existence in Apache
Instead of passing every .php request to PHP-FPM, configure Apache to check if the file actually exists on the disk first using the <If "-f %{REQUEST_FILENAME}"> directive.
Open your Apache configuration (e.g., /etc/apache2/conf-available/php8.1-fpm.conf or your VirtualHost file) and modify the FilesMatch block:
<FilesMatch "\.php$">
# Only proxy to PHP-FPM if the requested file actually exists
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost"
</If>
</FilesMatch>
By doing this, requests for non-existent .php files will be handled directly by Apache, which will immediately return a standard 404 Not Found without ever waking up a PHP-FPM worker.
If you are dealing with extreme traffic loads and frequent brute-force attacks causing high CPU usage from constant bot scanning, consider isolating your stack. Upgrading from shared environments to highly tunable bare-metal Dedicated Servers or specifically network-optimized Dedicated Servers in Pakistan can provide the raw compute and networking power needed to filter bad traffic at the firewall level before it ever hits Apache.
2. Flawed ProxyPassMatch Directives
In older Apache configurations, it was common to use ProxyPassMatch to route PHP requests. However, ProxyPassMatch operates early in the Apache request cycle and can map URIs to paths incorrectly, especially if Alias or mod_rewrite is involved.
Bad Configuration:
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php8.1-fpm.sock|fcgi://localhost/var/www/html/$1
If the virtual host’s DocumentRoot changes or if an Alias points outside of /var/www/html/, PHP-FPM will look in the wrong directory, leading to the Primary script unknown error.
The Fix: Migrate to SetHandler
Modern Apache setups (2.4.9+) should always use SetHandler inside a <FilesMatch> block instead of ProxyPassMatch. SetHandler evaluates much later in the request cycle, ensuring that Apache has already resolved the absolute path to the file on disk.
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php-fpm.sock|fcgi://localhost"
</FilesMatch>
3. Systemd ProtectHome Restrictions
If you’ve recently migrated a site to a user’s home directory (e.g., /home/username/public_html/), you might suddenly see this error across the entire site.
Modern Linux distributions (like Ubuntu, Debian, and Arch) heavily utilize systemd security features. The default php-fpm.service unit file often ships with ProtectHome=true. This security feature mounts /home, /root, and /run/user as empty directories for the PHP-FPM process. As a result, PHP-FPM literally cannot see your files.
The Fix: Override Systemd Service
You need to override the systemd configuration for PHP-FPM.
- Create an override directory for your PHP-FPM service:
systemctl edit php8.1-fpm.service - Add the following lines to disable the restriction:
[Service] ProtectHome=false - Save, reload the systemd daemon, and restart PHP-FPM:
systemctl daemon-reload systemctl restart php8.1-fpm
4. Incorrect Chroot or Permissions
If you are running a multi-tenant environment (like cPanel or Plesk) and utilizing PHP-FPM chrooting for security, the Primary script unknown error will trigger if the document root passed by Apache does not map perfectly to the internal chrooted path of the PHP-FPM pool.
For example, if Apache requests /home/user/public_html/index.php, but the PHP-FPM pool is chrooted to /home/user/, PHP-FPM expects the path relative to the chroot, effectively looking for /home/user/home/user/public_html/index.php.
The Fix: Validate Pool Config
Check your pool configuration (e.g., /etc/php/8.1/fpm/pool.d/www.conf):
; If chroot is enabled:
chroot = /home/user
; Ensure chdir matches the directory INSIDE the chroot:
chdir = /public_html
Finally, always double-check standard Linux permissions. The user defined in your PHP-FPM pool configuration (e.g., user = www-data or user = user1) must have +x (execute) permissions on all parent directories leading to the script, and at least +r (read) permissions on the .php file itself. You can verify this with:
sudo -u www-data stat /path/to/your/script.php
By systematically checking proxy directives, file existence, systemd boundaries, and chroot mapping, you can permanently eliminate the Primary script unknown error from your Apache logs.
