Nginx FastCGI
Unlike other web servers, nginx(8) does not offer a built-in FastCGI implementation.
PHP-FPM
First install and configure PHP-FPM.
nginx(8) just needs to be configured to proxy requests.
location ~ \.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; try_files $uri =404; fastcgi_pass localhost:9000; include fastcgi_params; }
To use a Unix socket to pass requests, try fastcgi_pass unix:/run/php-fpm/php-fpm.sock;.
Fastcgi_params
Here is a generic fastcgi_params file, which would work for the above example.
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
That final line has to do with crafted URLs. It is desirable in this context.
Hardening
HTTPoxy
To mitigate the HTTPoxy vulnerability, adjust the fastcgi_params file.
fastcgi_param HTTP_PROXY "";
Isolation
A common tactic for hardening a FastCGI program is to run php-fpm(8) in a different working directory.
This can lead to issues with the try_files directive, which checks for the existence of a file before responding to a request. On success it overwrites the $uri variable with the local URI. This is a mitigation for embedded PHP attacks.
A workaround is to create empty files in the web root to satisfy try_files.
location ~ \.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param SCRIPT_FILENAME /path/to/php/working/directory/$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; try_files $uri =404; fastcgi_pass localhost:9000; include fastcgi_params; }
Alternatively, replace try_files with a custom instruction.
location ~ \.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; if (!-f $document_root$fastcgi_script_name) { return 404; } }
Fcgiwrap
fcgiwrap(8) is a simple wrapper script that simplifies the configuration and administration of a FastCGI server. See here for help in configuring that server.
nginx(8) just needs to be configured to proxy requests.
location ~ \.php(/|$) { fastcgi_param DOCUMENT_ROOT /var/www/cgi-bin/; fastcgi_param SCRIPT_NAME myapp.php; fastcgi_pass unix:/run/fcgiwrap.sock; include fcgiwrap_params; }
See here for some details on the configuration.
Spawn-fcgi
spawn-fcgi(1) is a wrapper around the fcgiwrap(8) wrapper script. It comes from the Lighttpd project.
No configuration is necessary, just run the script like:
spawn-fcgi -n -u www-data -p 9000 -- /usr/bin/fcgiwrap -f
Or create a service file to automate this.
Use the same nginx(8) configuration as above.