Azione!Lab WordPress

A warm, editorial single-page website for the Azione!Lab contemporary theatre workshop. WordPress manages the content, a custom theme owns the visual system, and Docker Compose provides MariaDB, NGINX, optional Let's Encrypt, WP-CLI, and isolated browser tests.

Architecture

  • wordpress/: pinned WordPress 7/PHP 8.3 image, custom theme, and structured-content must-use plugin.
  • db: MariaDB 11.8 LTS, available only on the internal data network.
  • proxy: the only published service; routes azionelab.org to WordPress and applies edge security controls.
  • certbot: optional HTTP-01 certificate issue/renewal service.
  • wp-cli: opt-in bootstrap and maintenance service.
  • tests/functional: Playwright tests running only through the public virtual host.

See architecture and ADR-0001.

Prerequisites

  • Docker Engine with Docker Compose v2.
  • Local ports 8080 and 8443 available.
  • 127.0.0.1 azionelab.org in the local hosts file.

No host PHP, database, Node.js, or WordPress installation is required.

Start locally

cp .env.example .env
./scripts/prepare-host-volumes.sh
docker compose up --build -d
docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh
docker compose ps

Open:

Use the development credentials copied into .env only locally. Change them before sharing the environment.

First startup procedure

Use this checklist for the first run of a new environment.

  1. Create the environment file:

    cp .env.example .env
    
  2. Edit .env before starting containers:

    • set strong MARIADB_PASSWORD, MARIADB_ROOT_PASSWORD, and WP_ADMIN_PASSWORD;
    • set WP_URL to the public URL, for example https://lab.younerd.org;
    • set LETSENCRYPT_DOMAIN to the same hostname when direct Let's Encrypt is used;
    • keep LETSENCRYPT_STAGING=1 for the first certificate test;
    • configure DB_DATA_PATH, WORDPRESS_DATA_PATH, LETSENCRYPT_DATA_PATH, and CERTBOT_CHALLENGES_PATH for the host directories that must persist.
  3. Prepare host-based volumes and permissions:

    ./scripts/prepare-host-volumes.sh
    

    On Linux hosts, rerun with sudo if the script warns that it cannot change ownership:

    sudo ./scripts/prepare-host-volumes.sh
    
  4. Start the runtime services:

    docker compose up --build -d
    docker compose ps
    

    With LETSENCRYPT_ENABLED=1 and no certificate yet, NGINX intentionally returns 503 for normal application traffic while still serving ACME challenge and health routes. Certbot should start after the proxy becomes healthy.

  5. Install/configure WordPress on the real persistent volume:

    docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh
    

    Do not add -f docker-compose.test.yml here. The test override uses disposable test volumes and is only for automated checks.

  6. Follow certificate issuance:

    docker compose logs -f proxy certbot
    

    After the staging certificate flow is working, switch to the production CA:

    LETSENCRYPT_STAGING=0
    

    Then recreate Certbot so it sees the new environment and restart the proxy:

    docker compose up -d --force-recreate certbot
    docker compose up -d proxy
    

    If a staging certificate already exists, the Certbot entrypoint removes only that staging certificate before requesting the production one. During the replacement window, NGINX may briefly return 503 for application traffic and will recover as soon as the production certificate is issued.

  7. Final sanity checks:

    docker compose ps
    docker compose logs --tail=100 proxy wordpress db certbot
    

    Open the configured WP_URL and /wp-admin/.

Persistent data uses host-based bind mounts by default:

  • ./runtime/db for MariaDB;
  • ./runtime/wordpress for WordPress core, uploads, themes, and mu-plugins copied at container startup;
  • ./runtime/letsencrypt for certificates;
  • ./runtime/certbot/www for ACME HTTP-01 challenges.

Run ./scripts/prepare-host-volumes.sh before the first start, especially on Linux hosts. The script reads .env, creates the directories, and assigns the expected container owners (999:999 for MariaDB, 33:33 for WordPress, 0:0 for Certbot). Override the *_DATA_PATH and *_VOLUME_UID/GID variables in .env if your runtime uses different host paths or image user IDs.

Edit content

  • Appearance > Customize: hero, manifesto, laboratory, teacher, lessons, contacts, social links, and footer.
  • Shows: poster, title, excerpt, year, place, and order.
  • Gallery: image, category, caption/title, and order.
  • Settings > General: site name and tagline.

Real uploaded images replace the built-in editorial SVG placeholders. The three participation cards remain intentional theme copy; making them reorderable is a TODO if the workshop later needs more than the current three fixed audiences.

Production configuration

Set WP_ENVIRONMENT_TYPE=production, unique database passwords of at least 16 characters, a strong admin password, the public HTTPS WP_URL, and WORDPRESS_DEBUG=0. Production startup rejects placeholder database credentials. WordPress file editing and web-based theme/plugin/core modification are disabled; deploy updates by rebuilding the pinned image.

When a trusted load balancer owns TLS, keep LETSENCRYPT_ENABLED=0 and set TRUST_PROXY_HEADERS=1 only if NGINX is reachable exclusively from that load balancer and the load balancer overwrites forwarding headers.

For direct exposure, point public DNS at the host, expose ports 80/443, and start with the Let's Encrypt staging CA:

WP_ENVIRONMENT_TYPE=production
WP_URL=https://azionelab.org
LETSENCRYPT_ENABLED=1
LETSENCRYPT_DOMAIN=azionelab.org
LETSENCRYPT_EMAIL=operator@example.org
LETSENCRYPT_STAGING=1
NGINX_BIND_ADDRESS=0.0.0.0
NGINX_HTTP_PORT=80
NGINX_HTTPS_PORT=443
TRUST_PROXY_HEADERS=0

Before the first certificate exists, NGINX serves ACME challenges and returns 503 for application traffic. After issuance, HTTP redirects to HTTPS automatically.

After validating the staging certificate flow, set LETSENCRYPT_STAGING=0 and recreate the Certbot container. Existing staging certificates are removed automatically before a production certificate is requested:

docker compose up -d --force-recreate certbot
docker compose up -d proxy

Run the real bootstrap without the test override:

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.

Useful commands

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 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
docker compose run --rm --no-deps wordpress php -l /opt/azionelab/azionelab-content.php
docker compose run --rm --no-deps proxy nginx -t
docker compose -f docker-compose.yml -f docker-compose.test.yml up --build -d db wordpress proxy
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile tools run --rm wp-cli /scripts/bootstrap.sh
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --build --rm functional-tests
docker compose config --quiet

Backup

Back up the database and WordPress files at the same logical point in time:

docker compose stop wordpress
mkdir -p backups
docker compose exec -T db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE"' > backups/database.sql
tar -C runtime -czf backups/wordpress-files.tgz wordpress
docker compose start wordpress

Do not commit backups or .env. Encrypt and test real backups off-host. See operations before restoring or deleting volumes.

Rollback

Revert the application commit and rebuild containers. Preserve the host directories configured by DB_DATA_PATH, WORDPRESS_DATA_PATH, LETSENCRYPT_DATA_PATH, and CERTBOT_CHALLENGES_PATH. Database restoration is a separate, destructive operation and requires a verified backup.

S
Description
No description provided
Readme 422 KiB
Languages
Markdown 100%