Set up encrypted MariaDB backups using Mariabackup with AES encryption, automated scheduling, and verified restoration procedures for secure database protection.
Prerequisites
- MariaDB server running
- Root or sudo access
- At least 2GB free disk space for backups
What this solves
MariaDB Mariabackup provides encrypted hot backups without database downtime, protecting sensitive data at rest and during transfer. This tutorial sets up AES-256 encryption for automated backups with verification and restoration procedures.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of MariaDB backup tools.
sudo apt update && sudo apt upgrade -y
Install MariaDB backup tools
Install Mariabackup and required encryption utilities for secure backup operations.
sudo apt install -y mariadb-backup openssl qpress
Create backup directories and set permissions
Set up dedicated directories for backups with proper ownership for the mysql user.
sudo mkdir -p /var/backup/mariadb/{full,incremental,keys}
sudo chown -R mysql:mysql /var/backup/mariadb
sudo chmod 750 /var/backup/mariadb
sudo chmod 700 /var/backup/mariadb/keys
Generate encryption keys
Create a strong encryption key for backup encryption and store it securely.
sudo openssl rand -base64 32 | sudo tee /var/backup/mariadb/keys/backup.key
sudo chown mysql:mysql /var/backup/mariadb/keys/backup.key
sudo chmod 600 /var/backup/mariadb/keys/backup.key
Configure MariaDB backup user
Create a dedicated database user with minimum required privileges for backup operations.
sudo mysql -u root -p
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'SecureBackupPass2024!';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON . TO 'backup_user'@'localhost';
GRANT PROCESS ON . TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Create backup credentials file
Store database credentials securely to avoid exposing passwords in scripts.
[client]
user=backup_user
password=SecureBackupPass2024!
host=localhost
port=3306
sudo chown mysql:mysql /var/backup/mariadb/.my.cnf
sudo chmod 600 /var/backup/mariadb/.my.cnf
Create encrypted backup script
Develop a comprehensive backup script with encryption, compression, and error handling.
#!/bin/bash
MariaDB Encrypted Backup Script
Usage: mariadb-encrypted-backup.sh [full|incremental]
set -euo pipefail
Configuration
BACKUP_DIR="/var/backup/mariadb"
KEY_FILE="${BACKUP_DIR}/keys/backup.key"
CREDENTIALS="${BACKUP_DIR}/.my.cnf"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="${BACKUP_DIR}/backup_${DATE}.log"
RETENTION_DAYS=30
Functions
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
cleanup_old_backups() {
log "Cleaning up backups older than ${RETENTION_DAYS} days"
find "${BACKUP_DIR}/full" -name "*.tar.gz.enc" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}/incremental" -name "*.tar.gz.enc" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -name "backup_*.log" -mtime +${RETENTION_DAYS} -delete
}
perform_backup() {
local backup_type="$1"
local backup_subdir="${BACKUP_DIR}/${backup_type}"
local backup_name="mariadb_${backup_type}_${DATE}"
local temp_backup="${backup_subdir}/${backup_name}"
log "Starting ${backup_type} backup: ${backup_name}"
mkdir -p "$backup_subdir"
# Perform backup based on type
if [ "$backup_type" = "full" ]; then
mariabackup --defaults-file="$CREDENTIALS" \
--backup \
--compress \
--compress-threads=4 \
--target-dir="$temp_backup" 2>&1 | tee -a "$LOG_FILE"
else
# Incremental backup
local latest_full=$(find "${BACKUP_DIR}/full" -name "mariadb_full_*" -type d | sort -r | head -n1)
if [ -z "$latest_full" ]; then
log "ERROR: No full backup found for incremental backup"
exit 1
fi
mariabackup --defaults-file="$CREDENTIALS" \
--backup \
--compress \
--compress-threads=4 \
--target-dir="$temp_backup" \
--incremental-basedir="$latest_full" 2>&1 | tee -a "$LOG_FILE"
fi
# Compress and encrypt backup
log "Compressing and encrypting backup"
tar -czf "${temp_backup}.tar.gz" -C "$backup_subdir" "$(basename "$temp_backup")"
openssl enc -aes-256-cbc -salt -in "${temp_backup}.tar.gz" \
-out "${temp_backup}.tar.gz.enc" -pass file:"$KEY_FILE"
# Verify encryption
if [ -f "${temp_backup}.tar.gz.enc" ]; then
log "Backup encrypted successfully: ${temp_backup}.tar.gz.enc"
log "Backup size: $(du -h "${temp_backup}.tar.gz.enc" | cut -f1)"
# Clean up temporary files
rm -rf "$temp_backup" "${temp_backup}.tar.gz"
else
log "ERROR: Encryption failed"
exit 1
fi
}
Main execution
main() {
local backup_type="${1:-full}"
# Validate backup type
if [ "$backup_type" != "full" ] && [ "$backup_type" != "incremental" ]; then
echo "Usage: $0 [full|incremental]"
exit 1
fi
# Check prerequisites
if [ ! -f "$KEY_FILE" ]; then
log "ERROR: Encryption key not found at $KEY_FILE"
exit 1
fi
if [ ! -f "$CREDENTIALS" ]; then
log "ERROR: Credentials file not found at $CREDENTIALS"
exit 1
fi
log "Starting MariaDB ${backup_type} backup process"
perform_backup "$backup_type"
cleanup_old_backups
log "Backup process completed successfully"
}
main "$@"
sudo chmod 750 /usr/local/bin/mariadb-encrypted-backup.sh
sudo chown mysql:mysql /usr/local/bin/mariadb-encrypted-backup.sh
Create automated restoration script
Build a restoration script that handles decryption, decompression, and database preparation.
#!/bin/bash
MariaDB Encrypted Restore Script
Usage: mariadb-encrypted-restore.sh [target_directory]
set -euo pipefail
Configuration
BACKUP_DIR="/var/backup/mariadb"
KEY_FILE="${BACKUP_DIR}/keys/backup.key"
RESTORE_DIR="/var/restore/mariadb"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="${BACKUP_DIR}/restore_${DATE}.log"
Functions
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
verify_backup() {
local encrypted_file="$1"
log "Verifying encrypted backup file: $encrypted_file"
if [ ! -f "$encrypted_file" ]; then
log "ERROR: Backup file not found: $encrypted_file"
exit 1
fi
# Test decryption without extracting
if ! openssl enc -aes-256-cbc -d -in "$encrypted_file" \
-pass file:"$KEY_FILE" | head -c 1 > /dev/null 2>&1; then
log "ERROR: Cannot decrypt backup file. Check encryption key."
exit 1
fi
log "Backup file verification successful"
}
restore_backup() {
local encrypted_file="$1"
local target_dir="${2:-${RESTORE_DIR}}"
local temp_dir="${target_dir}/temp_${DATE}"
log "Starting restoration process"
log "Source: $encrypted_file"
log "Target: $target_dir"
# Create restoration directory
mkdir -p "$temp_dir"
# Decrypt and decompress
log "Decrypting and extracting backup"
openssl enc -aes-256-cbc -d -in "$encrypted_file" \
-pass file:"$KEY_FILE" | tar -xzf - -C "$temp_dir"
# Find the backup directory
local backup_content=$(find "$temp_dir" -maxdepth 1 -type d -name "mariadb_*" | head -n1)
if [ -z "$backup_content" ]; then
log "ERROR: No backup content found in extracted archive"
exit 1
fi
log "Backup extracted to: $backup_content"
# Prepare backup (decompress individual files)
log "Preparing backup for restoration"
mariabackup --decompress --target-dir="$backup_content"
# Remove compressed files
find "$backup_content" -name "*.qp" -delete
# Prepare the backup
log "Applying log files to backup"
mariabackup --prepare --target-dir="$backup_content"
log "Backup prepared successfully at: $backup_content"
log "To complete restoration, stop MariaDB and copy files to datadir"
log "Example commands:"
log " sudo systemctl stop mariadb"
log " sudo mv /var/lib/mysql /var/lib/mysql.backup"
log " sudo mariabackup --copy-back --target-dir=$backup_content"
log " sudo chown -R mysql:mysql /var/lib/mysql"
log " sudo systemctl start mariadb"
}
Main execution
main() {
if [ $# -lt 1 ]; then
echo "Usage: $0 [target_directory]"
echo "Example: $0 /var/backup/mariadb/full/mariadb_full_20240115_120000.tar.gz.enc"
exit 1
fi
local encrypted_file="$1"
local target_dir="${2:-${RESTORE_DIR}}"
# Check prerequisites
if [ ! -f "$KEY_FILE" ]; then
log "ERROR: Encryption key not found at $KEY_FILE"
exit 1
fi
verify_backup "$encrypted_file"
restore_backup "$encrypted_file" "$target_dir"
log "Restoration preparation completed successfully"
}
main "$@"
sudo chmod 750 /usr/local/bin/mariadb-encrypted-restore.sh
sudo chown mysql:mysql /usr/local/bin/mariadb-encrypted-restore.sh
Set up automated scheduling
Configure systemd timers for regular encrypted backups with different frequencies.
[Unit]
Description=MariaDB Full Encrypted Backup
Requires=mariadb.service
After=mariadb.service
[Service]
Type=oneshot
User=mysql
Group=mysql
ExecStart=/usr/local/bin/mariadb-encrypted-backup.sh full
TimeoutStartSec=3600
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/backup/mariadb
[Unit]
Description=Run MariaDB full backup weekly
Requires=mariadb-backup-full.service
[Timer]
OnCalendar=Sun 02:00
Persistent=true
RandomizedDelaySec=1800
[Install]
WantedBy=timers.target
[Unit]
Description=MariaDB Incremental Encrypted Backup
Requires=mariadb.service
After=mariadb.service
[Service]
Type=oneshot
User=mysql
Group=mysql
ExecStart=/usr/local/bin/mariadb-encrypted-backup.sh incremental
TimeoutStartSec=1800
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/backup/mariadb
[Unit]
Description=Run MariaDB incremental backup daily
Requires=mariadb-backup-incremental.service
[Timer]
OnCalendar=--* 02:30
Persistent=true
RandomizedDelaySec=900
[Install]
WantedBy=timers.target
Enable backup timers
Activate the systemd timers to start automated backup scheduling.
sudo systemctl daemon-reload
sudo systemctl enable --now mariadb-backup-full.timer
sudo systemctl enable --now mariadb-backup-incremental.timer
Create backup verification script
Build a verification script to regularly test backup integrity and restoration capability.
#!/bin/bash
MariaDB Backup Verification Script
set -euo pipefail
BACKUP_DIR="/var/backup/mariadb"
VERIFY_LOG="${BACKUP_DIR}/verify_$(date +%Y%m%d_%H%M%S).log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$VERIFY_LOG"
}
verify_latest_backup() {
local backup_type="$1"
local latest_backup=$(find "${BACKUP_DIR}/${backup_type}" -name "*.tar.gz.enc" -type f | sort -r | head -n1)
if [ -z "$latest_backup" ]; then
log "WARNING: No ${backup_type} backup found"
return 1
fi
log "Verifying ${backup_type} backup: $(basename "$latest_backup")"
# Test decryption
if /usr/local/bin/mariadb-encrypted-restore.sh "$latest_backup" "/tmp/verify_${backup_type}_$$" > /dev/null 2>&1; then
log "✓ ${backup_type} backup verification successful"
rm -rf "/tmp/verify_${backup_type}_$$"
return 0
else
log "✗ ${backup_type} backup verification failed"
return 1
fi
}
Main verification
log "Starting backup verification"
verify_latest_backup "full"
verify_latest_backup "incremental"
log "Backup verification completed"
sudo chmod 750 /usr/local/bin/mariadb-backup-verify.sh
sudo chown mysql:mysql /usr/local/bin/mariadb-backup-verify.sh
Verify your setup
Test the backup system to ensure encryption and restoration work correctly.
# Check timer status
sudo systemctl list-timers --all | grep mariadb-backup
Test manual full backup
sudo -u mysql /usr/local/bin/mariadb-encrypted-backup.sh full
Verify backup was created
ls -la /var/backup/mariadb/full/
Test backup verification
sudo -u mysql /usr/local/bin/mariadb-backup-verify.sh
Check backup logs
tail -f /var/backup/mariadb/backup_*.log
Test the restoration process with a sample backup:
# Find latest backup
latest_backup=$(find /var/backup/mariadb/full -name "*.tar.gz.enc" | sort -r | head -n1)
echo "Testing restoration of: $latest_backup"
Test restoration (preparation only)
sudo -u mysql /usr/local/bin/mariadb-encrypted-restore.sh "$latest_backup" "/tmp/test_restore"
Verify restored files
ls -la /tmp/test_restore/
Clean up test
sudo rm -rf /tmp/test_restore
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Permission denied errors | Incorrect file ownership | sudo chown -R mysql:mysql /var/backup/mariadb |
| Encryption key error | Missing or corrupted key file | Regenerate key: sudo openssl rand -base64 32 > /var/backup/mariadb/keys/backup.key |
| Backup authentication failed | Invalid database credentials | Check /var/backup/mariadb/.my.cnf and user privileges |
| Timer not running | Systemd timer not enabled | sudo systemctl enable --now mariadb-backup-full.timer |
| Out of disk space | Backup retention not working | Adjust RETENTION_DAYS in backup script |
| Restore preparation fails | Corrupt backup or missing dependencies | Verify backup integrity and install qpress |
Next steps
- Monitor MariaDB performance to track backup impact on database operations
- Set up MariaDB Galera clustering for high availability with replicated backups
- Configure backup monitoring with Prometheus for automated backup verification alerts
- Configure offsite backup replication with S3 for disaster recovery
- Implement advanced backup retention policies with automated lifecycle management
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# MariaDB Encrypted Backup Installation Script
# Installs and configures MariaDB backup encryption with Mariabackup
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
BACKUP_USER="backup_user"
BACKUP_PASS="SecureBackupPass2024!"
BACKUP_DIR="/var/backup/mariadb"
TOTAL_STEPS=8
# Usage
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -p PASSWORD Set backup user password (default: SecureBackupPass2024!)"
echo " -h Show this help"
exit 1
}
# Parse arguments
while getopts "p:h" opt; do
case $opt in
p) BACKUP_PASS="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Cleanup on error
cleanup() {
log_error "Installation failed. Cleaning up..."
rm -rf "$BACKUP_DIR" 2>/dev/null || true
}
trap cleanup ERR
# Check prerequisites
check_prerequisites() {
echo "[1/$TOTAL_STEPS] Checking prerequisites..."
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
if ! command -v mysql >/dev/null 2>&1; then
log_error "MariaDB/MySQL is not installed. Please install MariaDB first."
exit 1
fi
log_info "Prerequisites check passed"
}
# Detect distribution
detect_distro() {
echo "[2/$TOTAL_STEPS] Detecting distribution..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
log_info "Detected distribution: $PRETTY_NAME"
log_info "Package manager: $PKG_MGR"
}
# Update system packages
update_system() {
echo "[3/$TOTAL_STEPS] Updating system packages..."
log_info "Updating package repository..."
$PKG_UPDATE
log_info "System packages updated"
}
# Install MariaDB backup tools
install_backup_tools() {
echo "[4/$TOTAL_STEPS] Installing MariaDB backup tools..."
log_info "Installing mariadb-backup, openssl, and qpress..."
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL mariadb-backup openssl qpress
else
# For RHEL-based systems, qpress might be in EPEL
$PKG_INSTALL mariadb-backup openssl
# Try to install qpress, but don't fail if not available
if ! $PKG_INSTALL qpress 2>/dev/null; then
log_warn "qpress not available in standard repositories. You may need to install it manually."
fi
fi
log_info "Backup tools installed successfully"
}
# Create backup directories
create_backup_directories() {
echo "[5/$TOTAL_STEPS] Creating backup directories..."
log_info "Creating backup directory structure..."
mkdir -p "$BACKUP_DIR"/{full,incremental,keys}
# Set proper ownership and permissions
chown -R mysql:mysql "$BACKUP_DIR"
chmod 750 "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR/keys"
log_info "Backup directories created with proper permissions"
}
# Generate encryption keys
generate_encryption_key() {
echo "[6/$TOTAL_STEPS] Generating encryption key..."
local key_file="$BACKUP_DIR/keys/backup.key"
log_info "Generating 256-bit encryption key..."
openssl rand -base64 32 > "$key_file"
# Secure the key file
chown mysql:mysql "$key_file"
chmod 600 "$key_file"
log_info "Encryption key generated and secured"
}
# Configure MariaDB backup user
configure_backup_user() {
echo "[7/$TOTAL_STEPS] Configuring MariaDB backup user..."
log_info "Creating backup user with required privileges..."
mysql -u root << EOF
CREATE USER IF NOT EXISTS '${BACKUP_USER}'@'localhost' IDENTIFIED BY '${BACKUP_PASS}';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO '${BACKUP_USER}'@'localhost';
GRANT PROCESS ON *.* TO '${BACKUP_USER}'@'localhost';
FLUSH PRIVILEGES;
EOF
# Create credentials file
local cred_file="$BACKUP_DIR/.my.cnf"
cat > "$cred_file" << EOF
[client]
user=${BACKUP_USER}
password=${BACKUP_PASS}
host=localhost
port=3306
EOF
chown mysql:mysql "$cred_file"
chmod 600 "$cred_file"
log_info "Backup user configured successfully"
}
# Create backup script
create_backup_script() {
echo "[8/$TOTAL_STEPS] Creating encrypted backup script..."
local script_file="/usr/local/bin/mariadb-encrypted-backup"
cat > "$script_file" << 'EOF'
#!/bin/bash
# MariaDB Encrypted Backup Script
# Usage: mariadb-encrypted-backup [full|incremental]
set -euo pipefail
# Configuration
BACKUP_DIR="/var/backup/mariadb"
KEY_FILE="${BACKUP_DIR}/keys/backup.key"
CREDENTIALS="${BACKUP_DIR}/.my.cnf"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="${BACKUP_DIR}/backup_${DATE}.log"
RETENTION_DAYS=30
# Functions
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
cleanup_old_backups() {
log "Cleaning up backups older than ${RETENTION_DAYS} days"
find "${BACKUP_DIR}/full" -name "*.tar.gz.enc" -mtime +${RETENTION_DAYS} -delete 2>/dev/null || true
find "${BACKUP_DIR}/incremental" -name "*.tar.gz.enc" -mtime +${RETENTION_DAYS} -delete 2>/dev/null || true
find "${BACKUP_DIR}" -name "backup_*.log" -mtime +${RETENTION_DAYS} -delete 2>/dev/null || true
}
perform_backup() {
local backup_type="$1"
local backup_subdir="${BACKUP_DIR}/${backup_type}"
local backup_name="mariadb_${backup_type}_${DATE}"
local temp_backup="${backup_subdir}/${backup_name}"
local archive_file="${temp_backup}.tar.gz"
local encrypted_file="${archive_file}.enc"
log "Starting ${backup_type} backup: ${backup_name}"
mkdir -p "$backup_subdir"
# Perform backup
if [ "$backup_type" = "full" ]; then
mariabackup --defaults-file="$CREDENTIALS" \
--backup \
--target-dir="$temp_backup"
fi
# Prepare backup
log "Preparing backup..."
mariabackup --prepare --target-dir="$temp_backup"
# Compress backup
log "Compressing backup..."
tar -czf "$archive_file" -C "$backup_subdir" "$(basename "$temp_backup")"
# Encrypt backup
log "Encrypting backup..."
openssl enc -aes-256-cbc -salt -in "$archive_file" -out "$encrypted_file" -pass file:"$KEY_FILE"
# Cleanup temporary files
rm -rf "$temp_backup" "$archive_file"
log "Backup completed: $encrypted_file"
log "Backup size: $(du -h "$encrypted_file" | cut -f1)"
}
# Main execution
BACKUP_TYPE="${1:-full}"
if [ "$BACKUP_TYPE" != "full" ] && [ "$BACKUP_TYPE" != "incremental" ]; then
echo "Usage: $0 [full|incremental]"
exit 1
fi
log "Starting MariaDB encrypted backup (${BACKUP_TYPE})"
# Check if running as mysql user
if [ "$(id -u)" != "$(id -u mysql)" ]; then
echo "This script should be run as the mysql user"
echo "Use: sudo -u mysql $0 $*"
exit 1
fi
perform_backup "$BACKUP_TYPE"
cleanup_old_backups
log "Backup process completed successfully"
EOF
chmod 750 "$script_file"
chown mysql:mysql "$script_file"
log_info "Backup script created at $script_file"
}
# Verify installation
verify_installation() {
echo
log_info "Verifying installation..."
# Check if directories exist
if [[ -d "$BACKUP_DIR" ]]; then
log_info "✓ Backup directories created"
else
log_error "✗ Backup directories missing"
return 1
fi
# Check if key file exists
if [[ -f "$BACKUP_DIR/keys/backup.key" ]]; then
log_info "✓ Encryption key generated"
else
log_error "✗ Encryption key missing"
return 1
fi
# Check if credentials file exists
if [[ -f "$BACKUP_DIR/.my.cnf" ]]; then
log_info "✓ Database credentials configured"
else
log_error "✗ Database credentials missing"
return 1
fi
# Test database connection
if mysql --defaults-file="$BACKUP_DIR/.my.cnf" -e "SELECT 1" >/dev/null 2>&1; then
log_info "✓ Database connection successful"
else
log_error "✗ Database connection failed"
return 1
fi
# Check if backup script exists
if [[ -x "/usr/local/bin/mariadb-encrypted-backup" ]]; then
log_info "✓ Backup script installed"
else
log_error "✗ Backup script missing"
return 1
fi
echo
log_info "Installation completed successfully!"
echo
echo "Next steps:"
echo "1. Test backup: sudo -u mysql /usr/local/bin/mariadb-encrypted-backup full"
echo "2. Add to crontab for automated backups"
echo "3. Backup encryption key: $BACKUP_DIR/keys/backup.key"
echo
}
# Main execution
main() {
check_prerequisites
detect_distro
update_system
install_backup_tools
create_backup_directories
generate_encryption_key
configure_backup_user
create_backup_script
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh