First thing, I recommend keeping all your typical FCGI settings in a single file and importing them.
For example you might have an /etc/nginx/fastcgi.conf
(or /etc/nginx/fastcgi_params
that's installed by default on debian) file that looks like this:
#fastcgi.conf
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
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_FILENAME $document_root$fastcgi_script_name;
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 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;
This allows you to keep your individual FCGI configurations as simple as possible.
You may also want to replace $document_root
in SCRIPT_FILENAME
and DOCUMENT_ROOT
with an actual path, the $document_root
variable is hardcoded and may not reflect your install (will cause variations on 'script not found' errors, usually).
To use NGINX + Virtual Host + PHP you should ommit the SCRIPT_NAME
variable in order for PHP to choose the correct DOCUMENT_ROOT
.
Unlike Apache or Lighttpd, NGINX does not automatically spawn FCGI processes.
You must start them separately.
In fact, FCGI is a lot like proxying.
There's a few ways to start FCGI programs, but luckily PHP5 will auto-spawn as many as you set in the PHP_FCGI_CHILDREN
environment variable.
So we simply run php -b 127.0.0.1:9000
manually, or create an init script like so:
#!/bin/bash
BIND=127.0.0.1:9000
USER=www-data
PHP_FCGI_CHILDREN=15
PHP_FCGI_MAX_REQUESTS=1000
PHP_CGI=/usr/bin/php-cgi
PHP_CGI_NAME=`basename $PHP_CGI`
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
RETVAL=0
start() {
echo -n "Starting PHP FastCGI: "
start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
RETVAL=$?
echo "$PHP_CGI_NAME."
}
stop() {
echo -n "Stopping PHP FastCGI: "
killall -q -w -u $USER $PHP_CGI
RETVAL=$?
echo "$PHP_CGI_NAME."
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: php-fastcgi {start|stop|restart}"
exit 1
;;
esac
exit $RETVAL
Save this to /etc/init.d/
(or wherever your init scripts are) as php-fcgi
Install the usual way (for this debian init script, it's update-rc.d
php-fcgi
defaults) and start it.
Now that the FCGI process is running, we must tell NGINX to proxy requests to it via the FCGI protocol:
location ~ \.php$ {
include /etc/nginx/fcgi_params; #or whatever you named it
fastcgi_pass 127.0.0.1:9000;
}
Restart NGINX.
Too many example configs fail to secure the "uploads" directory of the application.
Remember that if someone can upload a file named xyz.php
and the uploads dir is publically accessible then you have given the attacker an easy way to insert PHP onto your site...
So if your app has an upload dir "/images/"
then insert if ($uri !~ "^/images/")
before fastcgi_pass
, as so:
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
if ($uri !~ "^/images/") {
fastcgi_pass 127.0.0.1:9000;
}
}