Digital Preservation with MySQL

In my previous post about using Docker and scripts to build static versions of your website, I used a very basic project that didn't use a database. A few of the projects I was restoring needed MySQL, so this post outlines the steps I took to make sure these websites worked correctly.

Updating the Dockerfile

Firstly, I needed to modify the Dockerfile, to install the required MySQL extensions.

FROM php:5.6-apache as project_name

RUN a2enmod rewrite

RUN apt-get update \
  && docker-php-ext-install pdo pdo_mysql mysql mysqli

COPY ./ /var/www/html/

EXPOSE 80

Adding the MySQL Container

The docker-compose.yaml has the biggest change. We need to add another service for MySQL and create a network so the two containers can talk to each other.

We can use the official MySQL image without the need for a specific Dockerfile. Instead of the build configuration, we specify the image, in this case, MySQL 5.7.

Next, we configure the local port which is mapped to the default 3306 internal MySQL port. If you want to connect to the database from your local machine, you should use this port, but internally, the containers will talk using the default port.

We can configure the local port and database credentials using an .env file.

When starting the MySQL container, it maps the storage engine to the .db directory in your project root. This means the database data is maintained between sessions and is not lost if you recreate the container. Secondly, it copies a database.sql file to the entry point initialise script – this runs the SQL file when building the container and is perfect to preload the database with the backup data you have.

version: "3.7"

services:
    website:
        build:
            context: .
            dockerfile: Dockerfile
        image: project_name:latest
        container_name: project_name
        ports:
            - '${FORWARD_APP_PORT:-8000}:80'
        volumes:
            - ./:/var/www/html
        networks:
            - project_name_network

    mysql:
        image: 'mysql:5.7'
        container_name: project_name_mysql
        ports:
            - '${FORWARD_DB_PORT:-3307}:3306'
        env_file:
            - ./.env
        environment:
            MYSQL_DATABASE: '${DB_DATABASE:-database}'
            MYSQL_USER: '${DB_USER:-username}'
            MYSQL_PASSWORD: '${DB_PASSWORD:-password}'
            MYSQL_ROOT_PASSWORD: ''
            MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
        command:
            - --default-authentication-plugin=mysql_native_password
            - --sql_mode=
        volumes:
            - ./.db:/var/lib/mysql
            - ./database.sql:/docker-entrypoint-initdb.d/init.sql
        healthcheck:
            test: ["CMD", "mysqladmin", "ping"]
        restart: 'unless-stopped'
        networks:
            - project_name_network

networks:
    project_name_network:
        driver: bridge

Note if you're using Apple Silicon computer then you may need to define the MySQL platform to use x86. You can do this by adding the following under the image setting.

image: 'mysql:5.7'
platform: linux/x86_64

You will need to configure your code with the correct MySQL credentials. This should use the internal name of the host, in the case above, it would be mysql.

define('DB_HOST', 'mysql');
define('DB_NAME', 'database');
define('DB_USER', 'username');
define('DB_PASSWORD', 'password');

Finally, the stop and remove helper scripts that I define in the package.json need the MySQL container added:

"stop": "docker stop project_name project_name_mysql",
"remove": "docker rm project_name project_name_mysql",

And that's it. Now you can use the build and deploy scripts to generate a static HTML version of your database-driven PHP website. This also works perfectly well for WordPress websites.