Docker Lab – Containerising your website, Part 2 (PHP)

In the previous instalment (Docker Lab – Containerising your website, Part 1), we installed Docker and Docker Compose, and set up an Nginx container. If all you need is to serve a few static pages there’s no need to read any further. But if you need your website to be dynamic, if you need PHP and, perhaps, a database, read on…

These instructions assume that you have followed the steps in part 1.

It will come as no surprise that, in order to install PHP, we need to edit the docker-compose.yml file. But before we do that, it will be necessary to stop Docker (just in case you left it running from the last session). In fact, you can edit the docker-compose.yml file while Docker is still running – but the changes won’t take effect until Docker is restarted.

Check to see if Docker is running as follows:

docker ps

If any docker containers are running then you’ll see them listed like this:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 673b1e25c03a bitnami/nginx:latest "/app-entrypoint.s..." 3 hours ago Up 3 hours 0.0.0.0:80->8080/tcp, 0.0.0.0:443->8443/tcp lempcompose_nginx_1

If you haven’t started any Docker containers manually then you can stop the containers using Docker Compose.

Stopping using Docker Compose

When I stop jobs using Docker Compose, I always like to clean up as well. The containers will be rebuilt by Compose, so there isn’t a great deal of extra effort and it helps keep the cruft under control.

cd ~/lemp-compose
docker-compose stop
docker-compose rm

Stopping Manually

If you have started any containers manually then you’ll need to stop them by using the docker command and the container ID.

docker stop <containerId>

This step will need to be repeated for all containers which are running.

Configuring your Containers.

Now that your containers are stopped, the docker-compose.yml file will need to be edited to add a PHP container. Add a networks section to the top of your docker-compose.yml, beneath the version number and before services:

networks:
 app-tier:
  driver: bridge

Now add a section for PHP. Note that you’ll need a different PHP section for each vhost that you want to use PHP. You can’t (easily) host multiple websites with a single PHP instance. Because each vhost will have its own PHP instance I like to add the website name to the name of the PHP container that it will use.

phpfpm-<your website name>:
 image: 'bitnami/php-fpm:latest'
 networks:
   - app-tier
 volumes:
   - ./public/<your website name>/htdocs:/app
   - ./logs/<your website name>-php:/opt/bitnami/php/log

Finally, add the network and dependency to your nginx container configuration, under the image name and before the ports.

depends_on:
  - phpfpm-<your website name>
networks:
  - app-tier

Having made these changes, your docker-compose.yml should look like this:

version: '2'

networks:
 app-tier:
  driver: bridge

services:
 nginx:
  image: 'bitnami/nginx:latest'
  depends_on:
   - phpfpm-<your website name>
  networks:
   - app-tier
  ports:
   - '80:8080'
   - '443:8443'
  volumes:
   - ./nginx/nginx.conf:/bitnami/nginx/conf/nginx.conf
   - ./nginx/fastcgi.conf:/bitnami/nginx/conf/fastcgi.conf
   - ./logs:/opt/bitnami/nginx/logs
   - ./nginx/vhosts:/bitnami/nginx/conf/vhosts
   - ./public:/opt/bitnami/nginx/html
 phpfpm-<your website name>:
  image: 'bitnami/php-fpm:latest'
  networks:
   - app-tier
  volumes:
   - ./public/<your website name>/htdocs:/app
   - ./logs/<your website name>-php:/opt/bitnami/php/log

Website configuration

So far so good – it still won’t work though – we need to make changes to the vhost configuration. The reason that it won’t work is that we haven’t set up PHP in the vhost configuration, and it will also be necessary to modify the root information so that all resources (php, html, image files etc) can be accessed correctly.

nano ~/nginx/vhosts/sites-available/<your website name>.conf

Edit it as follows, replacing the server_name domain name with the domain name(s) of your website.

server {
 listen 0.0.0.0:8080;
 server_name <your domain name>;
 server_tokens off;
 
 error_log "/opt/bitnami/nginx/logs/<your website name>-error.log";
 access_log "/opt/bitnami/nginx/logs/<your website name>-access.log";

 location / {
  try_files $uri $uri/index.php;
 }

 location ~ \.php$ {
  # fastcgi_pass [PHP_FPM_LINK_NAME]:9000;
  fastcgi_pass phpfpm-<your website name>:9000;
  fastcgi_index index.php;
  include fastcgi.conf;
  root /app;
 }

 location ~ \.htm$ {
  root /opt/bitnami/nginx/html/<your website name>/htdocs;
 }
 
 location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
  expires max;
  log_not_found off;
  root /opt/bitnami/nginx/html/<your website name>/htdocs;
 }
}

If you’ve pulled all of that off correctly, you should be able to put info.php into ~/lemp-compose/public/<your website name>/htdocs and start Docker:

cd ~/lemp-compose 
docker-compose up --remove-orphans -d

Enter your website URL into your browser and (fingers crossed) access your info.php which will, hopefully, be displayed correctly, served up by your containerised instance of Nginx and PHP. Go and have a well earned cup of tea before moving onto the next stage – setting up your database.

info.php

If you’ve never created an info.php file before it’s quite simple. It contains the following and nothing else:

<?php
phpinfo();
?>

If it displays information about your PHP instance then PHP is installed correctly. If nothing is displayed, or if you are greeted with the dreaded ‘File Not Found’ then go back and check your steps carefully.

Once you have confirmed that PHP is installed correctly be sure to delete your info.php file – it’s a hackers goldmine and may reveal passwords and other information that make your website trivially easy to compromise.

Leave a Reply

Your email address will not be published. Required fields are marked *