!! 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/
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.
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
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.
- 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)
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
- 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