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:
parent
d326670b1f
commit
892601f65b
4 changed files with 70 additions and 3 deletions
18
README.md
18
README.md
|
|
@ -267,9 +267,21 @@ No changes to this repo. In the new project:
|
||||||
## Maintenance / hardening
|
## Maintenance / hardening
|
||||||
|
|
||||||
- **Backups:** the `forgejo_data` volume is now the source of truth (repos, DB,
|
- **Backups:** the `forgejo_data` volume is now the source of truth (repos, DB,
|
||||||
registry blobs). Run `docker compose exec forgejo forgejo dump` on a schedule,
|
registry blobs). Two layers:
|
||||||
and set a **push-mirror** on each repo to a cloud host (GitLab/GitHub) for
|
- *Off-box git:* a **push-mirror** of each repo to Codeberg (repo → Settings →
|
||||||
off-box git backup.
|
Mirror Settings → Add Push Mirror; HTTPS URL + a `write:repository` token).
|
||||||
|
- *Full dump:* the systemd timer in [`backup/`](backup/) runs `forgejo dump`
|
||||||
|
daily and keeps 14 days under `/opt/backups/forgejo`. Install on the VPS:
|
||||||
|
```sh
|
||||||
|
sudo install -m 0755 backup/forgejo-backup.sh /usr/local/bin/forgejo-backup.sh
|
||||||
|
sudo cp backup/forgejo-backup.{service,timer} /etc/systemd/system/
|
||||||
|
sudo systemctl daemon-reload && sudo systemctl enable --now forgejo-backup.timer
|
||||||
|
sudo systemctl start forgejo-backup.service # test once
|
||||||
|
ls -lh /opt/backups/forgejo # confirm an archive landed
|
||||||
|
systemctl list-timers forgejo-backup.timer # confirm next run scheduled
|
||||||
|
```
|
||||||
|
Copy the dumps off-box too (they're useless if the VPS dies). Add
|
||||||
|
`--skip-package` in the script to exclude registry blobs if dumps get large.
|
||||||
- **Registry GC:** per-commit `:sha` tags accumulate. Enable Forgejo's package
|
- **Registry GC:** per-commit `:sha` tags accumulate. Enable Forgejo's package
|
||||||
cleanup rules / run periodic GC so the VPS disk doesn't fill.
|
cleanup rules / run periodic GC so the VPS disk doesn't fill.
|
||||||
- **Certs:** never delete the `caddy_data` volume — losing it re-issues every
|
- **Certs:** never delete the `caddy_data` volume — losing it re-issues every
|
||||||
|
|
|
||||||
10
backup/forgejo-backup.service
Normal file
10
backup/forgejo-backup.service
Normal 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
34
backup/forgejo-backup.sh
Executable 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}"
|
||||||
11
backup/forgejo-backup.timer
Normal file
11
backup/forgejo-backup.timer
Normal 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue