2weekmail/backup.sh
2025-03-23 13:14:14 +00:00

217 lines
6.6 KiB
Bash
Executable File

#!/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=(
"/opt/2weekmail"
)
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 ""