Nginx cannot run PHP itself. It forwards PHP requests to PHP-FPM using the FastCGI protocol and relays the answer. Most PHP-on-Nginx problems, from "File not found" to 502 errors and security holes, come from a few lines in that handover. This guide explains each line of a typical PHP location so you can write it correctly.
Before you start
- Nginx and PHP-FPM installed; a working site: Nginx server blocks with PHP-FPM.
- Know your PHP-FPM socket path (
grep ^listen /etc/php/*/fpm/pool.d/*.conf).
A complete PHP location
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 60s;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}Line by line
try_files $uri =404
Only pass the request to PHP if the .php file really exists. Without it, a request such as /uploads/avatar.jpg/x.php could make older or misconfigured PHP setups execute an uploaded image as PHP. Debian's snippets/fastcgi-php.conf includes an equivalent check. Also keep security.limit_extensions = .php in the pool (the default).
fastcgi_split_path_info
Splits URLs like /index.php/products/42 into the script (/index.php) and PATH_INFO (/products/42). Needed by some frameworks; harmless otherwise. Note: with try_files $uri =404 such URLs 404, so apps using PATH_INFO need a location matching \.php(/|$) and a try_files $fastcgi_script_name =404 instead.
include fastcgi_params
Loads the standard variables PHP expects: REQUEST_METHOD, QUERY_STRING, CONTENT_TYPE, REMOTE_ADDR, SERVER_NAME, HTTPS and others. Debian also ships fastcgi.conf, identical except that it already sets SCRIPT_FILENAME.
SCRIPT_FILENAME
The most important parameter: the full path of the file PHP-FPM should run. $document_root$fastcgi_script_name becomes e.g. /var/www/example.com/public/index.php. If it is missing or wrong, PHP-FPM answers "Primary script unknown" and the browser shows File not found.
fastcgi_pass
Where PHP-FPM listens:
| Option | Example | When to use |
|---|---|---|
| Unix socket | unix:/run/php/php8.3-fpm.sock | Same server; slightly faster, protected by file permissions |
| TCP | 127.0.0.1:9000 | PHP-FPM in another container or server; bind to localhost or a private IP only |
Never expose a FastCGI port to the internet: anyone reaching it can make PHP-FPM run arbitrary files.
fastcgi_read_timeout
How long Nginx waits for PHP to reply. Too short gives 504s on slow pages; align it with PHP's limits as described in keep-alive and timeouts.
fastcgi_buffers and fastcgi_buffer_size
Nginx buffers PHP's response in memory so PHP-FPM is freed quickly, even for slow clients. fastcgi_buffer_size holds the response headers; large cookies or many headers overflow it and cause 502 "upstream sent too big header". 32k fixes most cases. Responses larger than the buffers spill to a temp file, which is fine.
Passing extra values to PHP
fastcgi_param APP_ENV production;
fastcgi_param PHP_VALUE "upload_max_filesize=64M \n post_max_size=64M";PHP_VALUE changes php.ini settings per site. Prefer setting them in the pool with php_admin_value, which the app cannot override.
Telling PHP about HTTPS behind a proxy
If TLS ends at a load balancer, PHP sees plain HTTP. Map the forwarded header to the HTTPS param:
map $http_x_forwarded_proto $fastcgi_https { default ""; https on; }
fastcgi_param HTTPS $fastcgi_https if_not_empty;Troubleshooting
- "File not found." / "Primary script unknown": wrong
SCRIPT_FILENAMEorroot, or PHP-FPM can't read the file (permissions, open_basedir, chroot). - 502 Bad Gateway: socket path wrong, PHP-FPM down, or socket permissions deny Nginx. See fix 502 with PHP-FPM.
- PHP file downloads instead of running: the request never matched the PHP location (check location order).
- "upstream sent too big header": raise
fastcgi_buffer_size.
FAQ: Nginx and PHP-FPM over FastCGI
Socket or TCP: which is faster?
Sockets are marginally faster on the same machine. The difference rarely matters; choose by architecture.
Can one Nginx serve several PHP versions?
Yes. Point each site's fastcgi_pass at the matching version's socket.
What is FastCGI caching?
Nginx can store PHP output and reuse it: see Nginx FastCGI cache.
