From f75bce3dea6aaef2c590e4f4b2eb80d896204163 Mon Sep 17 00:00:00 2001 From: bisco Date: Thu, 23 Jul 2026 21:22:21 +0200 Subject: [PATCH] chore: add wp-cli maintenance override --- README.md | 19 +++++++++++++++++++ docker-compose.maintenance.yml | 10 ++++++++++ docs/operations.md | 14 ++++++++++++++ docs/runbook.md | 15 +++++++++++++++ docs/security.md | 4 ++++ docs/testing.md | 1 + tests/security/check-compose.sh | 20 ++++++++++++++++++++ 7 files changed, 83 insertions(+) create mode 100644 docker-compose.maintenance.yml diff --git a/README.md b/README.md index 2a5a330..e90aab6 100644 --- a/README.md +++ b/README.md @@ -212,12 +212,30 @@ docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh The `docker-compose.test.yml` override intentionally uses disposable test volumes; do not use it for production or staging bootstrap commands. +## Maintenance commands with internet access + +The default `wp-cli` service joins only the internal database network, so it cannot +download packages from the internet. For controlled maintenance commands that need +egress, such as a WordPress core update, include the maintenance override: + +```bash +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update --version=7.0.2 --force' +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update-db' +docker compose --profile tools run --rm wp-cli -c 'wp core version' +docker compose restart wordpress proxy +``` + +Use this override only for maintenance operations that genuinely need outbound +network access. Normal bootstrap and inspection commands should keep using the base +Compose file. + ## Useful commands ```bash docker compose logs -f proxy wordpress db certbot docker compose --profile tools run --rm wp-cli -c 'wp plugin list' docker compose --profile tools run --rm wp-cli -c 'wp core version' +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update --version=7.0.2 --force' docker compose run --rm --no-deps wordpress php -l /opt/azionelab/theme/functions.php docker compose run --rm --no-deps wordpress php -l /opt/azionelab/theme/front-page.php @@ -228,6 +246,7 @@ docker compose -f docker-compose.yml -f docker-compose.test.yml --profile tools docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --build --rm functional-tests docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --rm security-tests docker compose config --quiet +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml config --quiet ``` ## Backup diff --git a/docker-compose.maintenance.yml b/docker-compose.maintenance.yml new file mode 100644 index 0000000..f06147f --- /dev/null +++ b/docker-compose.maintenance.yml @@ -0,0 +1,10 @@ +# Optional maintenance override. +# +# The default wp-cli service only joins the internal data network. Use this override +# when a controlled maintenance command must reach the internet, for example a +# WordPress core download from wordpress.org. +services: + wp-cli: + networks: + - data + - web diff --git a/docs/operations.md b/docs/operations.md index 2fa4e01..1f765d9 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -23,6 +23,20 @@ Review security releases routinely, update pins in a task branch, rebuild, run t test suite, and deploy. Production disables WordPress web-based file modifications, so image rebuilds are the update path. +The default `wp-cli` service is attached only to the internal data network. When a +maintenance command must download from the internet, use +`docker-compose.maintenance.yml` explicitly: + +```bash +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update --version=7.0.2 --force' +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update-db' +docker compose --profile tools run --rm wp-cli -c 'wp core version' +docker compose restart wordpress proxy +``` + +Do not use the maintenance override for routine bootstrap or inspection commands that +do not need outbound network access. + External `wp-cron.php` requests are blocked to reduce public attack surface. If future content scheduling, maintenance jobs, or plugin features require WordPress cron, run it from a controlled host/container cron against the private WordPress service instead of diff --git a/docs/runbook.md b/docs/runbook.md index 79474cb..27eba25 100644 --- a/docs/runbook.md +++ b/docs/runbook.md @@ -35,6 +35,21 @@ HTTPS redirects during production startup. 2. Run `docker compose --profile tools run --rm wp-cli -c 'wp theme status azionelab'`. 3. Verify file ownership before changing permissions; never make the tree world-writable. +## WP-CLI cannot resolve wordpress.org + +The default WP-CLI container intentionally runs only on the internal data network. Use +the maintenance override for commands that must download WordPress core files: + +```bash +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update --version=7.0.2 --force' +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml --profile tools run --rm wp-cli -c 'wp core update-db' +docker compose --profile tools run --rm wp-cli -c 'wp core version' +docker compose restart wordpress proxy +``` + +If DNS still fails with the maintenance override, inspect the host/container DNS +configuration and firewall rules before retrying the update. + ## Uploaded image does not appear on the public page 1. Confirm the image was selected in **Appearance > Customize**, not only uploaded in diff --git a/docs/security.md b/docs/security.md index a91730a..58c23cd 100644 --- a/docs/security.md +++ b/docs/security.md @@ -28,6 +28,10 @@ WordPress/Apache retains the capabilities needed by the official image internally, but no WordPress port is published. A containerized security test fails if the WordPress service is configured with host-published ports. +- WP-CLI normally joins only the internal data network. The maintenance override + attaches WP-CLI to the web network for operator-triggered commands that require + outbound internet access, such as WordPress core downloads; do not use it for routine + bootstrap or inspection commands. - Persistent state uses host-based bind mounts. Keep those paths outside the public web root, restrict host access, never make them world-writable, and run `./scripts/prepare-host-volumes.sh` when paths or image user IDs change. diff --git a/docs/testing.md b/docs/testing.md index 2e56653..50e00dc 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -12,6 +12,7 @@ docker compose -f docker-compose.yml -f docker-compose.test.yml --profile tools docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --build --rm functional-tests docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --rm security-tests docker compose config --quiet +docker compose -f docker-compose.yml -f docker-compose.maintenance.yml config --quiet LETSENCRYPT_ENABLED=1 docker compose config --quiet ``` diff --git a/tests/security/check-compose.sh b/tests/security/check-compose.sh index f8e2102..be57ac3 100755 --- a/tests/security/check-compose.sh +++ b/tests/security/check-compose.sh @@ -56,3 +56,23 @@ grep -q "location ^~ /wp-content/mu-plugins/" /workspace/nginx/proxy-routes.conf echo "NGINX must hide the mu-plugins directory from public probing." >&2 exit 1 } + +[ -f /workspace/docker-compose.maintenance.yml ] || { + echo "The maintenance Compose override must exist for controlled wp-cli egress." >&2 + exit 1 +} + +grep -q "^[[:space:]]*wp-cli:" /workspace/docker-compose.maintenance.yml || { + echo "The maintenance override must target only the wp-cli service." >&2 + exit 1 +} + +grep -q "^[[:space:]]*-[[:space:]]*data$" /workspace/docker-compose.maintenance.yml || { + echo "The maintenance wp-cli service must keep database network access." >&2 + exit 1 +} + +grep -q "^[[:space:]]*-[[:space:]]*web$" /workspace/docker-compose.maintenance.yml || { + echo "The maintenance wp-cli service must explicitly opt into the web network." >&2 + exit 1 +}