- Create Redis data directory with correct ownership (UID 999) so Redis
can write RDB snapshots; root-owned directory caused stop-writes-on-bgsave-error
which crash-looped Nextcloud background jobs at 400%+ CPU
- Disable Redis RDB snapshots (--save "") — Redis is cache-only for
Nextcloud; snapshot writes failed due to directory permissions and
blocked all Redis writes, causing background jobs to crash-loop at
400%+ CPU
- Add passlib as a required local dependency (needed for password_hash
filter in Ansible templates)
- Make dl role SFTP setup conditional on dl_sftp_authorized_keys being
set in the vault
- Fix check-vault.sh stdin conflict (pipe + heredoc) by passing vault
content via environment variable
- Remove dl_sftp_authorized_keys from required_scalars (it is optional)
- Traefik rate-limits all routes (60 req/min standard, 300 for Nextcloud)
and writes access logs to /var/log/traefik/access.log
- Fail2ban watches Traefik access logs and bans IPs after 10 x 403/404
within 60 s for 24 h
- Nextcloud html directory created as www-data (UID 33) so Apache can
process .htaccess and serve requests correctly
- scripts/check-services.sh verifies all seven endpoints return the
expected HTTP status after provisioning
- ansible.cfg: suppress Python interpreter discovery warning
- ansible/inventory.ini: add ansible_host; server IP is now defined in
one place and read dynamically by run-bootstrap.sh
- group_vars/all/ → directory layout so vault.yml is auto-loaded by Ansible
(previously vault.yml did not match any group name and was silently ignored)
- scripts/run-bootstrap.sh: read server IP from inventory, chmod 600 private
keys automatically, show actual SSH error when root login fails
- scripts/bootstrap-deploy-user.sh: add sudoers.d entry for passwordless sudo
(deploy user has no password so sudo group membership alone was not enough)
- nextcloud: fix Redis healthcheck (CMD-SHELL pipe was unreliable in Alpine,
switched to CMD form with start_period)
- group_vars/all/vars.yml: fix Roundcube image tag (1.6-apache and 1.6 do not
exist; correct tag is 1.6.x-apache)
- docs/runbook.md: expand prerequisites (SSH keys section), add step 1 for
setting the server IP, expand bootstrap step with preflight detail, fix
step numbering