From eb69ee13e6d57248e27aeafadb1274247d564c17 Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 7 Apr 2026 17:53:21 -0700 Subject: [PATCH] changes --- .gitignore | 1 + BACKUP_RUNNER_PLAN.md | 70 +++++++++++++++++++++++++++++++++++++++ README.md | 54 ++++++++++++++++++++++++++++++ gitea-backup.cron | 4 +++ gitea-backup.sh | 2 +- gitea-dump-backup.sh | 76 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 BACKUP_RUNNER_PLAN.md create mode 100644 gitea-backup.cron create mode 100755 gitea-dump-backup.sh diff --git a/.gitignore b/.gitignore index de269cf4..06a27c2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ state/** tailscale-nginx/** +gitea-backups/** diff --git a/BACKUP_RUNNER_PLAN.md b/BACKUP_RUNNER_PLAN.md new file mode 100644 index 00000000..78ea28a2 --- /dev/null +++ b/BACKUP_RUNNER_PLAN.md @@ -0,0 +1,70 @@ +# Gitea Backup Runner Plan + +## Objective +Create a scheduled backup runner that: +1. Dumps Gitea data using the native `gitea dump` command via `docker exec` +2. Copies the backup archive from the container to the host +3. Transfers the backup to remote location `workstation:/mnt/data/git-backups` +4. Runs automatically once a month via cron + +## Current State +- Existing `gitea-backup.sh` uses `docker run` with tar to backup volume data +- This new approach uses Gitea's built-in `gitea dump` command which creates a complete backup including database, repos, and settings + +## Implementation Plan + +### 1. Create Backup Script: `gitea-dump-backup.sh` +- **Location**: `./gitea-dump-backup.sh` +- **Functions**: + - Generate timestamped backup filename + - Execute `gitea dump` inside the container via `docker exec` + - Copy the resulting archive from container to host backup directory + - Upload to remote workstation via `scp` or `rsync` + - Clean up old local backups (keep last N) + - Logging and error handling + +### 2. Create Cron Configuration +- **Location**: `./gitea-backup.cron` +- **Schedule**: First day of each month at 2:00 AM + ``` + 0 2 1 * * /path/to/gitea-dump-backup.sh >> /var/log/gitea-backup.log 2>&1 + ``` + +### 3. Directory Structure +``` +gitea-backups/ # Local backup storage (git-ignored) +├── gitea-dump-20260401-020000.zip +└── ... +``` + +### 4. Remote Transfer Options +- **Primary**: `rsync` over SSH to `workstation:/mnt/data/git-backups` +- Requires SSH key-based authentication setup or SSH agent forwarding + +### 5. Backup Retention +- Keep last 3 local backups (configurable) +- Remote retention handled by remote system + +### 6. Prerequisites +- SSH access to `workstation` server +- Sufficient disk space in container for dump operation +- Backup directory created on remote server + +## File Changes +| File | Action | +|------|--------| +| `gitea-dump-backup.sh` | Create - main backup script | +| `gitea-backup.cron` | Create - cron configuration | +| `.gitignore` | Update - exclude gitea-backups/ directory | + +## Security Considerations +- Store remote credentials securely (SSH key) +- Ensure backup files have appropriate permissions (600) +- Log handling for debugging + +## Testing Checklist +- [ ] Run backup script manually +- [ ] Verify archive contains expected files +- [ ] Test remote transfer +- [ ] Verify cron installation +- [ ] Test error handling scenarios diff --git a/README.md b/README.md index e69de29b..010d6090 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,54 @@ +# Gitea Docker + +A simple Docker Compose setup for running Gitea with Tailscale networking. + +## Backup + +This project includes a backup runner that uses Gitea's built-in `gitea dump` command. + +### Manual Backup + +```bash +./gitea-dump-backup.sh +``` + +### Automated Backup (Cron) + +The backup runs automatically on the 1st of every month at 2:00 AM. + +To install the cron job: + +```bash +crontab ./gitea-backup.cron +``` + +Or append to existing crontab: +```bash +crontab -l | cat - ./gitea-backup.cron | crontab - +``` + +### Configuration + +Edit the script variables to customize: + +- `REMOTE_HOST`: Remote backup server (default: `workstation`) +- `REMOTE_PATH`: Remote backup path (default: `/mnt/data/git-backups`) +- `KEEP_LOCAL`: Number of local backups to keep (default: 3) + +### Requirements + +- SSH access to the remote backup server +- `rsync` installed locally +- Backup directory must exist on remote server + +## Quick Start + +1. Create the remote backup directory: + ```bash + ssh workstation "mkdir -p /mnt/data/git-backups" + ``` + +2. Start Gitea: + ```bash + docker compose -f docker-compose.gitea.yml up -d + ``` diff --git a/gitea-backup.cron b/gitea-backup.cron new file mode 100644 index 00000000..5a1203c9 --- /dev/null +++ b/gitea-backup.cron @@ -0,0 +1,4 @@ +# Gitea Backup Cron Configuration +# Runs backup on the 1st of every month at 2:00 AM + +0 2 1 * * /home/noti/dev/gitea-docker/gitea-dump-backup.sh >> /var/log/gitea-backup.log 2>&1 diff --git a/gitea-backup.sh b/gitea-backup.sh index d880af53..761cf3e9 100755 --- a/gitea-backup.sh +++ b/gitea-backup.sh @@ -9,7 +9,7 @@ mkdir -p "$BACKUP_DIR" echo "Backing up Gitea data to $BACKUP_DIR/gitea-backup-$DATE.tar.gz..." docker run --rm \ - -v ai-game-2_gitea-data:/data \ + -v gitea_gitea-data:/data \ -v "$(pwd)/$BACKUP_DIR":/backup \ alpine \ tar czf "/backup/gitea-backup-$DATE.tar.gz" -C /data . diff --git a/gitea-dump-backup.sh b/gitea-dump-backup.sh new file mode 100755 index 00000000..cdc00313 --- /dev/null +++ b/gitea-dump-backup.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# Gitea Dump Backup Script +# Backs up Gitea using the native 'gitea dump' command and transfers to remote storage + +set -euo pipefail + +# Configuration +BACKUP_DIR="./gitea-backups" +REMOTE_HOST="workstation" +REMOTE_PATH="/mnt/data/git-backups" +REMOTE_USER="${REMOTE_USER:-$(whoami)}" +CONTAINER_NAME="${CONTAINER_NAME:-gitea}" +KEEP_LOCAL="${KEEP_LOCAL:-3}" +LOG_FILE="${LOG_FILE:-/var/log/gitea-backup.log}" + +# Timestamps +DATE=$(date +%Y%m%d) +TIMESTAMP=$(date +%Y%m%d_%H%M%S) + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" +} + +error() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*" | tee -a "$LOG_FILE" >&2 + exit 1 +} + +# Ensure local backup directory exists +mkdir -p "$BACKUP_DIR" + +log "Starting Gitea backup process..." + +# Step 1: Execute gitea dump inside the container +log "Creating Gitea dump inside container..." +CONTAINER_DUMP_PATH="/data/gitea-dump-${TIMESTAMP}.zip" + +docker exec -u 1000 -i "$CONTAINER_NAME" bash -c "/app/gitea/gitea dump -c /data/gitea/conf/app.ini -f ${CONTAINER_DUMP_PATH}" \ + || error "Failed to execute gitea dump command" + +log "Dump created in container at: $CONTAINER_DUMP_PATH" + +# Step 2: Copy the archive from container to host +LOCAL_BACKUP="${BACKUP_DIR}/gitea-dump-${TIMESTAMP}.zip" +log "Copying backup from container to host..." + +docker cp "${CONTAINER_NAME}:${CONTAINER_DUMP_PATH}" "$LOCAL_BACKUP" \ + || error "Failed to copy backup from container" + +log "Backup saved locally: $LOCAL_BACKUP" + +# Step 3: Clean up the dump file inside the container +log "Cleaning up container dump file..." +docker exec "$CONTAINER_NAME" rm -f "$CONTAINER_DUMP_PATH" || log "Warning: Failed to clean up container dump file (non-fatal)" + +# Step 4: Upload to remote workstation +log "Uploading backup to remote storage (${REMOTE_HOST}:${REMOTE_PATH})..." +if ssh "$REMOTE_USER@$REMOTE_HOST" "test -d $REMOTE_PATH"; then + rsync -avz --progress "$LOCAL_BACKUP" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/" \ + || error "Failed to upload backup to remote storage" + log "Backup uploaded successfully" +else + error "Remote backup directory does not exist: ${REMOTE_HOST}:${REMOTE_PATH}" +fi + +# Step 5: Clean up old local backups (keep only KEEP_LOCAL most recent) +log "Cleaning up old local backups (keeping last $KEEP_LOCAL)..." +cd "$BACKUP_DIR" || error "Cannot access backup directory" +ls -t gitea-dump-*.zip 2>/dev/null | tail -n +$((KEEP_LOCAL + 1)) | xargs -r rm -f +log "Local cleanup complete" + +# Final status +log "Backup completed successfully!" +log "Backup file: $(ls -lh "$LOCAL_BACKUP" | awk '{print $5, $9}')" + +exit 0