# Runbook ## Installation screen remains visible 1. Check `docker compose ps` for healthy database and WordPress services. 2. Run `docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh`. 3. Inspect `docker compose logs wordpress db` without printing secret values. ## WordPress stays in waiting or unhealthy 1. Inspect `docker compose logs wordpress db` without printing secret values. 2. Confirm the database volume was initialized with the same `MARIADB_DATABASE`, `MARIADB_USER`, and password currently configured in `.env`. 3. Confirm `WP_URL` has the intended scheme and hostname. In production it should be the public HTTPS URL. 4. Rebuild after changes to the WordPress image: ```bash docker compose up --build -d wordpress ``` The WordPress healthcheck is internal and does not depend on the public DNS/TLS route. It sends the configured host and forwarded protocol headers to avoid following external HTTPS redirects during production startup. ## NGINX returns 502 1. Run `docker compose ps` and `docker compose exec proxy nginx -t`. 2. Check the WordPress health status and `docker compose logs proxy wordpress`. 3. Confirm the request host is exactly `azionelab.org`; unknown hosts return 404. ## Images or theme are missing 1. Confirm `WORDPRESS_DATA_PATH` is mounted in both WordPress and WP-CLI. 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. ## Uploaded image does not appear on the public page 1. Confirm the image was selected in **Appearance > Customize**, not only uploaded in **Media**. For the teacher portrait, use **Appearance > Customize > Il maestro > Foto**, then publish the change. 2. Hard-refresh the browser or purge the CDN cache. An NGINX log status `304` for `/wp-content/uploads/...` is not an application error; it means the browser already has a cached copy and NGINX did not resend the file body. 3. If the upload appears in Media but not on the page, inspect the generated `` URL and verify it uses the public scheme/host configured by `WP_URL`. 4. Confirm the uploaded file exists under `WORDPRESS_DATA_PATH/wp-content/uploads` and is readable by the WordPress container user. ## Show card description is hard to find Edit **Spettacoli**, open the show, then use **Dettagli spettacolo > Descrizione breve**. That field is rendered below the title in the homepage show card. The small uppercase line above the title is not the description. It is built from **Dettagli spettacolo > Anno** and **Luogo**. Empty fields are hidden on the public card. ## A service cannot write to its volume 1. Stop the affected service. 2. Confirm the relevant `.env` path points to the intended host directory. 3. Run `./scripts/prepare-host-volumes.sh`. 4. Start the service and inspect logs without printing secret values. ## Certificate issuance fails Verify public DNS, inbound port 80, the operator email, and staging mode. Request a missing `/.well-known/acme-challenge/` path: an NGINX 404 confirms the route is yours. Avoid repeated production-CA retries while debugging. When Let's Encrypt is enabled, the proxy intentionally returns 503 for normal application paths until a certificate exists. ACME challenge paths and proxy health paths must still work in that pending state, otherwise Certbot will never start. ## Staging certificate remains after switching to production Certbot does not replace a still-valid staging certificate just because `LETSENCRYPT_STAGING` changed. Recreate the Certbot container so it reads the updated environment: ```bash docker compose up -d --force-recreate certbot docker compose up -d proxy ``` The entrypoint removes an existing staging certificate for `LETSENCRYPT_DOMAIN` before requesting the production certificate. If issuance fails, inspect `docker compose logs certbot proxy`, verify DNS and port 80, and avoid repeated production-CA retries. ## Bootstrap writes to the wrong data volume Do not combine the test override with production bootstrap commands. This command writes to isolated test volumes only: ```bash docker compose -f docker-compose.yml -f docker-compose.test.yml --profile tools run --rm wp-cli /scripts/bootstrap.sh ``` Use this command for the real host-based WordPress data directory: ```bash docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh ``` ## Rollback Revert the deployment commit and rebuild while preserving all host data directories. Restore database/files only for a data rollback and only from a verified coordinated backup.