feat(backup): add forgejo dump systemd timer + wire into runbook

Daily 'forgejo dump' (tar.zst) to /opt/backups/forgejo with 14-day retention,
via a oneshot service + timer. Maintenance section now documents both backup
layers (Codeberg push-mirror for git, dump timer for full state).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Josh Bairstow 2026-06-03 00:55:03 +10:00
parent d326670b1f
commit 892601f65b
4 changed files with 70 additions and 3 deletions

View file

@ -0,0 +1,10 @@
# Oneshot unit invoked by forgejo-backup.timer. Install both into
# /etc/systemd/system/ and `systemctl enable --now forgejo-backup.timer`.
[Unit]
Description=Forgejo dump backup
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/forgejo-backup.sh

34
backup/forgejo-backup.sh Executable file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# ----------------------------------------------------------------------------
# forgejo-backup.sh — dump the live Forgejo instance and copy the archive to
# the host. Run on the VPS via forgejo-backup.timer (see this dir).
#
# `forgejo dump` produces a single archive of the database, repositories,
# config, and the data dir (attachments + the container registry blobs). It is
# safe to run against a live instance.
#
# Install:
# sudo install -m 0755 forgejo-backup.sh /usr/local/bin/forgejo-backup.sh
# ----------------------------------------------------------------------------
set -euo pipefail
CONTAINER=forgejo
BACKUP_DIR=/opt/backups/forgejo
RETAIN_DAYS=14
STAMP="$(date +%Y%m%d-%H%M%S)"
NAME="forgejo-${STAMP}.tar.zst"
mkdir -p "$BACKUP_DIR"
# Dump as the git user inside the container (writes to /tmp), then copy out.
# Add --skip-package to exclude the registry blobs if dumps get too large
# (they grow with per-commit :sha image tags — see registry GC in the README).
docker exec -u git "$CONTAINER" \
forgejo dump --type tar.zst --skip-log --file "/tmp/${NAME}"
docker cp "${CONTAINER}:/tmp/${NAME}" "${BACKUP_DIR}/${NAME}"
docker exec "$CONTAINER" rm -f "/tmp/${NAME}"
# Retention: drop dumps older than RETAIN_DAYS.
find "$BACKUP_DIR" -maxdepth 1 -name 'forgejo-*.tar.zst' -mtime +"${RETAIN_DAYS}" -delete
echo "Backup written: ${BACKUP_DIR}/${NAME}"

View file

@ -0,0 +1,11 @@
# Daily Forgejo backup at 03:30 server time. Persistent=true runs a missed
# backup after the box was off at the scheduled time.
[Unit]
Description=Daily Forgejo dump backup
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
[Install]
WantedBy=timers.target