CloudOpsGuide
docker

Running WordPress on Docker Compose in Production

Intermediate
11 minutes
October 2026
CloudOpsGuide Team

Running WordPress on Docker Compose in Production

Docker Compose has a reputation as a dev-only tool, but for small-to-medium workloads on a single host it's a perfectly reasonable production setup — if you treat it like production. Here's how we run WordPress on Compose with nginx and MariaDB, and the practices that matter.

Table of Contents

The reference stack

services:
  db:
    image: mariadb:11.4
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/mysql
    networks: [backend]

  wordpress:
    image: wordpress:php8.3-fpm
    restart: unless-stopped
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      db:
        condition: service_healthy
    networks: [backend]

  nginx:
    image: nginx:1.27-alpine
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - wordpress_data:/var/www/html:ro
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    networks: [backend]

volumes:
  db_data:
  wordpress_data:
networks:
  backend:

What makes this "production"

  • Pinned image versions — mariadb:11.4, not latest. Upgrades are deliberate, tested events.
  • restart: unless-stopped — containers come back after crashes and reboots.
  • Named volumes — data survives docker compose down. Never store real data in container layers.
  • Healthchecks — depends_on: condition: service_healthy means WordPress doesn't start hammering a half-initialized database.
  • Secrets via files — Docker secrets or env files with 600 perms, never passwords in the compose file you commit.

nginx as the front door

Putting nginx in front gives you TLS termination, gzip, caching headers, and rate limiting in one place — and lets you swap the app behind it without touching DNS. Mount the WordPress volume read-only (:ro) so a compromised nginx can't modify application files.

Backups: the part everyone skips

# database dump
docker compose exec db mariadb-dump -u wp -p"$WP_PASS" wordpress \
  | gzip > backups/wp-$(date +%F).sql.gz

# files
docker run --rm -v wordpress_data:/data -v $(pwd)/backups:/b \
  alpine tar czf /b/files-$(date +%F).tar.gz -C /data .

A backup you haven't restored is a hope, not a backup. Test the restore monthly.

Honest limits

Compose won't give you rolling deploys, auto-scaling, or self-healing across hosts. When you need multiple hosts or zero-downtime deploys, that's your signal to look at Kubernetes — not before. Until then, a boring, well-backed-up Compose stack beats a half-understood cluster every time.

Related Articles


Last Updated: October 2026 Author: CloudOpsGuide Team Difficulty: Intermediate Estimated Reading Time: 11 minutes