Skip to content

Alternative Wordpress docker image for building immutable WP containers

Notifications You must be signed in to change notification settings

icewindow/wordpress-docker

 
 

Repository files navigation

Wordpress Docker base image

!! THIS IS A PROOF-OF-CONCEPT REPO, DO NOT USE IN PRODUCTION !!

Use this as a base image for 'immutable' Wordpress containers. Wordpress installed in this image is configured not to be writable by web server. All necessary file-level changes must be done by extending this image (see example below). This allows better maintenance, versioning, rollbacks and horizontal scaling possibility. Also, it improves Wordpress security by reducing the attack surface.

This image is automatically build and published on Docker Hub: https://hub.docker.com/r/wigwam/wordpress/

How it works

This image is based on debian:bookworm base image and has Apache, PHP and all Wordpress dependencies installed from Debian repositories. Wordpress is downloaded and extracted into /var/www/wordpress directory. Apache is configured to use this path as document root. Files in document root are not writable by web server, so "Install/Update plugin/theme" functionality in Wordpress admin panel does not work. In order to install plugins and themes from wordpress.org in build time, a wrapper script wp-install.sh is provided, see the example below. Entrypoint of this image is docker-entrypoint.sh a file taken from official Wordpress image and modified to work for immutable containers. It is responsible for applying the configuration specified in environment variables.

Example Dockerfile

You can extend this base image to create a custom Wordpress deployment (see example):

FROM wigwam/wordpress

# Install a theme from wordpress.org catalogue
RUN wp-install.sh theme zenearth

# Install a plugin from wordpress.org catalogue
RUN wp-install.sh plugin simple-lightbox

# Install a custom plugin
COPY cajwan-transcriptor /var/www/wordpress/wp-content/plugins/cajwan-transcriptor
RUN chown -R nobody:nogroup /var/www/wordpress/wp-content/plugins/cajwan-transcriptor

Configuration variables

Containers created from this image can be configured and customized by providing following environment variables (see examples/simple/docker-compose.yml):

Config option Default value Description
APACHE_SERVER_NAME wordpress.local ServerName in Apache virtual host config
APACHE_WP_ADMIN_ALLOW_FROM all granted Require directive for wp-admin directory in Apache virtual host config
APACHE_XMLRPC_ALLOW_FROM all denied Require directive for xmlrpc.php file in Apache virtual host config
WORDPRESS_DB_HOST mysql DB_HOST constant in wp-config.php
WORDPRESS_DB_USER root DB_USER constant in wp-config.php
WORDPRESS_DB_PASSWORD (empty) DB_PASSWORD constant in wp-config.php
WORDPRESS_DB_NAME wordpress DB_NAME constant in wp-config.php
WORDPRESS_TABLE_PREFIX (not set) $table_prefix`` variable in wp-config.php`
WORDPRESS_DEBUG (not set) DEBUG constant in wp-config.php
WORDPRESS_AUTH_KEY (autogenerated) AUTH_KEY constant in wp-config.php
WORDPRESS_SECURE_AUTH_KEY (autogenerated) SECURE_AUTH_KEY constant in wp-config.php
WORDPRESS_LOGGED_IN_KEY (autogenerated) LOGGED_IN_KEY constant in wp-config.php
WORDPRESS_NONCE_KEY (autogenerated) NONCE_KEY constant in wp-config.php
WORDPRESS_AUTH_SALT (autogenerated) AUTH_SALT constant in wp-config.php
WORDPRESS_SECURE_AUTH_SALT (autogenerated) SECURE_AUTH_SALT constant in wp-config.php
WORDPRESS_LOGGED_IN_SALT (autogenerated) LOGGED_IN_SALT constant in wp-config.php
WORDPRESS_NONCE_SALT (autogenerated) NONCE_SALT constant in wp-config.php
PHP_UPLOAD_MAX_FILESIZE (empty) upload_max_filesize PHP config value
PHP_POST_MAX_SIZE (empty) post_max_size PHP config value

Autogenerated Wordpress keys and salts work well with single-container deployments. However, they must be provided externally if the workload is load balanced between multiple containers, as they must be exactly the same for all containers in the deployment. Otherwise, Wordpress will not work properly. If you are constantly being logged out from the admin panel, this is most probably the reason.

Findings

How Wordpress works:

  • Wordpress normally rewrites its file structure (upgrades, plugin and theme installations), not advantageous for maintaining and versioning
  • Can be prevented by removing web server user's permissions to write files in document root
  • Wordpress can be configured not to display buttons to do any file-level actions:
define('DISALLOW_FILE_MODS', true);
define('DISALLOW_FILE_EDIT', true);
  • When configured like this, all code-level operations must be done manully - or, in Docker way, by rebuilding the image
  • When code self-rewriting is disabled, the only path the web server still needs to have write permissions is wp-content/uploads where Wordpress stores media files
  • PHP execution in wp-content/uploads directory can be disabled to prevent possibility of uploading arbitrary PHP script by attacker (only media files should be there)
  • Wordpress does not use PHP sessions and is fairly stateless. The shared state is in:
    • MySQL database
    • Media files storage (by default wp-content/uploads directory, plugins can be installed to support different storage backends)

Wordpress official Docker image:

Firstly, I have tried to use official Wordpress Docker image for this project, but it does not work as expected:

  • Wordpress official image could not be used, as it uses volume for /var/www/html what cannot be reverted in children images
  • wp-cli can't be used for build-time plugins and themes installation as it requires database access which is not yet available

TODO

  • SSL support (extra container for letsencrypt)
  • Consolidated logging
  • Enable plugin/theme specific version installation
  • Exlore container limits (memory, ...) options
  • Support apache2 prefork mpm config via the environment variables
  • Explore nginx/php-fpm options

About

Alternative Wordpress docker image for building immutable WP containers

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Shell 83.6%
  • Dockerfile 16.4%