Containerize WordPress & SQL and Host Multiple Websites on One Host
that cool logo comes from https://www.docker.com/

Containerize WordPress & SQL and Host Multiple Websites on One Host

Problem Statement

I recently had a problem statement that went along the lines of this: "I need to host all my virtual wordpress instances on one machine to be efficient with resource usage and cloud expenditure for instance-based charges and I would like them to be containerized so we can easily upgrade and fix potential issues on the fly without forming a dependency on the VM itself."

Action Plan

Taking the problem statement into action calls for a few things:

  • Apache will sit on the host itself and act as a reverse proxy for each wordpress instance. Split DNS will be used to identify hostnames externally/internally of the VM box. Therefore, a HTTP request sent to www.host1.com and www.host2.com will go to the VM IP and Apache will proxy the request to the correct backend instance (in this case running on a docker container).
  • WordPress containers need to run independently on one host and access their respective databases and also be able to have changes done quickly without affecting each other.
  • Databases need to be containerized and isolated for each WordPress instance to be efficient and organized on which WordPress instance is accessing a specific database - this just helps but I would surmise you could also just run one container of SQL granted though, a dependency would form on that SQL container causing subsequent problems with it to cascade to other instances. Separation is a kind friend here.
  • Static IPs need to be created on the docker instances to ensure subsequent restarts etc. do not change where the instance is connected to for example. Volume mounts of the Apache directory and the wordpress directory to respective locations on the host allow start/stop/removal of the container instances and new ones to be spun up with different configurations.

Configuration

Now onward to the specific configurations.

I used an Ubuntu 18.04 box for this particular effort but any old Linux VM capable of docker and Apache will do. Since the machine itself is not receiving 1,000,000 requests a second, I went more lightweight with 2 cores, 4GB of memory, and 32GB of storage. I will list the steps out below.

Database Work

  • If you are using Ubuntu 18.04 with lvm then resize the default lvm partition to use 100% of the available space.
sudo lvextend -l 100%FREE --resizefs /dev/ubuntu-vg/ubuntu-lv

  • Update the box.
sudo apt-get update -y && sudo apt-get upgrade -y

  • Turn off swap to make docker behave.
sudo swapoff -a

  • Install docker.
 sudo apt install docker.io

  • Create the docker network for the wordpress and sql instances.
sudo docker network create --subnet=172.18.0.0/24 wordpressnet

  • Create the directory on the host to mount the mysql data directory.
mkdir -p /opt/host1/mysql-data
  • In order for each wordpress instance to have their own database container, we will run the mysql docker container with environment variables to specify for each instance. We use a workaround to allow for the database password authentication to work when the wordpress container attempts to connect. Please customize as you wish for host1 and host2 paying special attention to setting a secure password:
sudo docker run --name host1-mysql \
--restart=always \
--net wordpressnet \
--ip 172.18.0.10 \
-v /opt/host1/mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpressdb \
-e MYSQL_USER=wordpress \
-e MYSQL_PASSWORD=password \
-d mysql:latest mysqld --default-authentication-plugin=mysql_native_password

Wordpress Work

  • Make the directory for the individual websites on the host. This will mount the wordpress install folder:
mkdir -p /opt/host1/www
mkdir -p /opt/host2/www
  • One thing that must be done is to start the wordpress container to obtain the apache default configuration files first. We will craft the docker run directive for host1 and host2.
  • Below is the example docker run command for host1 wordpress. Customize this to fit your needs and use it for host2 as well.
  • Here we set restart to always so that docker automatically restarts the container either when it crashes or it detects that it stopped. Then we specify the docker network we would like to use and then the static docker IP in this network. After that, we specify the container ports to map. We are mapping port 8282 on the host to port 80 of the container and port 8646 on host to port 443 on the container. Then we provide volume mounts of the container's wordpress directory and apache2 directory to the directories on the host.
  • After that, we specify where to find the wordpress database, the db user, the db password, and the db name and finally we specify it to start the container and run in the background and we use wordpress:latest to specify the latest build of wordpress:
sudo docker run --name host1-wordpress \
--restart=always \
--net wordpressnet \
--ip 172.18.0.3 \
-p 8282:80 \
-p 8646:443 \
-v /opt/host1/www:/var/www/html \
-v /opt/host1/apache2:/etc/apache2 \
-e WORDPRESS_DB_HOST=172.18.0.10:3306 \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=password \
-e WORDPRESS_DB_NAME=wordpressdb \
-d wordpress:latest
  • Get the container id of the running wordpress container use:
sudo docker ps -a
No alt text provided for this image
  • Issue a docker copy command to copy each instance apache config files to the host:
sudo docker cp <docker container ID>:/etc/apache2 /opt/host1
sudo docker cp <docker container ID>:/etc/apache2 /opt/host2
  • You can now stop the container and start it again for the changes to file structure to take affect:
sudo docker stop <docker container ID>
sudo docker start <docker container ID>
  • At this point, we can start to configure wordpress. Remember that we pointed port 8282 on the host to port 80 of the container. We can reach this initial install page by going to https://<host IP>/wp-admin/install.php
  • Go through the process to setup wordpress on host1 and host2 - this will initiate the databases as well. You now have a baseline wordpress install for each instance in their own docker container. Let's move onto apache config.

Apache Work

  • Install apache on the host machine and enable SSL and reverse proxy mods.
sudo apt-get install apache2
sudo ufw allow 'Apache'
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_https
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
sudo systemctl restart apache2
  • Create a configuration file for each instance in /etc/apache2/sites-enabled - this can be named host1.conf and host2.conf if you would like to follow convention. In this configuration file, we are setting up the virtual host directive for port 80 and port 443 on the box to reverse proxy to the backend servers and in this case the port that the containers are listening to. Ensure that you have created proper DNS entries for this to work. I used Let's Encrypt here to issue my SSL certs which makes it easy. Choose what's best for you. Restart apache after you are finished with sudo systemctl restart apache2.
<VirtualHost *:80>
        ServerAdmin [email protected]
        ServerName host1.com
        ServerAlias www.host1.com
        ErrorLog ${APACHE_LOG_DIR}/host1-http-error.log
        CustomLog ${APACHE_LOG_DIR}/host1-http-access.log combined


        <Proxy *>
            Order allow,deny
            Allow from all
        </Proxy>
        ProxyPreserveHost On
        ProxyPass / https://www.host1.com:8282/
        ProxyPassReverse / https://www.host1.com:8282/
</VirtualHost>


<VirtualHost *:443>
        ServerAdmin [email protected]
        ServerName host1.com
        ServerAlias www.host1.com
        ErrorLog ${APACHE_LOG_DIR}/host1-https-error.log
        CustomLog ${APACHE_LOG_DIR}/host1-https-access.log combined


        SSLEngine on
        SSLProxyEngine on
        # self-signed
        #SSLCertificateFile          /etc/ssl/certs/ssl-cert-snakeoil.pem
        #SSLCertificateKeyFile       /etc/ssl/private/ssl-cert-snakeoil.key
        # let's encrypt
        SSLCertificateFile           /etc/apache2/ssl/host1-cert.pem
        SSLCertificateKeyFile        /etc/apache2/ssl/host1-key.pem
        SSLCertificateChainFile      /etc/apache2/ssl/host1-chain.pem


        <Proxy *>
            Order allow,deny
            Allow from all
            Require all granted
        </Proxy>
        ProxyPreserveHost On
        ProxyPass / https://www.host1.com:8646/
        ProxyPassReverse / https://wwww.host1.com:8646/
</VirtualHost>
  • After this is finished, we need to edit the apache configuration for the docker containers as well. We can navigate to /opt/host1/apache2/sites-enabled and create a host1.conf as well with the following config:
<VirtualHost *:80>
        ServerAdmin [email protected]
        ServerName host1.com
        ServerAlias www.host1.com
        DocumentRoot /var/www/html


        ErrorLog ${APACHE_LOG_DIR}/http-error.log
        CustomLog ${APACHE_LOG_DIR}/http-access.log combined
</VirtualHost>


<VirtualHost *:443>
        ServerAdmin [email protected]
        ServerName host1.com
        ServerAlias www.host1.com


    <Directory /var/www/html>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
        Require all granted
    </Directory>


        DocumentRoot /var/www/html
        SSLEngine on
        SSLCertificateFile           /etc/apache2/ssl/cert.pem
        SSLCertificateKeyFile        /etc/apache2/ssl/key.pem
        SSLCertificateChainFile      /etc/apache2/ssl/chain.pem
        ErrorLog ${APACHE_LOG_DIR}/https-error.log
        CustomLog ${APACHE_LOG_DIR}/https-access.log combined
</VirtualHost>
  • At this point, we need to enter the docker container for host1 and enable apache ssl and restart apache:
Get the running docker container ID of host1 wordpress then type:

sudo docker exec -it <container ID> /bin/bash

This will place you in the docker container of host1.

Enable apache2 ssl: a2enmod ssl

Restart apache: service apache2 restart
  • After restarting apache on the container, it will kick you out of the container. Remember you can always view the logs of your container by issuing docker logs <container ID>

That's All Folks

With this configuration, you have a docker container for host1 and host2 - both of which point to their own docker sql container. You have the run commands with environment variables that you can edit in the future if needed. You also have volume mounts on the host to maintain persistence between docker containers and make edits to wordpress and apache. You are able to host multiple instances on one box with apache acting as a reverse proxy on the host to the backend docker containers. Overall, this is an interesting and efficient way to use docker to size instances efficiently and of course it is a fun way to experiment with docker and lab things out!

要查看或添加评论,请登录

Richard K.的更多文章

社区洞察

其他会员也浏览了