docker-maintenance/ adds a systemd timer + prune.sh for the root LV that holds Docker's data-root and has filled to 100% before, risking ENOSPC corruption. The script sticks to the safe reclaim set (builder cache, dangling images, stopped containers) and deliberately avoids `-a` and volume pruning, which can destroy live data when run unattended. kanboard/backup.sh and healthcheck.sh bring Kanboard in line with the other services. seafile/ and vaultwarden/ backup scripts get fixes carried from the stability audit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
70 lines
3.3 KiB
Bash
Executable File
70 lines
3.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Kanboard backup — tier-0 hardening (kb#158, A2A-26, DESIGN-a2a-agents.md v2.1 §6c).
|
|
# Mirrors the vaultwarden backup.sh pattern (same repo, ~/agap_git/vaultwarden/backup.sh):
|
|
# scheduled dump -> /mnt/backups, retention of last 5, Zabbix freshness trapper.
|
|
#
|
|
# Runs every 3 days via alvis's user crontab (NOT root crontab like vaultwarden's --
|
|
# /mnt/backups/kanboard was bootstrapped chown'd to alvis specifically so this backup,
|
|
# like the rest of the kanboard tooling, needs no root/sudo at all. alvis is in the
|
|
# `docker` group so `docker exec`/`docker cp` need no privilege escalation either).
|
|
#
|
|
# DB dump method: kanboard's container has no sqlite3 CLI and no PHP `sqlite3`
|
|
# extension (only pdo_sqlite) -- checked directly (kb#158). Instead we run SQLite's
|
|
# own `VACUUM INTO` via PDO, which is SQLite's supported way to take an atomic,
|
|
# consistent online snapshot of a live database (safe against concurrent writers,
|
|
# same safety property `vaultwarden backup` gives us for that service).
|
|
|
|
set -euo pipefail
|
|
|
|
BACKUP_DIR="/mnt/backups/kanboard"
|
|
ZABBIX_TOKEN_FILE="/home/alvis/.zabbix_token"
|
|
ZABBIX_URL="http://192.168.1.4:81/api_jsonrpc.php"
|
|
ZABBIX_ITEM_ID="70605" # kanboard.backup.ts on host AgapHost (10776)
|
|
|
|
DATE=$(date '+%Y%m%d-%H%M')
|
|
DEST="$BACKUP_DIR/$DATE"
|
|
TMP_NAME="backup_${DATE}.sqlite"
|
|
|
|
mkdir -p "$DEST"
|
|
|
|
# Online, consistent snapshot via SQLite's VACUUM INTO (PDO sqlite driver is present
|
|
# in the image; the sqlite3 CLI/extension is not, so this replaces the vaultwarden
|
|
# `docker exec vaultwarden /vaultwarden backup` equivalent for this service).
|
|
docker exec kanboard php -r '
|
|
$db = new PDO("sqlite:/var/www/app/data/db.sqlite");
|
|
$db->exec("VACUUM INTO \"/var/www/app/data/'"$TMP_NAME"'\"");
|
|
'
|
|
|
|
# Pull the snapshot out to the host, then remove the temp copy from the live data dir
|
|
# (mirrors vaultwarden's "move the file out of DATA_DIR" step).
|
|
docker cp "kanboard:/var/www/app/data/$TMP_NAME" "$DEST/db.sqlite"
|
|
docker exec kanboard rm -f "/var/www/app/data/$TMP_NAME"
|
|
|
|
# Plugins volume (PLUGIN_INSTALLER=true means plugins can be installed at runtime,
|
|
# not just baked into the image) -- back it up too so a restore doesn't silently
|
|
# drop installed plugins.
|
|
docker run --rm --user 1000:1000 -v kanboard_plugins:/plugins:ro -v "$DEST":/dest alpine \
|
|
sh -c 'cd /plugins && tar -czf /dest/plugins.tar.gz . 2>/dev/null || true'
|
|
|
|
echo "$(date): Backup complete: $DEST"
|
|
ls -la "$DEST/"
|
|
|
|
# Notify Zabbix (trapper item kanboard.backup.ts, unixtime) -- pushes a real epoch
|
|
# timestamp, unlike vaultwarden.backup.ts which (kb#158 finding) pushes a formatted
|
|
# date STRING into a numeric item and has therefore never recorded a valid value.
|
|
if [[ -f "$ZABBIX_TOKEN_FILE" ]]; then
|
|
ZABBIX_TOKEN=$(cat "$ZABBIX_TOKEN_FILE")
|
|
NOW_EPOCH=$(date '+%s')
|
|
env -u HTTPS_PROXY -u HTTP_PROXY -u ALL_PROXY -u https_proxy -u http_proxy -u all_proxy \
|
|
curl -s -X POST "$ZABBIX_URL" \
|
|
-H "Content-Type: application/json" \
|
|
-H "Authorization: Bearer $ZABBIX_TOKEN" \
|
|
-d "{\"jsonrpc\":\"2.0\",\"method\":\"history.push\",\"id\":1,\"params\":{\"itemid\":\"$ZABBIX_ITEM_ID\",\"value\":$NOW_EPOCH}}" > /dev/null \
|
|
&& echo "Zabbix notified (kanboard.backup.ts=$NOW_EPOCH)."
|
|
else
|
|
echo "WARNING: $ZABBIX_TOKEN_FILE not found -- skipped Zabbix freshness push." >&2
|
|
fi
|
|
|
|
# Rotate: keep last 5 backups
|
|
ls -1dt "$BACKUP_DIR"/[0-9]*-[0-9]* 2>/dev/null | tail -n +6 | xargs -r rm -rf
|