# Runbook: mailcow update (mx2) ## Purpose Update the mailcow stack on mx2 to the latest supported release. ## Scope - Applicable: [mx2.windy.me](../hosts/mx2.windy.me.md), `/opt/mail`. - Not applicable: config changes beyond the update, DB migration, secret rotation. ## Ownership - Owner: personal ops (Windy) - Last reviewed: 2026-08-17 - Related systems: mx2.windy.me (`/opt/mail`) ## Approval gates | Action | Risk | Explicit approval | |---|---|---| | Run `./update.sh` (recreates containers, brief mail interruption) | Medium | Yes — user confirmation required | Target: [mx2.windy.me](../hosts/mx2.windy.me.md) Path: `/opt/mail` **Confirm with the user before running an update.** ## Safety - Never run the update without explicit user confirmation. - Never pass secrets into the chat log; do not commit `mailcow.conf`. - If a step fails, capture `docker compose ps` and logs and stop before further changes. - If live state conflicts with this runbook's assumptions (e.g. unexpected `mailcow.conf` values), `STOP` and report. ## Before 1. Run [mailcow-health](mailcow-health.md) (Ansible health report). Record baseline. 2. Note config quirks in `mailcow.conf`, especially: - `SKIP_CLAMD=y` — after update, `clamd` may still be running until services are recreated per mailcow docs. - `SKIP_LETS_ENCRYPT`, ports, hostname — should stay `mx2.windy.me`. 3. Disk/memory: `df -h /` and `free -h` on the host. ## Update ```bash ssh -t windy@mx2.windy.me 'cd /opt/mail && ./update.sh' ``` - Prefer interactive SSH (`-t`) so prompts work. - Do not pass secrets into the chat log; do not commit `mailcow.conf`. If update asks to stop/recreate containers, allow it unless the user said otherwise. ## After 1. Re-run health checks ([mailcow-health](mailcow-health.md)). 2. Confirm UI: `https://mx2.windy.me` 3. Confirm SMTP banner and queue empty. 4. If `SKIP_CLAMD=y` but `cow-clamd-mailcow-1` is still Up and that is unwanted: ```bash cd ansible ansible-playbook playbooks/compose-reconcile.yml --limit mailcow \ -e '{"service_reconcile_confirm": true, "service_reconcile_targets": ["all"]}' ``` Only after user OK; recreate briefly interrupts mail. 5. Update **Verified** on [hosts/mx2.windy.me.md](../hosts/mx2.windy.me.md) with date and outcome. ## Rollback Mailcow updates are image/git based; there is no one-click rollback in this runbook. If something fails, capture `docker compose ps` and `docker compose logs --tail=100` for the failing service and stop before further changes.