Some checks failed
Architecture Lint / Linter Tests (push) Successful in 30s
Smoke Test / smoke (push) Failing after 24s
Validate Config / YAML Lint (push) Failing after 16s
Validate Config / JSON Validate (push) Successful in 21s
Validate Config / Cron Syntax Check (push) Successful in 15s
Validate Config / Deploy Script Dry Run (push) Successful in 14s
Validate Config / Python Syntax & Import Check (push) Failing after 1m2s
Validate Config / Python Test Suite (push) Has been skipped
Validate Config / Shell Script Lint (push) Failing after 1m3s
Validate Config / Playbook Schema Validation (push) Successful in 24s
Architecture Lint / Linter Tests (pull_request) Successful in 27s
Smoke Test / smoke (pull_request) Failing after 22s
Validate Config / YAML Lint (pull_request) Failing after 16s
Validate Config / JSON Validate (pull_request) Successful in 23s
Validate Config / Python Syntax & Import Check (pull_request) Failing after 1m5s
Validate Config / Python Test Suite (pull_request) Has been skipped
Validate Config / Cron Syntax Check (pull_request) Successful in 12s
Validate Config / Shell Script Lint (pull_request) Failing after 1m6s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 13s
Validate Config / Playbook Schema Validation (pull_request) Successful in 25s
PR Checklist / pr-checklist (pull_request) Failing after 4m33s
Architecture Lint / Lint Repository (push) Failing after 26s
Architecture Lint / Lint Repository (pull_request) Failing after 26s
- Add bin/gitea-backup.sh: daily backup script using gitea dump - Add cron/vps/gitea-daily-backup.yml: Hermes cron job (2 AM daily) - Add docs/backup-recovery-runbook.md: complete recovery procedures Addresses [AUDIT][RISK] Single-node VPS is a single point of failure. Closes #481
88 lines
2.8 KiB
Bash
88 lines
2.8 KiB
Bash
#!/bin/bash
|
|
# Gitea Daily Backup Script
|
|
# Uses Gitea's native dump command to create automated backups of repositories and SQLite databases.
|
|
# Designed to run on the VPS (Ezra) as part of a daily cron job.
|
|
#
|
|
# Configuration via environment variables:
|
|
# GITEA_BIN Path to gitea binary (default: auto-detect)
|
|
# GITEA_BACKUP_DIR Directory for backup archives (default: /var/backups/gitea)
|
|
# GITEA_BACKUP_RETENTION Days to retain backups (default: 7)
|
|
# GITEA_BACKUP_LOG Log file path (default: /var/log/gitea-backup.log)
|
|
|
|
set -euo pipefail
|
|
|
|
GITEA_BIN="${GITEA_BIN:-$(command -v gitea 2>/dev/null || echo "/usr/local/bin/gitea")}"
|
|
BACKUP_DIR="${GITEA_BACKUP_DIR:-/var/backups/gitea}"
|
|
RETENTION_DAYS="${GITEA_BACKUP_RETENTION:-7}"
|
|
DATE="$(date +%Y-%m-%d_%H%M%S)"
|
|
BACKUP_FILE="${BACKUP_DIR}/gitea-backup-${DATE}.tar.gz"
|
|
LOG_FILE="${GITEA_BACKUP_LOG:-/var/log/gitea-backup.log}"
|
|
|
|
mkdir -p "${BACKUP_DIR}"
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "${LOG_FILE}"
|
|
}
|
|
|
|
log "=== Starting Gitea daily backup ==="
|
|
|
|
# Verify gitea binary exists
|
|
if [ ! -x "${GITEA_BIN}" ]; then
|
|
log "ERROR: Gitea binary not found at ${GITEA_BIN}"
|
|
log "Set GITEA_BIN environment variable to the gitea binary path (e.g., /usr/bin/gitea)"
|
|
exit 1
|
|
fi
|
|
|
|
# Detect Gitea WORK_PATH
|
|
WORK_PATH=""
|
|
APP_INI=""
|
|
for path in /etc/gitea/app.ini /home/git/gitea/custom/conf/app.ini ~/gitea/custom/conf/app.ini; do
|
|
if [ -f "$path" ]; then
|
|
APP_INI="$path"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -n "$APP_INI" ]; then
|
|
# Parse [app] WORK_PATH = /var/lib/gitea
|
|
WORK_PATH=$(sed -n 's/^[[:space:]]*WORK_PATH[[:space:]]*=[[:space:]]*//p' "$APP_INI" | head -1)
|
|
log "Detected WORK_PATH from app.ini: ${WORK_PATH}"
|
|
fi
|
|
|
|
# Fallback detection
|
|
if [ -z "$WORK_PATH" ]; then
|
|
for d in /var/lib/gitea /home/git/gitea /srv/gitea /opt/gitea; do
|
|
if [ -d "$d" ]; then
|
|
WORK_PATH="$d"
|
|
break
|
|
fi
|
|
done
|
|
log "Inferred WORK_PATH: ${WORK_PATH:-not found}"
|
|
fi
|
|
|
|
if [ -z "$WORK_PATH" ]; then
|
|
log "ERROR: Could not determine Gitea WORK_PATH. Set GITEA_WORK_PATH manually."
|
|
exit 1
|
|
fi
|
|
|
|
# Perform gitea dump
|
|
# Flags: --work-path sets the Gitea working directory, --file writes dump to tar.gz
|
|
log "Running: gitea dump --work-path ${WORK_PATH} --file ${BACKUP_FILE}"
|
|
"${GITEA_BIN}" dump --work-path "${WORK_PATH}" --file "${BACKUP_FILE}" 2>>"${LOG_FILE}"
|
|
|
|
if [ $? -ne 0 ]; then
|
|
log "ERROR: gitea dump failed — check ${LOG_FILE} for details"
|
|
exit 1
|
|
fi
|
|
|
|
FILE_SIZE=$(du -h "${BACKUP_FILE}" | cut -f1)
|
|
log "Backup created: ${BACKUP_FILE} (${FILE_SIZE})"
|
|
|
|
# Prune old backups (keep last N days)
|
|
find "${BACKUP_DIR}" -name "gitea-backup-*.tar.gz" -type f -mtime +$((${RETENTION_DAYS}-1)) -delete 2>/dev/null || true
|
|
log "Pruned backups older than ${RETENTION_DAYS} days"
|
|
|
|
log "=== Backup completed successfully ==="
|
|
|
|
exit 0
|