Dockerizing WordPress in a multi-container architecture

Overview

This document explains how to build a multi-container docker environment that presents a blank WordPress install to the local network.
The project will be given the random name Bilbo to make it obvious when an object is related to this example.
This document has additional features as well:

  • How to install WordPress to operate behind a reverse proxy (apache shown)
  • How to configure WordPress to get downloads through a corporate proxy
  • How to build a simple WordPress docker container with persistent storage

Building the environment

Docker Compose can be used to build multi-container architecture easily.

Assembling the files

Make a work directory.

mkdir ~/bilbo
cd ~/bilbo

docker-compose.yml

cat <<EOF > docker-compose.yml
version: '2'
services:
  db:
    image: mariadb:latest
    volumes:
      - "/var/bilbo/db:/var/lib/mysql"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpress
      MYSQL_DATABASE: bilbo
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  wpmod:
    depends_on:
      - db
    #image: wordpress:latest
    build:
      context: .
      dockerfile: Dockerfile
    links:
      - db
    ports:
      - "8000:80"
    restart: always
    volumes:
      - "/var/bilbo/www:/var/www/html"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_PASSWORD: wordpress
      http_proxy: http://proxy.example.com:8080/
      https_proxy: http://proxy.example.com:8080/
      WP_HOME: http://kim.example.com/bilbo
      WP_SITEURL: http://kim.example.com/bilbo
EOF

Observe that the proxy commands will allow WordPress to download updates if the docker host is authenticated to the corporate proxy.

Dockerfile

cat <<EOF > Dockerfile
FROM wordpress:latest
MAINTAINER bgstack15@gmail.com

COPY entrymod.sh /entrymod.sh
RUN chmod +x /entrymod.sh
CMD ["/entrymod.sh","apache2","-DFOREGROUND"]
EOF

Entrymod.sh

This script wraps around the normal docker wordpress image entrypoint.sh file. It waits for the wp-config file to exist and then updates it with the right information provided in the docker-compose file. Basically it dynamically hard-codes the wordpress base URLs.

cat <<'EOFENTRYMOD' > entrymod.sh
#!/bin/bash
# File: entrymod.sh
# Purpose: Adds a few key elements to wp-config.php
# History 2016-06-20 changed to make entrymod the entry point and it just points to entrypoint.sh at the end
# Reference: https://wordpress.org/support/topic/wordpress-behind-reverse-proxy-1

infile1=/var/www/html/wp-config.php
tmpfile1=/tmp/295816928f7597.tmp
tmpfile2=/tmp/295816928f7598.tmp
WP_BLOGDIR=$( echo "${WP_HOME}" | sed 's!https\?://[^/]*!!;' )

function dotask {

rm -rf ${tmpfile1} ${tmpfile2} >/dev/null 2>&1

{
   sed -n -e '1,/.*define.*DB_NAME.*/p;' ${infile1}
   echo "# BEGIN ADDITIONS"
   [[ -n "${WP_HOME}" ]] && echo "define('WP_HOME','${WP_HOME}');"
   [[ -n "${WP_SITEURL}" ]] && echo "define('WP_SITEURL','${WP_SITEURL}');"
   [[ -n "${WP_BLOGDIR}" ]] && {
      echo "\$_SERVER['REQUEST_URI'] = '${WP_BLOGDIR}' . \$_SERVER['REQUEST_URI'];"
      echo "\$_SERVER['SCRIPT_NAME'] = '${WP_BLOGDIR}' . \$_SERVER['SCRIPT_NAME'];"
      #echo "\$_SERVER['PHP_SELF'] = '${WP_BLOGDIR}' . $_SERVER['PHP_SELF'];"
   }

   cat <<'EOF'
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
# END ADDITIONS
EOF
   tac ${infile1} | sed -n -e '1,/^define.*DB_NAME.*\|^\# END ADDITIONS/{/^define.*DB_NAME.*\|^\# END ADDITIONS/!p;}' | tac

} > ${tmpfile1}

chmod 0644 ${tmpfile1}
mv ${tmpfile1} ${infile1} >/dev/null 2>&1
}

{ while [[ ! -f ${infile1} ]]; do echo "waiting for ${infile1} to exist. Sleeping 3." && sleep 3; done; dotask;} &

exec /entrypoint.sh "$@"
EOFENTRYMOD

I learned that here-documents can employ variable names without being parsed by bash if you put the end string in quotes, as shown in this script file. Reference: Weblink 5

Running the wordpress install

Now start up the docker-compose.

sudo docker-compose up

Configuring Apache as a reverse proxy

Enable these mods. For ubuntu apache2:

a2enmod xml2enc headers rewrite proxy_http proxy_html proxy

Here is a virtualhost directive.

<VirtualHost *:80>
        ServerName kim.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        RewriteEngine On

        ProxyPass               /frodo          http://kim.example.com:8001
        ProxyPassReverse        /frodo          http://kim.example.com:8001

        ProxyPass               /bilbo          http://kim.example.com:8000
        ProxyPassReverse        /bilbo          http://kim.example.com:8000

</VirtualHost>

Appendices

Commands used during my building and testing

Aliases in ~/.bashrc.local

alias dc='/usr/bin/sudo docker-compose'
alias docker='/usr/bin/sudo docker'

Command lines

dc down && docker rmi bilbo_wpmod && sudo rm -rf /var/bilbo
watch 'head -n58 /var/bilbo/www/wp-config.php | tail -n 17'

Adding vim to a docker container

In the wordpress container, to get to the local organization mirror for ubuntu.
Need 3 apt keys, two of which are the main ubuntu keys.

apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32 40976EAF437D05B5
curl http://mirror.example.com/ubuntu/my-debian/my-debian.gpg > /root/my-debian.gpg
apt-key add /root/my-debian.gpg
apt-get update
apt-get install -y vim

References

Weblinks

  1. Apt-key commands https://chrisjean.com/fix-apt-get-update-the-following-signatures-couldnt-be-verified-because-the-public-key-is-not-available/
  2. http://www.apachetutor.org/admin/reverseproxies
  3. https://codex.wordpress.org/Changing_The_Site_URL
  4. https://pressable.com/blog/2015/10/15/reverse-proxy-plugin-for-using-a-hosted-wordpress-site-in-a-subdirectory/
  5. http://www.tldp.org/LDP/abs/html/here-docs.html#HERELIT

Reverse proxy for wordpress

I spent the most research time on getting wordpress to work behind a reverse proxy.
I ended up writing my own Dockerfile to make my own image based on the wordpress image, because the entrypoint was not sufficient.

  1. One of the first pages you hit https://wordpress.org/support/topic/wordpress-behind-reverse-proxy-1?replies=4
  2. Eventually I got to the point where main site would work, but the wp-admin pages would redirect to host.example.org/ and not include the /blog directory, like this guy who didn’t get it solved. https://wordpress.org/support/topic/stop-rewrites-to-reverse-proxy-for-wp-admin?replies=5
  3. Similar problems to this guy. He also provided his nginx reverse proxy config. https://wordpress.org/support/topic/wordpress-behind-a-reverse-proxyssl-endpoint-slightly-borked?replies=6
  4. At some point I had the wp-admin page working but the main site just wasn’t loading at all.
  5. The holy grail is found here by this WordPress genius. https://wordpress.org/support/topic/wordpress-strips-subdirectory-at-some-wp-admin-pages-with-and-reverse-proxy?replies=11#post-2445234
  6. I didn’t use this, but this might be needed in the future: a .htaccess file that I saw referenced in at least one other location. https://gist.github.com/neverything/7675846

Internal documents

  1. Dockerizing WordPress in One Container with Apache.docx
  2. Adding the service httpd.docx
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s