Skip to content

Nginx + PHP FastCGI on Windows: no php-fpm, no fantasy

Verified 1 min read

Run php-cgi as a FastCGI listener, point Nginx at it, set SCRIPT_FILENAME and fix_pathinfo, and know why IIS FastCGI is often the better Windows choice.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Page type
Task

Nginx does not spawn PHP workers. On Windows you start php-cgi.exe as a FastCGI listener and point Nginx at it:

Terminal window
C:\PHP\8.4\php-cgi.exe -b 127.0.0.1:9000 -c C:\PHP\8.4\php.ini

Then:

location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}

There is no official Windows php-fpm. If a guide says “install php-fpm on Windows”, it is using a third-party build or confusing FastCGI with FPM.

server {
listen 8084;
server_name php.local;
root C:/sites/php;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_pass 127.0.0.1:9000;
fastcgi_read_timeout 60s;
}
}

SCRIPT_FILENAME is the one parameter people forget. Without it, PHP-CGI returns “No input file specified” or a blank page.

cgi.fix_pathinfo=0
fastcgi.impersonate=1
date.timezone=UTC
expose_php=Off
display_errors=Off
log_errors=On

cgi.fix_pathinfo=0 plus try_files/=404 prevents a nonexistent .php path from being passed to PHP-CGI. It is not a substitute for upload validation.

PHP-CGI is a process you must keep alive:

  • run it under WinSW/NSSM or a scheduled task with restart;
  • set PHP_FCGI_MAX_REQUESTS (e.g. 500) so workers recycle;
  • log stderr/stdout somewhere outside the web root;
  • monitor the listener (Test-NetConnection 127.0.0.1 9000);
  • do not start a second listener on 9000.

For a Windows-only server, IIS FastCGI usually supervises PHP better than a hand-wrapped php-cgi; use Nginx+PHP when you already standardize on Nginx or need its config model.

Terminal window
& C:\PHP\8.4\php-cgi.exe -v
Test-NetConnection 127.0.0.1 -Port 9000
Set-Content C:\sites\php\info.php '<?php phpinfo();' -Encoding ASCII
curl.exe -I -H "Host: php.local" http://127.0.0.1:8084/info.php

Remove info.php after the test.

E1 for Nginx+PHP. The lab installed PHP 8.4.27 and verified IIS FastCGI, but did not run php-cgi behind Nginx. The Nginx config is the next verification step, not a reproduced claim.

Sources