Skip to main content

WordPress with Docker

We are going to create a MariaDB container and two WordPress containers (for the domains wp3.user1.fs.al and wp4.user1.fs.al). And because the WP containers need to communicate with the DB container, we will also create a docker (virtual) network, where all the three containers will be connected.

We are going to use the existing nginx as a reverse proxy for these two sites. Ideally, we should also containerize the reverse proxy, but let's keep it simple for the time being.

1. Create a network

docker network ls
docker network create wpnet
docker network ls
docker network inspect wpnet | less

2. Create a MariaDB container

  1. We can download and use the official mariadb image:

    docker search mariadb | less
    docker pull mariadb
    docker image ls
    docker image history mariadb | less

    It is official because it is maintained by the MariaDB foundation.

  2. Let's create a directory for this container:

    mkdir -p /var/docker/db1
    cd /var/docker/db1
  3. Create a container:

    cat <<'_EOF_' > create.sh
    #!/bin/bash -x

    mkdir -p data
    docker create \
    --name db1 \
    --hostname mariadb \
    --network wpnet \
    --network-alias mariadb1 \
    --mount type=bind,source=$(pwd)/data,destination=/var/lib/mysql \
    --restart unless-stopped \
    --env MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 \
    mariadb:latest
    _EOF_
    nano create.sh
    chmod +x create.sh
    ./create.sh
    docker ps -a
  4. Start and test the container:

    docker start db1
    docker ps
    docker logs db1 -f
    ls data/

    docker exec -it db1 mariadb
    show databases;
    exit

3. Install WP3

  1. Let's create a directory for it:

    mkdir -p /var/docker/wp3
    cd /var/docker/wp3/
  2. Create also a MariaDB database and user:

    docker exec -it db1 mariadb

    CREATE DATABASE wp3db;
    show databases;

    CREATE USER 'wp3user'@'%' IDENTIFIED BY 'wp3pass';
    select user, host from mysql.user;

    GRANT ALL ON wp3db.* TO 'wp3user'@'%';
    show grants for 'wp3user'@'%';

    FLUSH PRIVILEGES;
    exit;
  3. We can download and use the official wordpress image:

    docker search wordpress | less
    docker pull wordpress
    docker image ls
    docker image history wordpress | less

    This image includes Apache2, PHP and the WP application files.

  4. Create a container:

    cat <<'_EOF_' > create.sh
    #!/bin/bash -x

    mkdir -p www
    docker create \
    --name wp3 \
    --hostname wp3 \
    --network wpnet \
    --publish 127.0.0.1:8083:80 \
    --mount type=bind,source=$(pwd)/www,destination=/var/www/html \
    --env WORDPRESS_DB_HOST=mariadb1 \
    --env WORDPRESS_DB_NAME=wp3db \
    --env WORDPRESS_DB_USER=wp3user \
    --env WORDPRESS_DB_PASSWORD=wp3pass \
    --restart unless-stopped \
    wordpress:latest
    _EOF_
    nano create.sh
    chmod +x create.sh
    ./create.sh
    docker ps -a
  5. Start it:

    docker start wp3
    docker logs wp3 -f
    ls
    ls www/
    nano www/wp-config.php

    Test it with w3m:

    apt list w3m
    apt install w3m
    w3m http://127.0.0.1:8083 # use 'q' to exit
  6. Create a new site on the reverse proxy:

    cd /etc/nginx/sites-available/
    cp wp2 wp3
    sed -i wp3 -e 's/wp2/wp3/g'
    nano wp3

    Edit wp3 and make sure that the proxy_pass line looks like this:

    proxy_pass http://127.0.0.1:8083;

    Enable this site:

    cd ../sites-enabled/
    ln -s ../sites-available/wp3 .

    nginx -t
  7. Get an SSL cert for the new site:

    certbot certonly \
    --webroot -w /var/www \
    -d wp3.user1.fs.al,www.wp3.user1.fs.al \
    --dry-run
    certbot certonly \
    --webroot -w /var/www \
    -d wp3.user1.fs.al,www.wp3.user1.fs.al \
    -m dashohoxha@gmail.com \
    --agree-tos
    certbot certificates

    Reload nginx:

    nginx -t
    systemctl reload nginx
  8. Open in browser https://wp3.user1.fs.al and complete the installation wizard.

4. Install WP4

  1. Create a directory for it:

    mkdir -p /var/docker/wp4
    cd /var/docker/wp4/
  2. Create a MariaDB database and user:

    cat <<'_EOF_' > db-init.sh
    #!/bin/bash -x

    DBNAME="wp4db"
    DBUSER="wp4user"
    DBPASS="wp4pass"

    DBCONTAINER="db1"
    mariadb="docker exec -i $DBCONTAINER mariadb"

    cat <<EOF | tee /dev/tty | $mariadb
    create database $DBNAME;
    create user '$DBUSER'@'%' identified by '$DBPASS';
    grant all on $DBNAME.* to '$DBUSER'@'%';
    flush privileges;
    EOF

    _EOF_
    nano db-init.sh
    chmod +x db-init.sh
    ./db-init.sh
    echo 'show databases;' \
    | docker exec -i db1 mariadb
  3. Create a WP container:

    cat <<'_EOF_' > create.sh
    #!/bin/bash -x

    DBHOST='mariadb1'
    DBNAME='wp4db'
    DBUSER='wp4user'
    DBPASS='wp4pass'

    mkdir -p www
    docker create \
    --name wp4 \
    --hostname wp4 \
    --network wpnet \
    --publish 127.0.0.1:8084:80 \
    --mount type=bind,source=$(pwd)/www,destination=/var/www/html \
    --env WORDPRESS_DB_HOST=$DBHOST \
    --env WORDPRESS_DB_NAME=$DBNAME \
    --env WORDPRESS_DB_USER=$DBUSER \
    --env WORDPRESS_DB_PASSWORD="$DBPASS" \
    --restart unless-stopped \
    wordpress:latest
    _EOF_
    nano create.sh
    chmod +x create.sh
    ./create.sh
    docker ps -a
  4. Start it:

    docker start wp4
    docker logs wp4 -f
    ls www/
    ls -al www/

    w3m http://127.0.0.1:8084
  5. Create a new nginx site:

    cd /etc/nginx/sites-available/
    cp wp3 wp4
    sed -i wp4 -e 's/wp3/wp4/g' -e 's/8083/8084/'
    nano wp4

    cd ../sites-enabled/
    ln -s ../sites-available/wp4 .

    nginx -t
  6. Get an SSL cert and reload nginx:

    domain=wp4.user1.fs.al
    email=dashohoxha@gmail.com

    certbot certonly --webroot -w /var/www \
    -d $domain,www.$domain --dry-run

    certbot certonly --webroot -w /var/www \
    -d $domain,www.$domain -m $email --agree-tos

    certbot certificates
    nginx -t
    systemctl reload nginx
  7. Open in browser https://wp4.user1.fs.al and complete the installation wizard.

5. Maintenance

Logs:

docker logs db1 -f
docker logs wp4 -f

5.1 wp-cli

The tool wp-cli is crucial for the mantenance of a WP site. Let's make a script that runs it:

cat <<'_EOF_' > /var/docker/wp4/wp-cli.sh
#!/bin/bash

DBHOST='mariadb1'
DBNAME='wp4db'
DBUSER='wp4user'
DBPASS='wp4pass'

docker run -it --rm \
--user 33:33 \
--volumes-from wp4 \
--network container:wp4 \
--env WORDPRESS_DB_HOST=$DBHOST \
--env WORDPRESS_DB_NAME=$DBNAME \
--env WORDPRESS_DB_USER=$DBUSER \
--env WORDPRESS_DB_PASSWORD="$DBPASS" \
--env HOME=/tmp \
wordpress:cli "$@"
_EOF_
cd /var/docker/wp4/
chmod +x wp-cli.sh
./wp-cli.sh --help
./wp-cli.sh user list

5.2 Backup

  1. Let's create a backup script:

    cat <<'_EOF_' > ~/wp4-backup.sh
    #!/bin/bash -x

    systemctl stop nginx

    cd /var/docker/wp4/
    ./wp-cli.sh db export db.sql
    cd ..
    tar cfz wp4-$(date +%Y%m%d).tgz wp4/
    mv *.tgz ~/

    systemctl start nginx
    _EOF_
  2. Test it:

    nano ~/wp4-backup.sh
    chmod +x ~/wp4-backup.sh
    ~/wp4-backup.sh
    ls -lh ~/
    tar tvfz ~/wp4-20250210.tgz | less

5.3 Restore

  1. Uninstall WP4:

    cat <<'_EOF_' > ~/wp4-remove.sh
    #!/bin/bash -x

    docker stop wp4
    docker rm wp4
    rm -rf /var/docker/wp4/

    DBNAME="wp4db"
    DBUSER="wp4user"
    DBPASS="wp4pass"

    DBCONTAINER="db1"
    mariadb="docker exec -i $DBCONTAINER mariadb"
    cat <<EOF | tee /dev/tty | $mariadb
    revoke all privileges, grant option from '$DBUSER'@'%';
    drop user '$DBUSER'@'%';
    drop database $DBNAME;
    EOF
    _EOF_
    nano ~/wp4-remove.sh
    chmod +x ~/wp4-remove.sh
    ~/wp4-remove.sh
  2. Restore from the backup:

    cd /var/docker/
    tar xfz ~/wp4-*.tgz
    ls
    cd wp4/

    ls
    ./db-init.sh
    ./create.sh
    docker ps -a
    docker start wp4
    # open https://wp4.user1.fs.al in browser and finish the installation

    # import the DB backup
    ls www/
    ls -lh www/db.sql
    ./wp-cli.sh db import db.sql

5.4 Update

  1. Update WP files:

    systemctl stop nginx

    # Update WordPress core
    ./wp-cli.sh core version
    ./wp-cli.sh core update
    ./wp-cli.sh core update-db

    # Update all plugins
    ./wp-cli.sh plugin update --all

    # Update all themes
    ./wp-cli.sh theme update --all

    # Clear cache
    ./wp-cli.sh cache flush

    systemctl start nginx
  2. Update docker image:

    docker pull wordpress:latest
    docker image ls

    docker stop wp4
    docker rm wp4

    cd /var/docker/wp4/
    ./create.sh
    docker start wp4

    This is the equivalent of apt update && apt upgrade for docker containers.

    We destroy and recreate the container, however the DB and the WP files will be the same as before, because they are outside the container.