Friday, 6 November 2015

PHP: getting my dev environment running on Nginx instead of Apache

We're shifting from Apache to Nginx at work, and despite having other bods to look after that side of things - I'm just a developer, I avoid devops if I possibly can - I still need to write rewrites and the like, and so I need to be passably au fait with Nginx and how its rewrite system works.

So I decided to get a local site up and running via Nginx this morning. Well: I say "I decided to"... I needed to ;-)

As with anything I write about PHP and that sort of thing... I profess no expertise in how I throw things together, so I would not take these as model instructions or anything like that. I'm just documenting what I did.

Note: I'm running Windows.

Download and run

First up I downloaded Nginx from their site. It requires no installation: just unzip and run. Obviously however I need to configure the thing if I'm to do anything more than stare at gdayWorld.html on the screen.


Googling a bit, Nginx uses PHP's FastCGI module to run PHP, and one needs to configure NGinx to pass requests to PHP that way. This is all documented here: "PHP-FastCGI on Windows".

Basically I need to run php-cgi.exe, in the background, telling it to listen on a port:

C:\apps\php\5\5\php-cgi.exe -b

(I'm running PHP 5.5 cos that's what we use on our live site)

Note - and this is one thing that caught me out cos the docs weren't 100% explicit (and I didn't engage my brain) - that port is not the port that Nginx listens to for incoming HTTP requests, it's just a port for Nginx and PHP to communicate on. And - obviously for those who do engage their brains - it does actually need to be a different port. Sigh... that stupidity held me up for about 15min of head-scratching until I started to pay attention to what I was doing.

php-cgi.exe just sits there running.

Nginx config

Here's my Nginx config file. Basically I took out all the commented-out clutter, changed some stuff to suit my environment, and put some extra bits in (as suggested by that page I link to above):

worker_processes  1;

events {
    worker_connections  1024;

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       9550;
        server_name  php.silex.nginx.local;
        root D:/src/php/php.silex.nginx.local/public;
        autoindex on;

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;

        location ~ \.php$ {
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;


Note that I have directory listings switched on: this is convenient for me in dev, but you'd obviously not do that on live.

So Nginx is listening for requests on 9550, and it's talking to PHP via 8550 (and PHP is listening for it on 8550 too). These ports are arbitrary.


One other thing I did was make sure to read through a couple of the docs pages that the Nginx site was pretty emphatic about being "must reads":

I have to say I find the tone of the docs slightly patronising (I was reminded of the ColdBox docs as I read them... at least Nginx doesn't have the attempts at humour though), but the information was useful stuff (as is the info in the CB docs, I hasten to add... once one wades through all the bullshit).


I didn't do anything here, and it's irrelevant to Nginx, but I needed a Silex site running so I created a shell for testing purposes, and it all worked fine.


The last thing I did was to write a coupla batch files:

rem startNginxWithPhp55.bat
start C:\bin\RunHiddenConsole.exe C:\apps\php\5\5\php-cgi.exe -b
start nginx.exe

rem stopNginxWithPhp55.bat
nginx.exe -s stop
tskill php-cgi

RunHiddenConsole.exe (zip) does what it sounds like it does. It just prevents php-cgi.exe from starting in its own window (I'm running all this on my desktop machine, remember). I have no need to run this stuff as a service, so I did not look into that.


... that was really easy. Obviously this hardly even counts as scratching the surface, so it's not exactly the most earth-shattering blog article, but what perhaps is useful is seeing how easy it actually is. I was hesitant about how many bloody hoops I'd need to jump through to get things going, but it's all well documented, and there really ain't much to it. Now I need to get my brain around how the rewrites work.