diff --git a/backup-gitea.sh b/backup-gitea.sh new file mode 100644 index 0000000..51192da --- /dev/null +++ b/backup-gitea.sh @@ -0,0 +1,267 @@ +#!/bin/bash + +# backup-gitea.sh - Backup Gitea data and PostgreSQL database +# Author: Shell Repository +# Description: Comprehensive backup solution for Gitea with PostgreSQL database + +set -e + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BACKUP_DIR="/home/acedanger/backups/gitea" +COMPOSE_DIR="/home/acedanger/docker/gitea" +COMPOSE_FILE="$COMPOSE_DIR/docker-compose.yml" +LOG_FILE="$SCRIPT_DIR/logs/gitea-backup.log" + +# Ensure logs directory exists +mkdir -p "$(dirname "$LOG_FILE")" + +# Logging function +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" +} + +# Display usage information +usage() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Backup Gitea data and PostgreSQL database" + echo "" + echo "Options:" + echo " -h, --help Show this help message" + echo " -d, --dry-run Show what would be backed up without doing it" + echo " -f, --force Force backup even if one was recently created" + echo " -r, --restore FILE Restore from specified backup directory" + echo " -l, --list List available backups" + echo " -c, --cleanup Clean up old backups (keeps last 7 days)" + echo " --keep-days DAYS Number of days to keep backups (default: 7)" + echo "" + echo "Examples:" + echo " $0 # Regular backup" + echo " $0 --dry-run # See what would be backed up" + echo " $0 --list # List available backups" + echo " $0 --restore /path/to/backup # Restore from backup" +} + +# Check dependencies +check_dependencies() { + local missing_deps=() + + command -v docker >/dev/null 2>&1 || missing_deps+=("docker") + command -v docker-compose >/dev/null 2>&1 || missing_deps+=("docker-compose") + + if [ ${#missing_deps[@]} -ne 0 ]; then + echo -e "${RED}Error: Missing required dependencies: ${missing_deps[*]}${NC}" + echo "Please install the missing dependencies and try again." + exit 1 + fi + + # Check if docker-compose file exists + if [ ! -f "$COMPOSE_FILE" ]; then + echo -e "${RED}Error: Docker compose file not found at $COMPOSE_FILE${NC}" + exit 1 + fi + + # Check if we can access Docker + if ! docker info >/dev/null 2>&1; then + echo -e "${RED}Error: Cannot access Docker. Check if Docker is running and you have permissions.${NC}" + exit 1 + fi +} + +# Check if Gitea services are running +check_gitea_services() { + cd "$COMPOSE_DIR" + + if ! docker-compose ps | grep -q "Up"; then + echo -e "${YELLOW}Warning: Gitea services don't appear to be running${NC}" + echo "Some backup operations may fail if services are not running." + read -p "Continue anyway? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Backup cancelled" + exit 1 + fi + fi +} + +# List available backups +list_backups() { + echo -e "${BLUE}=== Available Gitea Backups ===${NC}" + + if [ ! -d "$BACKUP_DIR" ]; then + echo -e "${YELLOW}No backup directory found at $BACKUP_DIR${NC}" + return 0 + fi + + local count=0 + + # Find backup directories + for backup_path in "$BACKUP_DIR"/gitea_backup_*; do + if [ -d "$backup_path" ]; then + local backup_name + backup_name=$(basename "$backup_path") + local backup_date + backup_date=$(echo "$backup_name" | sed 's/gitea_backup_//' | sed 's/_/ /') + local size + size=$(du -sh "$backup_path" 2>/dev/null | cut -f1) + local info_file="$backup_path/backup_info.txt" + + echo -e "${GREEN}📦 $backup_name${NC}" + echo " Date: $backup_date" + echo " Size: $size" + echo " Path: $backup_path" + + if [ -f "$info_file" ]; then + local gitea_version + gitea_version=$(grep "Gitea Version:" "$info_file" 2>/dev/null | cut -d: -f2- | xargs) + if [ -n "$gitea_version" ]; then + echo " Version: $gitea_version" + fi + fi + + echo "" + count=$((count + 1)) + fi + done + + if [ $count -eq 0 ]; then + echo -e "${YELLOW}No backups found in $BACKUP_DIR${NC}" + echo "Run a backup first to create one." + else + echo -e "${BLUE}Total backups found: $count${NC}" + fi +} + +# Change to compose directory +cd "$COMPOSE_DIR" + +# Create timestamped backup directory +BACKUP_PATH="$BACKUP_DIR/gitea_backup_$DATE" +mkdir -p "$BACKUP_PATH" + +# Backup PostgreSQL database +echo "Backing up PostgreSQL database..." +docker-compose exec -T db pg_dump -U ${POSTGRES_USER:-gitea} ${POSTGRES_DB:-gitea} > "$BACKUP_PATH/database.sql" + +# Backup Gitea data volume +echo "Backing up Gitea data volume..." +docker run --rm \ + -v gitea_gitea:/data:ro \ + -v "$BACKUP_PATH":/backup \ + alpine:latest \ + tar czf /backup/gitea_data.tar.gz -C /data . + +# Backup PostgreSQL data volume (optional, as we have the SQL dump) +echo "Backing up PostgreSQL data volume..." +docker run --rm \ + -v gitea_postgres:/data:ro \ + -v "$BACKUP_PATH":/backup \ + alpine:latest \ + tar czf /backup/postgres_data.tar.gz -C /data . + +# Copy docker-compose configuration +echo "Backing up configuration files..." +cp "$COMPOSE_FILE" "$BACKUP_PATH/" +if [ -f ".env" ]; then + cp ".env" "$BACKUP_PATH/" +fi + +# Create a restore script +cat > "$BACKUP_PATH/restore.sh" << 'EOF' +#!/bin/bash +# Restore script for Gitea backup + +set -e + +RESTORE_DIR="$(dirname "$0")" +COMPOSE_DIR="/home/acedanger/docker/gitea" + +echo "WARNING: This will stop Gitea and replace all data!" +read -p "Are you sure you want to continue? (yes/no): " confirm + +if [ "$confirm" != "yes" ]; then + echo "Restore cancelled" + exit 1 +fi + +cd "$COMPOSE_DIR" + +# Stop services +echo "Stopping Gitea services..." +docker-compose down + +# Remove existing volumes +echo "Removing existing volumes..." +docker volume rm gitea_gitea gitea_postgres || true + +# Recreate volumes +echo "Creating volumes..." +docker volume create gitea_gitea +docker volume create gitea_postgres + +# Restore Gitea data +echo "Restoring Gitea data..." +docker run --rm \ + -v gitea_gitea:/data \ + -v "$RESTORE_DIR":/backup:ro \ + alpine:latest \ + tar xzf /backup/gitea_data.tar.gz -C /data + +# Start database for restore +echo "Starting database for restore..." +docker-compose up -d db + +# Wait for database to be ready +echo "Waiting for database to be ready..." +sleep 10 + +# Restore database +echo "Restoring database..." +docker-compose exec -T db psql -U ${POSTGRES_USER:-gitea} -d ${POSTGRES_DB:-gitea} < "$RESTORE_DIR/database.sql" + +# Start all services +echo "Starting all services..." +docker-compose up -d + +echo "Restore completed!" +EOF + +chmod +x "$BACKUP_PATH/restore.sh" + +# Create info file +cat > "$BACKUP_PATH/backup_info.txt" << EOF +Gitea Backup Information +======================== +Backup Date: $(date) +Backup Location: $BACKUP_PATH +Gitea Version: $(docker-compose exec -T server gitea --version | head -1) +PostgreSQL Version: $(docker-compose exec -T db postgres --version) + +Files included: +- database.sql: PostgreSQL database dump +- gitea_data.tar.gz: Gitea data volume +- postgres_data.tar.gz: PostgreSQL data volume +- docker-compose.yml: Docker compose configuration +- .env: Environment variables (if exists) +- restore.sh: Restore script + +To restore this backup, run: +cd $BACKUP_PATH +./restore.sh +EOF + +# Cleanup old backups (keep last 7 days) +echo "Cleaning up old backups..." +find "$BACKUP_DIR" -type d -name "gitea_backup_*" -mtime +7 -exec rm -rf {} + 2>/dev/null || true + +echo "Backup completed successfully!" +echo "Backup saved to: $BACKUP_PATH" +echo "Backup size: $(du -sh "$BACKUP_PATH" | cut -f1)" \ No newline at end of file