generated from bisco/codex-bootstrap
247 lines
8.5 KiB
Markdown
247 lines
8.5 KiB
Markdown
# 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](docs/architecture.md) and
|
|
[ADR-0001](docs/adr/0001-wordpress-single-page.md).
|
|
|
|
## 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
- site: <http://azionelab.org:8080>
|
|
- admin: <http://azionelab.org:8080/wp-admin/>
|
|
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
./scripts/prepare-host-volumes.sh
|
|
```
|
|
|
|
On Linux hosts, rerun with `sudo` if the script warns that it cannot change
|
|
ownership:
|
|
|
|
```bash
|
|
sudo ./scripts/prepare-host-volumes.sh
|
|
```
|
|
|
|
4. Start the runtime services:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
docker compose logs -f proxy certbot
|
|
```
|
|
|
|
After the staging certificate flow is working, switch to the production CA:
|
|
|
|
```dotenv
|
|
LETSENCRYPT_STAGING=0
|
|
```
|
|
|
|
Then recreate Certbot so it sees the new environment and restart the proxy:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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, short description, year, place, and order. The short
|
|
description is the **Descrizione breve** field inside **Dettagli spettacolo**.
|
|
- **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:
|
|
|
|
```dotenv
|
|
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:
|
|
|
|
```bash
|
|
docker compose up -d --force-recreate certbot
|
|
docker compose up -d proxy
|
|
```
|
|
|
|
Run the real bootstrap without the test override:
|
|
|
|
```bash
|
|
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
|
|
|
|
```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 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:
|
|
|
|
```bash
|
|
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](docs/operations.md) 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.
|