Quick Guide: Setting up PHP 7.1, NGINX 1.10 & MySQL 5.7 with Docker

After using Vagrant for the past few years and Docker gaining more adoption every day, I decided to give it a go as well. In this post I'll guide you through the installation process and how to configure it and use it with docker-compose.

There's also a TL;DR with just a download link if you don't care how it works but just want to get started ☺️!

What is Docker 🐳?

I'm not going to explain it myself, but I'll just pick a quote straight from the Docker website. It's pretty clear and describes everything that Docker does.

Docker containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – anything you can install on a server. This guarantees that it will always run the same, regardless of the environment it is running in.

Why use Docker over Vagrant, or even a local dev environment?

Local dev environments are just always a mess. People always have throuble configuring it, lots of issues with permissions, updates break it etc etc.

Than we have Vagrant which I have been using mostly for the past few years and runs on a virtual machine. That's a great thing and makes it easily possible to do compartmentalization and share entire stacks using this config file or even the whole image.

And than there is Docker. Which offers us a great deal of benefits over classic virtualization. Docker containers are substantially smaller than its equivalent VM. Speed is also an important consideration, using VMs there is a certain loss, while containers arguably have none -- excluding the small overhead for the Docker service. And it's very easy to configure using repositories from the community and with Docker Compose.

Of course there's also downsides and VMs do have some benefits over Docker containers, but I'm not going to go any deeper on that in this topic.

Requirements, what do we need?

Docker Engine

First of all, we need to install Docker itself by installing Docker Engine. You can download Docker Engine for macOS from here or for Windows here.

Docker Compose

After installing Docker Engine, we'll install Docker Compose. We will use this to define multiple services on multiple containers for our application. This makes it easy to start and stop the whole application with a single command.

Run the following command to install Docker Compose with curl (more in dept installation).

curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

And now make it executable using this command.

chmod +x /usr/local/bin/docker-compose

That's it, we're ready to configure the application!

Configuration

./docker-compose.yml

This is the main configuration file where we specify all the services we want to use and some configuration values for them such as the MySQL user & password and the location of your projects folder. In this case I'm using ~/Projects folder (this folder is located on your machine) as the location for the application. MySQL is configured with docker as value for the username, password as well as the database name.

An important thing to notice is that the first level within services is the also the name of the service to access it within the Docker application itself. Meaning if you want to access the database for example, you'll need to use mysql as hostname. You can make each service depending on another one and link services with each other if you need to access them or they're depending on them.

The ports for both MySQL and NGINX are exposed to our localhost, meaning we can access them via 127.0.0.1 or localhost. So you should be able to go to http://localhost/ in the browser and access the database using Sequel Pro or something simlar from 127.0.0.1:3306.

In the configuration below we're using MySQL 5.7, NGINX 1.10 (both from image) and PHP-FPM we're building ourselves using ./php/Dockerfile which we will get to in a minute.

version: '2'

services:
    mysql:
        image: mysql:5.7
        ports:
            - 3306:3306
        volumes:
            - /var/lib/mysql
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: docker
            MYSQL_PASSWORD: docker
            MYSQL_DATABASE: docker

    nginx:
        image: nginx:1.10.2
        ports:
            - 80:80
        restart: always
        volumes:
            - ./nginx/conf:/etc/nginx/conf.d
            - ~/Projects:/code
        links:
            - php
        depends_on:
            - php

    php:
        build: php
        expose:
            - 9000
        restart: always
        volumes:
            - ./php/conf/php.ini:/usr/local/etc/php/conf.d/custom.ini
            - ~/Projects:/code
        links:
            - mysql

./php/Dockerfile

This file we'll use build PHP manually instead of downloading a pre-defined image. Using this file we can customize our needs better and install a few extensions such as Curl, GD & Intl.

FROM php:7.1-fpm

RUN apt-get update

# Some basic extensions
RUN docker-php-ext-install -j$(nproc) json mbstring opcache pdo pdo_mysql mysqli

# Curl
RUN apt-get install -y libcurl4-openssl-dev
RUN docker-php-ext-install -j$(nproc) curl

# GD
RUN apt-get install -y libpng-dev libjpeg-dev
RUN docker-php-ext-install -j$(nproc) gd

# Intl
RUN apt-get install -y libicu-dev
RUN docker-php-ext-install -j$(nproc) intl

./php/conf/php.ini

Don't think this needs any explanation, just basic configuration of php.

display_errors = On
display_startup_errors = On
default_charset = "UTF-8"
html_errors = On

./nginx/conf/default.conf

And lastly our nginx default config. Just contains some basic stuff like autoindex, support for php and the hostname.

server {
    listen       80 default_server;
    server_name  localhost _;
    index        index.php index.html index.htm;
    root         /code;

    location / {
        try_files   $uri $uri/ /index.php?$query_string;
        autoindex on;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Testing application

If you have followed this guide completely you should now have a similar directory structure. If not, you can also download it from my repo on Github.

.                            # Docker directory
├─ nginx                     # NGINX directory
├─── conf                    # NGINX config directory
├───── default.conf          # Basic NGINX configuration
├─ php                       # PHP directory
├─── conf                    # PHP config directory
├───── php.ini               # Basic php configuration
├─── Dockerfile              # PHP Dockerfile
├─ docker-compose.yml        # Docker Compose file

You can start up your Docker application using the command docker-compose up. And normally, if everything went well, you should be able to go to http://localhost/, use PHP and connect to MySQL on port 3306.

TL;DR

For the people that didn't bother to read or just don't care how it works or configure it and just want to get started, don't worry! I've made it very easy for you. You can clone or download my repo and start it using docker-compose up.

Cheers! 🍻