#!/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)"