Nginx by examples: php setup
Nginx configuration for PHP can be a little fiddly.
Let’s see how to make things work :)
When setting up PHP with Nginx we are effectively still using Nginx as a reverse proxy in front of a FastCGI server as the fastcgi_pass
directive is functionally equivalent to the proxy_pass
one.
There are plenty of blog posts and examples online that show how to setup PHP behind nginx but most of them don’t really explain why the suggested setup simply works :)
Let’s start with a simple configuration:
server {
root /var/www/mydomain.com/web/;
index index.php;
server_name mydomain.com;
access_log /var/www/mydomain.com/log/mydomain.com.access;
error_log /var/www/mydomain.com/log/mydomain.com.error error;
location / {
# we serve a file if it's there,
# otherwise we rewrite internally as a request to /index.php
try_files $uri /index.php?$args;
}
# regex matching: anything ending with .php
location ~ \.php$ {
# allows for requests to /test.php/article/0001
# to be handled by /test.php. At the same time
# it sets the $fastcgi_path_info env variable
# (that can be sent to php via the fastcgi interface)
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# defaults calls to /uri/ to /uri/index.php (optional)
fastcgi_index index.php;
# sets the standard fastcgi parameters (from another file)
include fastcgi_params;
# if the rewritten $uri doesn't really exist
# let's return 404 to the user
try_files $uri =404;
# let's pass the request to the fastcgi downstream
fastcgi_pass 127.0.0.1:9000;
}
}
Request resolution process
The main point here is to understand how the
location / {
try_files $uri /index.php?$args;
}
and the
location ~ \.php$ {
...
}
interact with each other
In the catch-all location / {}
block the tryfiles
directive matches any incoming request not ending with .php
If the request has:
- a URI matching an existing file causes the file to be served.
- a URI that doesn’t match any existing file causes an internal rewrite of the request which will go through another round of location block resolution process. The request is thus
- rewritten as
/index.php?$args
(last option in thetry_files
directive) - is now ending with
.php
- it now matches the php
location
block as Nginx gives precedence to location blocks with matching regular exceptions - is now served through the
fastcgi_pass
directive
Apache Mod Rewrite
- This setup is functionally equivalent to Apache Mod Rewrite only way less complex and allows for all modern PHP frameworks that require bootstrapping via an
index.php
single entry point to work seamlessly.