WordPress

Using WordPress with Docker

Run WordPress on the fpm-apache variation. WordPress expects to update its own files from the admin screen. Many plugins also write rewrite rules to .htaccess, which only Apache reads. The setup on this page keeps both working.

Run WordPress with MariaDB

Download WordPress and extract it into public/, which is the image's default document root. Then add this Compose file next to public/:

compose.yml
services:
  wordpress:
    image: serversideup/php:8.5-fpm-apache
    ports:
      - "80:8080"
    volumes:
      - ./:/var/www/html
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:11.8
    environment:
      MARIADB_ROOT_PASSWORD: rootpassword
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wordpress
      MARIADB_PASSWORD: wordpress
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

Run docker compose up, open http://localhost, and enter mariadb as the database host in the installer. Change the passwords before you use this anywhere but your own machine.

WordPress runs as www-data (UID 33 on Debian). It can only install plugins and updates if that user can write to the mounted files. See understanding file permissions if the admin screen asks for FTP credentials.

For HTTPS, put a reverse proxy such as Traefik in front of the container or set SSL_MODE. See configuring SSL.

What the image blocks

  • xmlrpc.php: blocked by fpm-apache only. fpm-nginx and frankenphp don't block it, so add a rule yourself if you use them and don't need XML-RPC.
  • Dotfiles such as .env and .git/ (except /.well-known/), and files ending in .sql, .log, .bak, .ini, and similar: blocked by every web server variation.

The full Apache rules are in security.conf.

Choose how to deploy updates

There are two ways to run WordPress in containers. Pick by how much of your site is third-party plugins.

Volume-based approach (traditional)

WordPress core, plugins, and themes live on a volume, and the container only provides PHP and Apache. The admin screen updates everything as it would on a regular host. Only your own themes and plugins go in version control. Deploy them with git pull or your usual tool. The example repository uses this approach.

Choose it for sites that rely on third-party plugins. The trade-off is that updates made in the admin screen are not versioned or reproducible.

With PHP_OPCACHE_ENABLE=1, PHP keeps cached files until the container restarts, because PHP_OPCACHE_VALIDATE_TIMESTAMPS defaults to 0. Updates from the admin screen still apply, because WordPress clears the cache for files it writes with wp_opcache_invalidate(). Changes from git pull, WP-CLI, SFTP, or plugins that write PHP files directly don't apply until you restart the container or set PHP_OPCACHE_VALIDATE_TIMESTAMPS=1. See production performance tuning.

Immutable images

WordPress core and every plugin are built into the image, often with Roots Bedrock and Composer. You package the image like any other app. You get rolling deployments and rollbacks to a previous image.

Choose it for custom sites where you control the code. Updates happen in your build, not the admin screen. Plugins that write to their own folders or expect the standard WordPress layout can break. Test every plugin you rely on.