Nginx downloads PHP files instead of executing them
Fix the Nginx issue where PHP files download instead of executing by configuring the fastcgi_pass directive, PHP-FPM socket path, and server block order.
Nginx downloads PHP files to the user's device instead of executing them when the nginx.conf configuration does not pass PHP requests to the PHP-FPM process manager.
When Nginx Produces This Error
Nginx downloads PHP files instead of executing them when a visitor requests a
.php URL such as
example.com/index.php. Instead of seeing the rendered web page, the browser downloads the raw PHP source file. This behavior occurs because Nginx treats the PHP file as static content and serves it directly without forwarding it to PHP-FPM for processing.
Nginx also downloads PHP files when the
fastcgi_pass directive exists but points to the wrong PHP-FPM socket or TCP port. The connection fails silently and Nginx falls back to serving the file as a download.
What Causes Nginx to Download PHP Files Instead of Executing Them
Nginx downloads PHP files when the
fastcgi_pass directive is missing from the server block.Without a
fastcgi_pass directive in the location block that matches
.php files, Nginx has no instruction to forward the request to PHP-FPM. Nginx serves the file using its default handler, which triggers a download in the browser.
Nginx downloads PHP files when the PHP location block is in the wrong server block.If the
location ~ \.php$ block is defined in a different server block than the one handling the domain, Nginx matches the request to the correct server block but finds no PHP handler. The request falls through to the default file handler.
Nginx downloads PHP files when the
fastcgi_pass path does not match the PHP-FPM listen address.PHP-FPM can listen on a Unix socket (e.g.,
/var/run/php/php8.2-fpm.sock) or a TCP port (e.g.,
127.0.0.1:9000). A mismatch between the nginx.conf
fastcgi_pass value and the PHP-FPM
listen value prevents the connection.
Nginx downloads PHP files when
cgi.fix_pathinfo is set to
1 and the script path is invalid.PHP's
cgi.fix_pathinfo setting controls how PHP resolves the script filename. When set to
1, PHP may attempt to execute a non-PHP file or fail to locate the correct script, causing unexpected behavior.
How to Fix Nginx Downloading PHP Files
- Verify that the
fastcgi_passdirective exists inside the correct server block. The PHP location block must appear within the server block that handles the domain.
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}- Verify the PHP-FPM listen address. Open the PHP-FPM pool configuration and check the
listendirective:
sudo vi /etc/php/8.2/fpm/pool.d/www.confMatch the
listen value to the
fastcgi_pass value in nginx.conf. If PHP-FPM listens on a TCP port:
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}If PHP-FPM listens on a Unix socket:
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}- Set
cgi.fix_pathinfoto0inphp.inito prevent PHP from executing unintended scripts:
sudo vi /etc/php/8.2/fpm/php.ini
cgi.fix_pathinfo = 0- Verify that the file ownership matches the Nginx and PHP-FPM user. Check the Nginx worker user:
ps aux | grep nginxSet the PHP-FPM pool configuration to run as the same user:
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data- For PHP frameworks like WordPress or Laravel, add a
try_filesdirective that routes all requests throughindex.phpwith the query string:
location / {
try_files $uri $uri/ /index.php?$query_string;
}- Restart PHP-FPM and reload Nginx:
sudo systemctl restart php8.2-fpm
sudo nginx -t
sudo systemctl reload nginxHow to Verify the Fix
Nginx executes PHP files and returns rendered HTML instead of downloading them. Send a request to a PHP page:
curl http://example.com/index.phpThe response should contain rendered HTML, not raw PHP source code. Check the
Content-Type header:
curl -I http://example.com/index.phpThe header should show
Content-Type: text/html when PHP-FPM processes the file correctly. A
Content-Type: application/octet-stream or similar value indicates Nginx is still serving the file as a download.
Edge Cases and Variations
Nginx downloads PHP files only for specific URLs.The
location ~ \.php$ block may not match requests that use URL rewriting. For applications that rewrite all URLs through a front controller (e.g., WordPress, Laravel), the
try_files directive must route non-matching requests to
index.php.
Nginx downloads PHP files after adding a new server block.A new
default_server block without a PHP location handler intercepts requests intended for another server block. Verify which server block Nginx selects by checking the
server_name and
listen directives.
Related Nginx Errors
Nginx: 502 Bad Gateway-- Nginx returns 502 when it connects to PHP-FPM but receives an invalid response. The download behavior occurs when Nginx does not attempt the connection at all.
Nginx: connect() to php-fpm.sock failed (Permission denied)-- A permission error prevents the connection to PHP-FPM and may produce a 502 error instead of a download, depending on the nginx.conf fallback configuration.