217 lines
6.6 KiB
Bash
217 lines
6.6 KiB
Bash
#!/bin/bash
|
|
|
|
# Load environment variables from .env file
|
|
if [ -f .env ]; then
|
|
# Read each line from .env and export variables
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
# Skip comments and empty lines
|
|
[[ $line =~ ^#.*$ ]] && continue
|
|
[[ -z "$line" ]] && continue
|
|
|
|
# Export the variable
|
|
export "$line"
|
|
done < .env
|
|
else
|
|
echo "Error: .env file not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Variables (now using environment variables with defaults)
|
|
MYSQL_USER="admin"
|
|
MYSQL_PASSWORD=${MYSQL_ADMIN_PASSWORD}
|
|
BACKUP_DIR="$(pwd)/backups"
|
|
REMOTE_HOST="${BACKUP_SERVER_HOST}" # Remote server hostname/IP
|
|
REMOTE_USER="${BACKUP_SERVER_USER}" # Remote server username
|
|
REMOTE_BACKUP_DIR="${BACKUP_SERVER_PATH}" # Remote server backup path
|
|
TEMP_DIR="$BACKUP_DIR/tmp"
|
|
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
|
|
MODE=""
|
|
HOURLY_RETENTION=4
|
|
DAILY_RETENTION=3
|
|
WEEKLY_RETENTION=1
|
|
MIN_SPACE=20 # Minimum space in GB
|
|
DB_CONTAINER="mailserver_db"
|
|
|
|
# Function to display usage
|
|
function usage() {
|
|
echo "Usage: $0 --hourly | --daily | --weekly"
|
|
exit 1
|
|
}
|
|
|
|
# Function to check available space and cleanup if necessary
|
|
function check_and_cleanup_space() {
|
|
local available_space=$(df -BG "$REMOTE_BACKUP_DIR" | awk 'NR==2 {gsub("G","",$4); print $4}')
|
|
|
|
if [ "$available_space" -le "$MIN_SPACE" ]; then
|
|
echo "Available space ($available_space GB) is less than minimum required ($MIN_SPACE GB)"
|
|
echo "Starting cleanup..."
|
|
|
|
while [ "$available_space" -le "$MIN_SPACE" ]; do
|
|
# Find oldest backup file
|
|
oldest_file=$(find "$REMOTE_BACKUP_DIR" -type f -name "*.zip" -printf '%T+ %p\n' | sort | head -n 1 | awk '{print $2}')
|
|
|
|
if [ -z "$oldest_file" ]; then
|
|
echo "No more files to delete!"
|
|
break
|
|
fi
|
|
|
|
# Get file size before deletion for logging
|
|
file_size=$(du -h "$oldest_file" | cut -f1)
|
|
|
|
# Delete the file
|
|
rm -f "$oldest_file"
|
|
echo "Deleted old backup: $oldest_file (Size: $file_size)"
|
|
|
|
# Recalculate available space
|
|
available_space=$(df -BG "$REMOTE_BACKUP_DIR" | awk 'NR==2 {gsub("G","",$4); print $4}')
|
|
done
|
|
|
|
echo "Cleanup complete. Available space: $available_space GB"
|
|
fi
|
|
}
|
|
|
|
echo "##########################"
|
|
echo "Starting backup..."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
# Check if the correct parameter is passed
|
|
if [[ "$1" == "--hourly" ]]; then
|
|
MODE="hourly"
|
|
elif [[ "$1" == "--daily" ]]; then
|
|
MODE="daily"
|
|
elif [[ "$1" == "--weekly" ]]; then
|
|
MODE="weekly"
|
|
else
|
|
usage
|
|
fi
|
|
echo "##########################"
|
|
echo "Mode: $MODE"
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
echo "##########################"
|
|
echo "Creating backup directories..."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
# Create backup and temp directories if they don't exist
|
|
mkdir -p "$BACKUP_DIR"
|
|
mkdir -p "$TEMP_DIR"
|
|
mkdir -p "/var/log/backup"
|
|
|
|
# Backup all MySQL databases
|
|
echo "##########################"
|
|
echo "Backing up MySQL databases..."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
# Test database connection first
|
|
if ! docker exec -i $DB_CONTAINER mariadb -u $MYSQL_USER -p${MYSQL_PASSWORD} -e "SELECT 1;" >/dev/null 2>&1; then
|
|
echo "Error: Cannot connect to MySQL database. Please check credentials."
|
|
echo "Container: $DB_CONTAINER"
|
|
echo "User: $MYSQL_USER"
|
|
echo "Password being used: ${MYSQL_PASSWORD}"
|
|
exit 1
|
|
fi
|
|
|
|
# Get databases list without using -it flag (which requires terminal)
|
|
databases=$(docker exec -i $DB_CONTAINER mariadb -u $MYSQL_USER -p${MYSQL_PASSWORD} -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
|
|
|
|
for db in $databases; do
|
|
echo "Backing up database: $db"
|
|
docker exec -i $DB_CONTAINER mariadb-dump -u $MYSQL_USER -p${MYSQL_PASSWORD} --databases "$db" > "$TEMP_DIR/${db}.sql"
|
|
if [ $? -eq 0 ]; then
|
|
zip -j "$TEMP_DIR/${db}.sql.zip" "$TEMP_DIR/${db}.sql"
|
|
rm "$TEMP_DIR/${db}.sql"
|
|
else
|
|
echo "Error backing up database: $db"
|
|
fi
|
|
done
|
|
|
|
DIRECTORIES_TO_BACKUP=(
|
|
"/root/isekai"
|
|
)
|
|
|
|
for dir in "${DIRECTORIES_TO_BACKUP[@]}"; do
|
|
DIR_NAME=$(basename "$dir")
|
|
zip -r "$TEMP_DIR/${DIR_NAME}_${MODE}_$TIMESTAMP.zip" "$dir" -x "*/node_modules/*" "*/backups/*"
|
|
done
|
|
|
|
# Compress all SQL and directories into a single zip file
|
|
echo "##########################"
|
|
echo "Compressing backup files..."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
FINAL_BACKUP_FILE="$BACKUP_DIR/${MODE}_backup_$TIMESTAMP.zip"
|
|
find "$TEMP_DIR" -name "*.zip" | while read file; do
|
|
zip -ur "$FINAL_BACKUP_FILE" "$file"
|
|
done
|
|
|
|
# Clean up temporary files
|
|
rm -rf "$TEMP_DIR"
|
|
|
|
echo "##########################"
|
|
echo "Backup complete: $FINAL_BACKUP_FILE"
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
function apply_retention() {
|
|
backup_type=$1
|
|
retention_count=$2
|
|
|
|
# Find all backup files of the specified type, sort them by modification time, and keep the newest
|
|
backups=($(ls -t $BACKUP_DIR/${backup_type}_backup_*.zip))
|
|
|
|
# If the number of backups exceeds the retention limit, delete the older ones
|
|
if [ ${#backups[@]} -gt $retention_count ]; then
|
|
delete_count=$((${#backups[@]} - $retention_count))
|
|
for (( i=$retention_count; i<${#backups[@]}; i++ )); do
|
|
rm -f "${backups[$i]}"
|
|
echo "Deleted old $backup_type backup: ${backups[$i]}"
|
|
done
|
|
fi
|
|
}
|
|
|
|
echo "##########################"
|
|
echo "Applying retention policy..."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
# Apply retention policy
|
|
if [[ "$MODE" == "hourly" ]]; then
|
|
apply_retention "hourly" $HOURLY_RETENTION
|
|
elif [[ "$MODE" == "daily" ]]; then
|
|
apply_retention "daily" $DAILY_RETENTION
|
|
elif [[ "$MODE" == "weekly" ]]; then
|
|
apply_retention "weekly" $WEEKLY_RETENTION
|
|
fi
|
|
|
|
echo "Retention policy applied: $MODE backups cleaned."
|
|
echo "##########################"
|
|
echo "Backup cleanup complete."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
echo "##########################"
|
|
echo "Checking remote backup space..."
|
|
echo "##########################"
|
|
echo ""
|
|
|
|
# Check and cleanup space before copying new backup
|
|
check_and_cleanup_space
|
|
|
|
# Use rsync to copy the backup
|
|
if ! ssh -p "$BACKUP_SERVER_PORT" "${REMOTE_USER}@${REMOTE_HOST}" exit 2>/dev/null; then
|
|
echo "Error: Cannot connect to remote backup server"
|
|
echo "Backup file is saved locally at: $FINAL_BACKUP_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
rsync -av --progress -e "ssh -p $BACKUP_SERVER_PORT" "$FINAL_BACKUP_FILE" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_BACKUP_DIR}/"
|
|
|
|
echo "##########################"
|
|
echo "Remote backup complete"
|
|
echo "##########################"
|
|
echo "" |