back home

Voila, PHP is served! – Adding an NGINX web server container

Written by Bunkers on February 28, 2017

We're one step away from something useful! If you've been following along since the start of the series, then thanks for bearing with me. Having these smaller posts with discrete steps is my strategy for making sure they actually get written, but it's probably pretty frustrating for the reader! Having said that, as a single post this series would be a ridiculous length so hopefully it makes reading and referencing more manageable. I'd love to know what you think so drop me a line with any thoughts.

Anyway, our next step is to add a web server container that acts as a proxy to our PHP container, forwarding any relevant requests. The inspiration for this setup is the WP Engine hosting we use and their Mercury environment for Vagrant. They use NGINX for their web server, so I'm going to do the same. You may want to stick with Apache, and that could simplify a couple of aspects, but apart from a different format of configuration file, there's not much you need to learn.

The only file we're changing in the NGINX container is the site.conf configuration file. The good news here is that we can use the official NGINX container, and mount our configuration file as a volume. Tying our containers to the WordPress/PHP environment makes it difficult to reuse them in other projects, so being able to use standard official containers is great.

Add the following to the docker-compose.yml file:

    image: nginx:latest
      - "80:80"
      - data
      - ./web/site.conf:/etc/nginx/conf.d/site.conf

This brings in the volumes from our data container, which map to the expected /var/www/html. We map the container's port 80 to port 80 on the host (the docker machine). Lastly it links the configuration file for the site to the appropriate place within the container. We haven't created that yet, so let's do that now.

Make another directory for our container called web alongside the others, percona, site and php. In there create a file called site.conf with the following contents:

server {
    index index.php index.html;
    server_name tutorial.bunkers;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

You may want to change your server name! A lot of people use something like .local or .dev as a dummy TLD, but I thought I'd go with .bunkers for my local sites. This configuration just sets up the server's file location, and tells it to forward requests for PHP files to our php container.

At this point we've got a couple of options for pointing our fake domain at this web server. The simplest is to probably add an entry in your /etc/hosts file. Remember to use sudo when starting your favourite text editor, so if you're using nano it would be:

sudo nano /etc/hosts

and add the line:


or whatever you chose for your server name. If you're creating more than one of these you may want to use a more convenient setup where all requests to our fake TLD get forwarded to our local IP address. To do this you can install dnsmasq which is a local DNS server. Instead of documenting that process here, I'll just refer you to one of the well written tutorials already out there. This one is for the Mac and uses Homebrew to install dnsmasq like we have for other tools in this setup.

Whichever method you choose, once you have the domain resolving correctly we're ready to bring up our environment with the familiar command:

docker-compose up -d

To check it's working create a simple test index.php in the wp-content directory. For example I use a call to phpinfo.


Now for the moment of truth. Point a web browser at http://tutorial.bunkers/wp-content/ (substituting your domain) and you should see the familiar PHP information rendered. If so, congratulations! We've got a working local PHP development environment running on a small cluster of Docker containers.

You could use this setup for any PHP development you wanted. You would likely want to tweak the data container as I'm mapping that to wp-content, which is specific to our WordPress setup. But this feels like a nice alternative to running lots of virtual machines. If you wanted you could create an alternative backup and restore process for the database which would mean we could use the default official image for Percona. With a Docker Hub account you could create and push the modified PHP image. This would mean that each instance of this environment would only need a modified site image and the associated configuration files. In the future I'll create a process to generate these, which is probably a job for something like Ansible or Yeoman.

What's left is to setup our site image to install WordPress if it's not found when the container runs, as well as setup the wp-config.php file. All this magic happens in the file and we'll start taking a look at that next time. Until then!