Containerising PHP

Tips on containerising Moodle on a LAMP stack, with Docker multistage builds

We start by following this Semaphore CI guide
folding in:

Which container base image? #

Many guides suggest Alpine in all circumstances

In this guide, we'll go for:

Moodle requirements for 3.9 - PHP 7.2 is required. PHP 7.3 and 7.4 are supported. I'll therefore choose 7.4

Go to the Docker Hub page for official PHP images

By looking at the digests, we see that these three tags are all the same underlying image:

I'll choose php:7.4.9-apache-buster

Note it looks like for PHP 7.3, there was the option of stretch images (Debian 9) or buster(Debian 10), but as of PHP 7.4, this has moved to buster.

If we click through to the underlying image page we see the 32 commands which comprise the image history, ending in:

WORKDIR /var/www/html
CMD ["apache2-foreground"]

What's in our container?

Run this command to:

docker run -it -p 8000:80 --rm php:7.4.9-apache-buster

In your browser, go to http://localhost:8000 and you should see


You don't have permission to access this resource.

Apache/2.4.38 (Debian) Server at localhost Port 8000

And on the command line, you'll see

AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server'
s fully qualified domain name, using Set the 'ServerName' directive globally to suppress this message
[Fri Aug 28 20:40:58.698283 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.9 configured -- resuming normal operations
[Fri Aug 28 20:40:58.698362 2020] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND' - - [28/Aug/2020:20:41:10 +0000] "\x16\x03\x01\x02" 400 0 "-" "-"
[Fri Aug 28 20:41:14.282539 2020] [autoindex:error] [pid 19] [client] AH01276: Cannot serve directory /var/www/html/: No matching DirectoryIndex (index.php,index.html) found, and server-generated directory index forbidden by Options directive - - [28/Aug/2020:20:41:14 +0000] "GET / HTTP/1.1" 403 493 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"

Exit the command line with Ctrl + C, and you should see

^C[Fri Aug 28 20:41:27.288194 2020] [mpm_prefork:notice] [pid 1] AH00169: caught SIGTERM, shutting down

The --rm flag means that when the container stopped, it was deleted.

Now we want to create our first Dockerfile

Create a directory - mkdir docker-php
Initialise git - git init
Make a file Dockerfile

Look at Moodle's PHP dependencies

Reference #

MariaDB #


Work with Docker #

Alpine #

Existing images #

Work with full Ubuntu #

Docker Compose #

docker-compose up -d --force-recreate --no-deps --build nginx

Options description #

| -d | Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit |
| --force-recreate | Recreate containers even if their configuration and image haven't changed |
| --build | Build images before starting containers. |
| --no-deps | Don't start linked services. |

RUN curl --silent --show-error --fail --location \
--header "Accept: application/tar+gzip, application/x-gzip, application/octet-stream" -o - \
",http.realip&license=personal&telemetry=off" \
| tar --no-same-owner -C /usr/bin/ -xz caddy

Paul Redmond's book on LeanPub:

From Bret Fisher

From Nick Janetakis

Performance, S6:

Juan Treminio:

Other interesting #



Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated 💖! For feedback, please ping me on Twitter.