Docker Swarm is a popular infrastructure tool for running websites and web applications online. Here’s how to deploy WordPress Multisite on Docker Swarm.

Server racks. Source.

This post extends https://blog.budhajeewa.com/deploy-wordpress-on-docker-swarm/. We’ll refer to that as the “parent post” in this post.

Setup WordPress

Follow the parent post, and get a WordPress stack up and running.

Allow Multisite Feature

Open the docker-compose.yml and add the highlighted lines to it.

version: '3' services: wordpress: image: wordpress:5.1.1-php7.1-apache depends_on: - mariadb volumes: - ./volumes/wordpress/content:/var/www/html/wp-content environment: WORDPRESS_DB_HOST: mariadb:3306 WORDPRESS_DB_PASSWORD: root WORDPRESS_CONFIG_EXTRA: | /* Multisite */ define('WP_ALLOW_MULTISITE', true ); ports: - 8001:80 mariadb: image: mariadb:10.4.4 volumes: - ./volumes/mariadb/data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root

Then run make deploy (This is facilitate by https://blog.budhajeewa.com/docker-swarm-deploying-web-apps-and-sites/#easy-redeployment-with-a-makefile.). Wait till the the site is back up, and continue with the rest of the instructions.

Network Setup

In the WordPress dashboard, go to Tools → Network Setup , choose the address style, fill in network details, and click “Install”. It will then present you with some codes to be added to the wp-config.php and some code to replace current content of .htaccess file with.

As you’re running a Docker Container based on an Docker Image for WordPress, you don’t really have to edit the file manually, and the changes will be lost sooner or later, as Docker Containers are volatile. We can use the environment variable WORDPRESS_CONFIG_EXTRA to add the configuration changes.

What I have shown below is what was given to me by WordPress; yours may change. Be sure to use your own code, as given by WordPress. I’ve highlighted the newly added lines.

version: '3' services: wordpress: image: wordpress:5.1.1-php7.1-apache depends_on: - mariadb volumes: - ./volumes/wordpress/content:/var/www/html/wp-content environment: WORDPRESS_DB_HOST: mariadb:3306 WORDPRESS_DB_PASSWORD: root WORDPRESS_CONFIG_EXTRA: | /* Multisite */ define('WP_ALLOW_MULTISITE', true ); define('MULTISITE', true); define('SUBDOMAIN_INSTALL', true); define('DOMAIN_CURRENT_SITE', 'example.com'); define('PATH_CURRENT_SITE', '/'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); ports: - 8001:80 mariadb: image: mariadb:10.4.4 volumes: - ./volumes/mariadb/data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root

Unfortunately, there’s no quick environment variable to replace the content of the .htaccess file. So we have to create a file, and mount it at the proper location.

In the com-example/volumes/wordpress/ directory, create a file named htaccess (No period at the start of the file name, as we don’t want to turn that into a hidden file.), and add the following content into it.

RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] # add a trailing slash to /wp-admin RewriteRule ^wp-admin$ wp-admin/ [R=301,L] RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] RewriteRule ^(wp-(content|admin|includes).*) $1 [L] RewriteRule ^(.*\.php)$ $1 [L] RewriteRule . index.php [L]

Then open the docker-compose.yml file and add the highlighted line to it.

version: '3' services: wordpress: image: wordpress:5.1.1-php7.1-apache depends_on: - mariadb volumes: - ./volumes/wordpress/content:/var/www/html/wp-content - ./volumes/wordpress/htaccess:/var/www/html/.htaccess environment: WORDPRESS_DB_HOST: mariadb:3306 WORDPRESS_DB_PASSWORD: root WORDPRESS_CONFIG_EXTRA: | /* Multisite */ define('WP_ALLOW_MULTISITE', true ); define('MULTISITE', true); define('SUBDOMAIN_INSTALL', true); define('DOMAIN_CURRENT_SITE', 'example.com'); define('PATH_CURRENT_SITE', '/'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); ports: - 8001:80 mariadb: image: mariadb:10.4.4 volumes: - ./volumes/mariadb/data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root

We now mount the outside volumes/wordpress/htaccess file to the Docker Container’s mount point /var/www/html/.htaccess .

Above is how your docker-compose.yml would ultimately look.

Support Any Subdomain and Main Domain in NGINX

You only have to do this if you choose sub domains as the domain style for your child sites.

As instructed in https://blog.budhajeewa.com/deploy-wordpress-on-docker-swarm/#map-a-domain-to-the-wordpress-installation, our WordPress Stack’s NGINX configuration currently looks like following:

server { listen 80; server_name example.com; location / { proxy_pass http://host.public.ip.address:8001; proxy_set_header Host $host; } }

It only supports the main domain, you can get it to support the main domain as well as any sub domains of it, by prepending a period to the server_name value. This is how the configuration file would look like after the change. Changed line is highligted.

server { listen 80; server_name .example.com; location / { proxy_pass http://host.public.ip.address:8001; proxy_set_header Host $host; } }