Skip to main content

WP with Compose

We have already installed docker compose:

docker compose version
docker compose --help | less

1. Install a WP site

1.1 Create a project

  1. Create a directory:

    mkdir -p /var/compose/wordpress
    cd /var/compose/wordpress/
  2. Create the config file compose.yml:

    cat << '_EOF_' > compose.yml
    services:
    db:
    image: mariadb
    restart: unless-stopped
    environment:
    MARIADB_DATABASE: wp5db
    MARIADB_USER: wp5user
    MARIADB_PASSWORD: wp5pass
    MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: '1'
    volumes:
    - ./db:/var/lib/mysql
    wp5:
    image: wordpress
    restart: unless-stopped
    ports:
    - 127.0.0.1:8086:80
    environment:
    WORDPRESS_DB_HOST: db
    WORDPRESS_DB_NAME: wp5db
    WORDPRESS_DB_USER: wp5user
    WORDPRESS_DB_PASSWORD: wp5pass
    volumes:
    - ./www:/var/www/html
    _EOF_

    It is similar to the docker create commands that we have used previously.

    nano compose.yml
    nano /var/docker/db1/create.sh
    nano /var/docker/wp3/create.sh
  3. Start the services and look around:

    docker compose up -d
    ls
    ls db/
    ls www/

    docker network ls
    docker network inspect wordpress_default | less

    docker compose ls
    docker compose ps -a
    docker compose logs db -f
    docker compose logs wp5 -f
    docker compose exec db bash
    docker compose exec db mariadb
    docker compose exec wp5 bash

    docker compose --help | less

1.2 Setup reverse proxy

  1. Create a site configuration on nginx:

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

    Make sure to use the correct port on proxy_pass:

    proxy_pass http://127.0.0.1:8086;
  2. Enable it:

    cd ../sites-enabled/
    ls ../sites-available/wp5
    ln -s ../sites-available/wp5 .
    ls -l
  3. Get an SSL certificate:

    domain=wp5.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
  4. Reload nginx:

    nginx -t
    systemctl reload nginx

1.3 Installation wizard

Open in browser https://wp5.user1.fs.al and complete the installation wizard.

1.4 Use an env file

Let's use an environment file for the settings:

  1. Stop the containers and destroy them:

    docker compose down

    It will remove the network as well, but not the data volumes/directories.

  2. Create the file db.env:

    cat << '_EOF_' > db.env
    DBNAME=wp5db
    DBUSER=wp5user
    DBPASS=wp5pass
    _EOF_
  3. Modify compose.yml by adding env_file: db.env to each service, and by using the DB env variables:

    services:
    db:
    image: mariadb
    restart: unless-stopped
    env_file: db.env
    environment:
    MARIADB_DATABASE: ${DBNAME:-wp5db}
    MARIADB_USER: ${DBUSER:-wp5user}
    MARIADB_PASSWORD: ${DBPASS:-wp5pass}
    MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: '1'
    volumes:
    - ./db:/var/lib/mysql

    wp5:
    image: wordpress
    restart: unless-stopped
    ports:
    - 127.0.0.1:8086:80
    env_file: db.env
    environment:
    WORDPRESS_DB_HOST: db
    WORDPRESS_DB_NAME: ${DBNAME:-wp5db}
    WORDPRESS_DB_USER: ${DBUSER:-wp5user}
    WORDPRESS_DB_PASSWORD: ${DBPASS:-wp5pass}
    volumes:
    - ./www:/var/www/html
    depends_on:
    - db
  4. Run the containers:

    docker compose up -d

    Check also https://wp5.user1.fs.al in browser.

1.5 Use custom names

  1. The default name of the project is the name of the directory where the configuration file is located. It can be specified using the option -p on the command docker compose, or using the field name: on the configuration file:

    docker compose ls
    docker compose ps
    docker network ls

    docker compose down

    sed -i compose.yml -e '1i name: wp'
    head compose.yml

    docker compose up -d

    docker compose ls
    docker compose ps
    docker network ls
  2. To set the name of the default network we can add something like this:

    networks:
    default:
    name: wp-net
    docker compose down

    cat << _EOF_ >> compose.yml

    networks:
    default:
    name: wp-net
    _EOF_

    tail compose.yml
    nano compose.yml

    docker compose up -d

    docker network ls
  3. To set the name of a container we can use the field container_name: like this

    name: wp
    services:
    db:
    image: mariadb
    container_name: mariadb1
    # . . . . . . . . . .
    wp5:
    image: wordpress
    container_name: wp5
    # . . . . . . . . . .
    docker compose down
    nano compose.yml
    docker compose up -d
    docker compose ps

1.6 Build custom image

The default WP image that we are using, wordpress:latest, does not have the tool wp-cli installed inside it. We want to build and use a custom image that has wp-cli installed as well.

  1. Let's start by creating this Dockerfile:

    cat << '_EOF_' > Dockerfile
    # syntax=docker/dockerfile:1.4

    FROM wordpress:latest

    RUN <<EOF
    apt update
    apt upgrade --yes

    # install less and mariadb-client
    apt install --yes less mariadb-client

    # install wp-cli
    curl -s -o /usr/local/bin/wp \
    https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    chmod +x /usr/local/bin/wp
    EOF
    _EOF_
    nano Dockerfile
  2. Stop and remove the current project:

    docker compose down
  3. Add the field build: . to compose.yml, like this:

      wp5:
    build: .
    image: wordpress:local
    container_name: wp5

    In this case, build: shows the directory where the Dockerfile is located (. is the current directory).

  4. Build and start the project:

    docker compose up -d

    Notice that it will build first the image wordpress:local because it is not available.

    docker image ls
    docker compose ps
  5. Let's try wp-cli:

    docker compose exec -u www-data wp5 wp
    docker compose exec -u www-data wp5 wp user list

    Create an alias:

    alias wp5cli='docker compose exec -u www-data wp5 wp'
    alias
    wp5cli user list

    Add this alias to ~/.bashrc_custom as well.

2. Install another WP site

We can create another compose project, another directory with another config file compose.yml, similar to the current one. In this case it will start another MariaDB container and another WP container.

But we can also install it on the same project, using the same MariaDB container. Let's try this approach because using a common MariaDB container is a bit more efficient than using separate ones, and because it is more didactic (we can learn more).

  1. First, let's rename the directory www to wp5 and the file db.env to wp5db.env:

    docker compose down

    mv www wp5
    mv db.env wp5db.env

    sed compose.yml -e 's#\./www:#./wp5:#' -e 's/db\.env/wp5db.env/'
    sed -i compose.yml -e 's#\./www#./wp5#' -e 's/db\.env/wp5db.env/'
    sed compose.yml -n -e '/volumes:/,+2 p' -e '/env_file:/ p'

    docker compose up -d
  2. Then create the file wp6db.env:

    cat << EOF > wp6db.env
    DBNAME=wp6db
    DBUSER=wp6user
    DBPASS=wp6pass
    EOF
    cat wp6db.env
  3. Create a new database and user on the container mariadb1:

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

    source wp6db.env

    DBCONTAINER="mariadb1"
    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 wp6db.sh
    chmod +x wp6db.sh
    ./wp6db.sh

    echo "show databases;" \
    | docker exec -i mariadb1 mariadb
  4. Add this service definition to compose.yml:

      wp6:
    build: .
    image: wordpress:local
    container_name: wp6
    restart: unless-stopped
    ports:
    - 127.0.0.1:8087:80
    env_file: wp6db.env
    environment:
    WORDPRESS_DB_HOST: db
    WORDPRESS_DB_NAME: ${DBNAME:-wp6db}
    WORDPRESS_DB_USER: ${DBUSER:-wp6user}
    WORDPRESS_DB_PASSWORD: ${DBPASS:-wp6pass}
    volumes:
    - ./wp6:/var/www/html
    docker compose down
    nano compose.yml
    docker compose up -d

    ls
    ls wp6/
    docker compose ps
  5. Create a reverse proxy site for it:

    cd /etc/nginx/sites-available/

    ls
    cp wp5 wp6
    sed -i wp6 -e 's/wp5/wp6/g' -e 's/8086/8087/'
    nano wp6

    cd ../sites-enabled/
    ls ../sites-available/wp6
    ln -s ../sites-available/wp6 .
    ls -l

    nginx -t
    certbot certonly --webroot -w /var/www/ \
    -d wp6.user1.fs.al,www.wp6.user1.fs.al \
    -m dashohoxha@gmail.com --agree-tos
    certbot certificates

    nginx -t
    systemctl reload nginx
  6. Open https://wp6.user1.fs.al in browser and finish the installation.

4. Maintenance

4.1 Backup

  1. Create a backup script:

    cat << '_EOF_' > ~/wp-backup.sh
    #!/bin/bash -x
    cd /var/compose/wordpress/

    docker compose down
    tar cfz ~/wp-$(date +%Y%m%d).tgz -C /var/compose/ wordpress/
    docker compose up -d
    _EOF_
  2. Make the backup:

    cd
    nano wp-backup.sh
    chmod +x wp-backup.sh
    ./wp-backup.sh
    ls -lh wp-*.tgz
    tar tvfz wp-20250210.tgz | less

4.2 Restore

  1. Remove WP:

    cd /var/compose/wordpress/
    docker compose down
    cd ..
    rm -rf wordpress/
    ls
  2. Restore from the backup:

    ls ~/wp-*.tgz
    tar xfz /root/wp-20250210.tgz -C /var/compose/
    ls /var/compose/
    cd /var/compose/wordpress/
    ls
    docker compose up -d

4.3 Backup DB

  1. Create a backup script:

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

    systemctl stop nginx

    wp5cli='docker compose exec -u www-data wp5 wp'
    $wp5cli db export db.sql

    wp6cli='docker compose exec -u www-data wp6 wp'
    $wp6cli db export db.sql

    systemctl start nginx
    _EOF_
  2. Make the backup:

    nano db-backup.sh
    chmod +x db-backup.sh
    db-backup.sh
    ls wp5/
    ls wp6/
    nano wp6/db.sql
note

Usually we need a backup of the database when we need to change the version of MariaDB container. If we upgrade it, usually it can be done autommatically. However if we need to downgrade, we may have to install a fresh DB and then restore the content of the DB from the backup.

4.4 Update

  1. Update apps:

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

    wp5cli='docker compose exec -u www-data wp5 wp'
    wp6cli='docker compose exec -u www-data wp6 wp'

    systemctl stop nginx

    $wp5cli core update
    $wp5cli core update-db
    $wp5cli plugin update --all
    $wp5cli theme update --all
    $wp5cli cache flush

    $wp6cli core update
    $wp6cli core update-db
    $wp6cli plugin update --all
    $wp6cli theme update --all
    $wp6cli cache flush

    systemctl start nginx
    _EOF_
    nano update.sh
    chmod +x update.sh
    ./update.sh
  2. Update docker images:

    docker pull mariadb
    docker pull wordpress
    cd /var/compose/wordpress/
    docker compose build
    docker compose up -d