How to compile the php plugin for pip installed uwsgi (on ubuntu server 14.04 LTS)

I am not a ubuntu server professional, I do not know if the following represent current best practice or results in a system that is insecure or misconfigured in other ways. I simply report what worked for me. With that out of the way…

TLDR:

sudo apt-get -y --no-upgrade install libphp5-embed libonig-dev libqdbm-dev libxml2-dev libdb-dev libbz2-dev libpcre3-dev libkrb5-dev

cd /tmp/
wget https://github.com/unbit/uwsgi/archive/$(uwsgi --version).tar.gz
tar -xvzf $(uwsgi --version).tar.gz
uwsgi --build-plugin /tmp/uwsgi-$(uwsgi --version)/plugins/php
sudo mkdir -p /usr/local/lib/uwsgi-$(uwsgi --version)/plugins/
sudp mv php_plugin.so /usr/local/lib/uwsgi-$(uwsgi --version)/plugins/

Having installed uwsgi from pip as described elsewhere on the net, I needed to find a way to run a php site as well. I wanted to keep my setup lean and minimize the amount of processes running, so I decided run it via the php plugin for uwsgi.

Since the version of uwsgi that gets installed via pip, does not include the php plugin, it has to be added seperately. The good news is that the uwsgi binary has the ability to builds its own plugins, it just needs the code to do so. so that is our first step.

cd /tmp/
wget https://github.com/unbit/uwsgi/archive/$(uwsgi --version).tar.gz
tar -xvzf $(uwsgi --version).tar.gz

We do the work in the tmp folder so we do not clutter elsewhere. I found the link for the source download on the uwsgi page and uses wget to download it. Then it is extracted. The $(uwsgi –version) encantation means we run the uwsgi –version command, which prints something along the lines of 2.0.9 and that is the inserted in to the outer command. this ensures that if another version of uwsgi gets installed from pip then (hopefully) the right sourcecode is downloaded.

We are now ready to compile a plugin, and to test we can compile the simple cgi (common gateway interface) plugin by calling uwsgi –build-plugin and pointing it at a folder that contains a plugin:

uwsgi --build-plugin /tmp/uwsgi-$(uwsgi --version)/plugins/cgi

This produces a cgiplugin.so file in the current folder, so all is well.

If we try this for the php plugin, it will fail because it needs some headers that are not installed by default. For me, the way to handle these is to simply look at the errors and google the missing headers. In ubuntu these headers seems to be placed in the lib*-dev packages. The set that worked for me for php was:

sudo apt-get -y --no-upgrade install libphp5-embed libonig-dev libqdbm-dev libxml2-dev libdb-dev libbz2-dev libpcre3-dev libkrb5-dev

and the we can produce the compiled php plugin

uwsgi --build-plugin /tmp/uwsgi-$(uwsgi --version)/plugins/php

The next step is to figure out where to place this file. The plugin directory is configured in the uwsgi file for the site, so it doesn't really matter. I chose to to place the phpplugin.so file in usr/local/lib since that seems to be reasonable as far as I can figure out.

sudo mkdir -p /usr/local/lib/uwsgi-$(uwsgi --version)/plugins/
sudo mv php_plugin.so /usr/local/lib/uwsgi-$(uwsgi --version)/plugins/

Finally we are ready to run a php site. I have uwsgi hosted behind an nginx server so my configs looks as follow: nginxsite.conf, notice the uwsgimodifier1 parameter which tells uwsgi to load the php plugin (its a magic number from various examples)

  server {
    listen 8084;
    server_name localhost;

    access_log /var/log/nginx/phpinfo.access.log;
    error_log /var/log/nginx/phpinfo.error.log;

location ~ \.php$ {
                  include     uwsgi_params;
                  uwsgi_pass  unix://srv/www/phptest/conf/socket;
                  uwsgi_modifier1 14;   
        }                 
}

uwsgi.ini, notice that we set the plugin-dir and the plugin:

[uwsgi]
socket = /srv/www/phptest/conf/socket
plugin-dir = /usr/local/lib/uwsgi-2.0.9/plugins/
plugin = php
cheaper = 1
processes = 4
php-index = index.php

These two files get symplinked into the nginx avalable-sites and uwsgi vassal folders and then a simple phpinfo file is served.

<?php phpinfo(); ?>

In my testing it has to be <?php, simply putting <? did not work.