Why these apps together
A small business or a blog runs its own WordPress and wants to hear about downtime before visitors do, without a paid monitoring service for the first checks.
Each app page deploys its app alone. Run together behind Caddy, Uptime Kuma can watch WordPress twice: through the public address, as visitors reach it (DNS, certificate, Caddy, WordPress), and directly at the container over the network Caddy shares with both. When only the first check fails, the problem is in front of WordPress. This page gives both addresses and states what a monitor on the same server cannot see.
Apps in this stack
| App | Role in the stack | Load level | Compose support |
|---|---|---|---|
| WordPress | The site, with MariaDB as its database. | Light | Run-tested |
| Uptime Kuma | Checks the site every minute and sends the alerts. | Light | Run-tested |
How the apps connect
- Uptime Kuma to WordPress:
http://wordpress:80 - An HTTP monitor on the WordPress container itself, over Caddy's edge network: it answers whether WordPress and its database respond, whatever Caddy does.
- Uptime Kuma to WordPress:
https://<WORDPRESS_DOMAIN> - An HTTP(s) monitor on the public address from .env: the path visitors take, through public DNS, the certificate and Caddy.
Resources for the whole server
Computed by the Stack Sizer's engine for these apps and load levels: what the apps need, the system baseline and the safety headroom. The same input in the Stack Sizer gives the same numbers.
| Part | vCPU | RAM (GiB) | Disk (GiB) |
|---|---|---|---|
| WordPress | 2 | 0.625 | 7 |
| Uptime Kuma | 0.5 | 0.5 | 1.7 |
| System baseline | 0.1 | 1.25 | 8.4 |
| Safety headroom | 0.52 | 0.475 | 2.565 |
| Recommended total | 3.12 | 2.85 | 19.665 |
Caddy is not included in the resource calculation of the Stack Sizer or the Deployment Spec.
Files from the Compose Generator
# Generated by the ANAROQ Compose Generator: https://anaroq.com/tools/compose-generator
# Engine @anaroq/compose 1.0.0, catalog 2026.10.10, exposure caddy.
# Apps: wordpress 1.1.0, uptime-kuma 1.1.0 (supported, not run-tested).
# No secrets in this file: copy .env.example to .env and fill it in before `docker compose up -d`.
services:
wordpress:
image: "wordpress:7.1.3-php8.4-apache"
restart: "unless-stopped"
environment:
WORDPRESS_DB_HOST: "wordpress-mariadb"
WORDPRESS_DB_USER: "wordpress"
WORDPRESS_DB_PASSWORD: "${WORDPRESS_DB_PASSWORD:?set WORDPRESS_DB_PASSWORD in .env}"
WORDPRESS_DB_NAME: "wordpress"
volumes:
- "wordpress-data:/var/www/html"
networks:
- "wordpress-internal"
- "edge"
depends_on:
wordpress-mariadb:
condition: "service_healthy"
wordpress-mariadb:
image: "mariadb:12.3.3"
restart: "unless-stopped"
environment:
MARIADB_DATABASE: "wordpress"
MARIADB_USER: "wordpress"
MARIADB_PASSWORD: "${WORDPRESS_DB_PASSWORD:?set WORDPRESS_DB_PASSWORD in .env}"
MARIADB_RANDOM_ROOT_PASSWORD: "1"
volumes:
- "wordpress-mariadb-data:/var/lib/mysql"
networks:
- "wordpress-internal"
healthcheck:
test:
- "CMD"
- "healthcheck.sh"
- "--connect"
- "--innodb_initialized"
interval: "10s"
timeout: "5s"
retries: 3
start_period: "10s"
uptime-kuma:
image: "louislam/uptime-kuma:2.5.6"
restart: "unless-stopped"
environment:
UPTIME_KUMA_DB_TYPE: "sqlite"
volumes:
- "uptime-kuma-data:/app/data"
networks:
- "uptime-kuma-internal"
- "edge"
caddy:
image: "caddy:2.11.7-alpine"
restart: "unless-stopped"
environment:
WORDPRESS_DOMAIN: "${WORDPRESS_DOMAIN:?set WORDPRESS_DOMAIN in .env}"
UPTIME_KUMA_DOMAIN: "${UPTIME_KUMA_DOMAIN:?set UPTIME_KUMA_DOMAIN in .env}"
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- "./Caddyfile:/etc/caddy/Caddyfile:ro"
- "caddy-data:/data"
- "caddy-config:/config"
networks:
- "edge"
networks:
wordpress-internal: {}
uptime-kuma-internal: {}
edge: {}
volumes:
wordpress-data: {}
wordpress-mariadb-data: {}
uptime-kuma-data: {}
caddy-data: {}
caddy-config: {}
# Generated by the ANAROQ Compose Generator: https://anaroq.com/tools/compose-generator
# Engine @anaroq/compose 1.0.0, catalog 2026.10.10, exposure caddy.
# Copy this file to .env and fill in every value. Never commit .env.
# ANAROQ does not create passwords or keys: generate them on your own machine.
# --- wordpress ---
# Password of the WordPress MariaDB user (MARIADB_PASSWORD and WORDPRESS_DB_PASSWORD).
# Secret, required. For example: openssl rand -hex 24
WORDPRESS_DB_PASSWORD=
# Public host name of the site behind the reverse proxy, for example blog.example.com.
# Required.
WORDPRESS_DOMAIN=
# --- uptime-kuma ---
# Public host name of Uptime Kuma behind the reverse proxy, for example status.example.com (a subdirectory is not supported).
# Required.
UPTIME_KUMA_DOMAIN=
# Generated by the ANAROQ Compose Generator: https://anaroq.com/tools/compose-generator
# Engine @anaroq/compose 1.0.0, catalog 2026.10.10, exposure caddy.
# Each site address comes from .env through the Caddy container's environment.
{$WORDPRESS_DOMAIN} {
reverse_proxy wordpress:80
}
{$UPTIME_KUMA_DOMAIN} {
reverse_proxy uptime-kuma:3001
}
Generated by the Compose Generator's engine for these apps behind Caddy. The files hold no secrets: copy .env.example to .env and fill it in.
Compose Analyzer result
10 findings: 0 error, 0 high, 0 medium, 10 low, 0 info.
Low10
- LowAQ-HLTH-002Line 8, column 5
services.wordpresswordpress has no
healthcheck.Fix: Add a healthcheck, so Compose and you can tell when the service is ready.
- LowAQ-HLTH-005Line 8, column 5
services.wordpresswordpress does not limit the size of its logs (
logging.options.max-size).Fix: Limit the log size so logs cannot fill the disk.
- LowAQ-SEC-005Line 11, column 7
services.wordpress.environmentwordpress passes secrets through
environment(WORDPRESS_DB_PASSWORD).Fix: Where the image supports it, use
secrets:or a_FILEvariable instead. - LowAQ-HLTH-005Line 24, column 5
services.wordpress-mariadbwordpress-mariadb does not limit the size of its logs (
logging.options.max-size).Fix: Limit the log size so logs cannot fill the disk.
- LowAQ-SEC-005Line 27, column 7
services.wordpress-mariadb.environmentwordpress-mariadb passes secrets through
environment(MARIADB_PASSWORD, MARIADB_RANDOM_ROOT_PASSWORD).Fix: Where the image supports it, use
secrets:or a_FILEvariable instead. - LowAQ-HLTH-005Line 46, column 5
services.uptime-kumauptime-kuma does not limit the size of its logs (
logging.options.max-size).Fix: Limit the log size so logs cannot fill the disk.
- LowAQ-HLTH-002Line 56, column 5
services.caddycaddy has no
healthcheck.Fix: Add a healthcheck, so Compose and you can tell when the service is ready.
- LowAQ-HLTH-005Line 56, column 5
services.caddycaddy does not limit the size of its logs (
logging.options.max-size).Fix: Limit the log size so logs cannot fill the disk.
- LowAQ-PORT-005Line 62, column 9
services.caddy.ports.0This file publishes 3 port mappings. Docker publishes ports past ufw rules.
Fix: Filter them in the
DOCKER-USERchain or at the provider's firewall, or do not publish them. - LowAQ-VOL-005Line 66, column 9
services.caddy.volumes.0caddy bind-mounts the relative path ./Caddyfile.
Fix: That works, but the data lives in the directory you run Compose from: back it up.
The Compose Analyzer (ruleset 1.0.0) checked docker-compose.yml: 0 error, 0 high, 0 medium and 10 low findings. A recipe is published only without error and high findings.
Continue in the tools
The link opens the Compose Generator with these apps, options and exposure, and with the Deployment Spec of this sizing, so cloud-init and the Runbook start from the same state.
Runbook
Before the first start
- Copy
.env.exampleto.envnext todocker-compose.ymland fill in every value. Compose stops with an error while a required value is missing. - Create WORDPRESS_DB_PASSWORD on your own machine, for example with
openssl rand -hex 24. ANAROQ never creates passwords or keys. - Keep
Caddyfilenext todocker-compose.yml; the Caddy container mounts it read-only. - Ports 80 and 443 (TCP, and 443/UDP for HTTP/3) must be reachable from the internet for Caddy's automatic HTTPS.
- Before starting, point the A/AAAA records of the domain in WORDPRESS_DOMAIN (wordpress) to this server; Caddy requests its certificate on first start.
- Before starting, point the A/AAAA records of the domain in UPTIME_KUMA_DOMAIN (uptime-kuma) to this server; Caddy requests its certificate on first start.
- Start the stack with
docker compose up -dand follow it withdocker compose ps.
After the first start
Create the Uptime Kuma admin
Open the Uptime Kuma host name from .env and create the admin account on the first screen.
Monitor the container
Add an HTTP(s) monitor with the internal address below. It stays up while WordPress and MariaDB answer, even if Caddy or the certificate fails.
http://wordpress:80Monitor the public address
Add a second HTTP(s) monitor with https:// and the WordPress host name from .env, and connect a notification (email, chat) to both monitors.
What the apps share
- A monitor on the same server goes down with it: a power, network or provider outage silences both. Keep one external check, or a second Uptime Kuma elsewhere, for the server itself.
- Uptime Kuma gets its own public host name through Caddy. Create its admin account right after the first start, before anyone else can reach the page.
- Back up WordPress's files and database and Uptime Kuma's data volume: the monitors and their history live there.
Alternatives
- A hosted uptime service checks from outside and sees a server outage; it complements the internal check rather than replacing it.
- Uptime Kuma alone, on another server, watches this site from outside: its own page sizes it. Uptime Kuma
Basis
- Catalog
- 2026.10.10
- Sizing policy
- 2026.10.0
- Compose engine
- @anaroq/compose 1.0.0
- Analyzer ruleset
- 1.0.0
Sources
How profiles, sizes and Compose files are built is described in the methodology. Read the methodology