Production-grade Docker Compose deployment for WordPress + MariaDB 11 + Redis 7.
Two web server variants: Nginx + PHP-FPM (recommended) and Apache mod_php (legacy). Designed for self-hosting on Coolify, Traefik, Caddy, or any Docker-native reverse proxy.
git clone https://github.com/artysan-code/wordpress-composing.git
cd wordpress-composing
cp .env.example .env
# Edit .env with your passwords
docker compose up -dVisit http://your-host/wp-admin/install.php to complete the WordPress installation.
The stack runs three services on an internal backend network — database and cache are never exposed externally. WordPress sits behind a reverse proxy (Coolify, Traefik, Caddy) that handles TLS termination.
- WordPress — Nginx + PHP-FPM 8.3 (supervisor) or Apache mod_php, with WP-CLI pre-installed
- MariaDB 11 — tuned for WordPress with InnoDB buffer pool and slow query log
- Redis 7 — object cache with igbinary serialization, password-protected
| File | Web Server | Use Case |
|---|---|---|
compose.yaml |
Nginx + PHP-FPM (supervisor) | Default. Production-ready, Coolify-compatible |
compose.apache.yaml |
Apache mod_php | Legacy / simpler setups |
compose.dev.yaml |
Overlay only | Adds phpMyAdmin, exposes MariaDB port 3306 |
The dev overlay is never used alone — always combine it with a base file:
docker compose -f compose.yaml -f compose.dev.yaml up -dcap_drop: ALLwith minimalcap_addon every service- PHP execution blocked in
/uploadsdirectory xmlrpc.phpdenied;wp-login.phprate limited (Nginx)- Security headers:
X-Content-Type-Options,X-Frame-Options,Referrer-Policy,X-XSS-Protection - Vulnerability scanner bot blocking
- Cloudflare trusted proxy ranges configured
- OPcache: 256 MB, 10 000 files
- Redis object cache with igbinary serialization
- Gzip compression (level 6)
- Static asset caching with 30-day expires
- MariaDB tuned: 512 MB InnoDB buffer pool, slow query log
- All resource limits configurable via environment variables
- WP-CLI pre-installed in both variants
- Health checks on all services
- Structured JSON logging with rotation (configurable size/count)
- Redis cache flush on startup (opt-in)
- WP Cron disable (opt-in) — use external scheduler for
wp-cron.php
The entrypoint auto-configures HTTPS detection in wp-config.php for:
| Header | Used By |
|---|---|
X-Forwarded-Proto |
Coolify, Traefik, generic proxies |
X-Forwarded-SSL |
Standard SSL termination |
CF-Visitor |
Cloudflare |
If the site URL starts with http:// but the proxy sends HTTPS headers, WordPress URLs are auto-migrated to https:// in the database on container start.
All settings are managed through .env. Every variable has a sensible default — only credentials are required.
| Variable | Description |
|---|---|
SERVICE_PASSWORD_WORDPRESS |
MariaDB WordPress user password |
SERVICE_PASSWORD_ROOT |
MariaDB root password |
SERVICE_PASSWORD_REDIS |
Redis password |
| Variable | Default | Description |
|---|---|---|
SERVICE_USER_WORDPRESS |
wordpress |
MariaDB WordPress user |
FLUSH_REDIS_ON_STARTUP |
false |
Flush Redis on container start (Apache variant) |
DISABLE_WP_CRON |
false |
Disable WP-Cron; use external scheduler |
| Variable | Default (Nginx) | Default (Apache) | Description |
|---|---|---|---|
WP_CPU_LIMIT |
2.0 |
2.0 |
WordPress CPU limit |
WP_MEMORY_LIMIT |
1536M |
2048M |
WordPress memory limit |
WP_CPU_RESERVATION |
0.5 |
0.5 |
WordPress CPU reservation |
WP_MEMORY_RESERVATION |
384M |
512M |
WordPress memory reservation |
DB_CPU_LIMIT |
1.0 |
1.0 |
MariaDB CPU limit |
DB_MEMORY_LIMIT |
1024M |
1024M |
MariaDB memory limit |
DB_CPU_RESERVATION |
0.25 |
0.25 |
MariaDB CPU reservation |
DB_MEMORY_RESERVATION |
256M |
256M |
MariaDB memory reservation |
REDIS_CPU_LIMIT |
0.5 |
0.5 |
Redis CPU limit |
REDIS_MEMORY_LIMIT |
2048M |
512M |
Redis max memory |
| Variable | Default | Description |
|---|---|---|
DB_INNODB_BUFFER_POOL |
512M |
InnoDB buffer pool size |
DB_MAX_CONNECTIONS |
500 |
Max concurrent connections |
DB_MAX_ALLOWED_PACKET |
64M |
Max packet size |
DB_SLOW_QUERY_TIME |
2 |
Slow query threshold (seconds) |
DB_WAIT_TIMEOUT |
300 |
Connection idle timeout (seconds) |
| Variable | Default | Description |
|---|---|---|
REDIS_MAX_MEMORY_POLICY |
allkeys-lru |
Eviction policy |
| Variable | Default | Description |
|---|---|---|
LOG_MAX_SIZE |
10m |
Max log file size before rotation |
LOG_MAX_FILES |
3 |
Number of rotated log files to keep |
- Create a new service, select Docker Compose
- Set the repository URL:
https://github.com/artysan-code/wordpress-composing - Configure environment variables in Coolify's env editor (match
.env.example) - Deploy — Coolify handles reverse proxy and TLS termination
The compose files use expose instead of ports, which is the Coolify-compatible pattern.
# Nginx (recommended)
docker compose up -d
# Apache
docker compose -f compose.apache.yaml up -d
# With dev tools
docker compose -f compose.yaml -f compose.dev.yaml up -dWP-CLI is pre-installed in both variants.
# List plugins
docker compose exec wordpress wp plugin list --allow-root
# Update WordPress core
docker compose exec wordpress wp core update --allow-root
# Search-replace URLs (after domain change)
docker compose exec wordpress wp search-replace 'old.com' 'new.com' --allow-root
# Redis cache management
docker compose exec wordpress wp redis status --allow-root
docker compose exec wordpress wp cache flush --allow-rootAdds phpMyAdmin and exposes MariaDB on host port 3306:
docker compose -f compose.yaml -f compose.dev.yaml up -d# Rebuild images
docker compose build
# View logs
docker compose logs -f wordpress
docker compose logs -f mariadb
docker compose logs -f redis
# Shell access
docker compose exec wordpress bashSwitching from the Apache variant to Nginx is automatic. The entrypoint detects the migration and:
- Temporarily disables Redis object cache
- Flushes Redis (removes incompatible serialized data)
- Clears WordPress file caches (preserves Matomo)
- Re-configures Redis settings for igbinary
- Re-enables Redis object cache
No manual intervention required.
.
├── compose.yaml # Nginx variant (default, production)
├── compose.apache.yaml # Apache variant (legacy)
├── compose.dev.yaml # Dev overlay (phpMyAdmin + MariaDB port)
├── Dockerfile # Nginx + PHP-FPM image
├── Dockerfile.apache # Apache mod_php image
├── docker-entrypoint.sh # Nginx entrypoint
├── docker-entrypoint-apache.sh # Apache entrypoint
├── .env.example # Environment variable template
├── config/
│ ├── nginx/ # Nginx configuration
│ ├── php/ # PHP-FPM and PHP ini
│ └── supervisor/ # Supervisor process manager
├── CONTRIBUTING.md # Contribution guidelines
├── SECURITY.md # Security policy
└── CODE_OF_CONDUCT.md # Community standards
Contributions are welcome. Please read CONTRIBUTING.md for guidelines on reporting issues, submitting pull requests, and our development workflow.
For security vulnerabilities, see SECURITY.md.
This project is licensed under the GNU General Public License v3.0.