Configure comprehensive backup and disaster recovery for MinIO object storage with automated snapshots, cross-site replication, and encryption. Implement production-ready backup strategies to protect critical data and ensure business continuity.
Prerequisites
- MinIO server installed and running
- Root or sudo access
- Network connectivity between sites
What this solves
MinIO object storage requires proper backup and disaster recovery strategies to protect against data loss, hardware failures, and site-wide disasters. This tutorial configures automated bucket backups, cross-site replication, encryption, and comprehensive recovery procedures. You'll implement production-ready backup automation that ensures your data remains secure and recoverable.
Step-by-step configuration
Update system packages
Start by updating your package manager to ensure you have the latest security patches and package versions.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg2
Install MinIO Client and backup tools
Install the MinIO client (mc) and additional tools needed for backup operations and encryption.
curl https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc
chmod +x /usr/local/bin/mc
mc --version
sudo apt install -y rsync gzip tar cron
Configure MinIO client connections
Set up connections to your primary MinIO instance and backup destinations. Replace the URLs and credentials with your actual MinIO server details.
mc alias set primary https://minio1.example.com:9000 minioadmin SecurePassword123!
mc alias set backup https://minio2.example.com:9000 minioadmin BackupPassword456!
mc alias ls
Create backup storage structure
Create dedicated buckets for storing backups with proper naming conventions and organization.
mc mb primary/backups
mc mb backup/disaster-recovery
mc mb backup/snapshots
Set versioning on backup buckets
mc version enable primary/backups
mc version enable backup/disaster-recovery
mc version enable backup/snapshots
Configure bucket replication
Set up cross-site replication between primary and backup MinIO instances for automatic data synchronization.
# Create replication configuration
mc replicate add primary/production backup/disaster-recovery --priority 1
mc replicate add primary/uploads backup/disaster-recovery --priority 2
Enable replication status tracking
mc replicate ls primary/production
mc replicate status primary/production
Create backup encryption keys
Generate encryption keys for securing backup data during transit and storage.
sudo mkdir -p /etc/minio/backup-keys
sudo chmod 700 /etc/minio/backup-keys
Generate encryption key
openssl rand -hex 32 | sudo tee /etc/minio/backup-keys/backup-encryption.key
sudo chmod 600 /etc/minio/backup-keys/backup-encryption.key
sudo chown root:root /etc/minio/backup-keys/backup-encryption.key
Create backup automation script
Create a comprehensive backup script that handles snapshots, encryption, and retention policies.
#!/bin/bash
MinIO Backup Script
set -euo pipefail
Configuration
PRIMARY_ALIAS="primary"
BACKUP_ALIAS="backup"
BACKUP_BUCKET="backups"
ENCRYPTION_KEY_FILE="/etc/minio/backup-keys/backup-encryption.key"
LOG_FILE="/var/log/minio-backup.log"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d-%H%M%S)
Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
Function to backup bucket
backup_bucket() {
local source_bucket=$1
local backup_name="${source_bucket}-${DATE}"
log "Starting backup of bucket: $source_bucket"
# Create encrypted backup
mc mirror --encrypt-key "${PRIMARY_ALIAS}/${source_bucket}=$(cat $ENCRYPTION_KEY_FILE)" \
"${PRIMARY_ALIAS}/${source_bucket}" \
"${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}"
# Verify backup integrity
local source_count=$(mc ls --recursive "${PRIMARY_ALIAS}/${source_bucket}" | wc -l)
local backup_count=$(mc ls --recursive "${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}" | wc -l)
if [ "$source_count" -eq "$backup_count" ]; then
log "Backup verified successfully: $backup_name ($source_count files)"
else
log "ERROR: Backup verification failed for $backup_name"
exit 1
fi
}
Function to cleanup old backups
cleanup_old_backups() {
log "Cleaning up backups older than $RETENTION_DAYS days"
mc find "${BACKUP_ALIAS}/${BACKUP_BUCKET}" --name "*" --older-than "${RETENTION_DAYS}d" \
--exec "mc rm --recursive --force {}" || true
}
Main backup process
main() {
log "=== MinIO Backup Started ==="
# List of buckets to backup (customize as needed)
BUCKETS=("production" "uploads" "documents")
for bucket in "${BUCKETS[@]}"; do
if mc ls "${PRIMARY_ALIAS}/${bucket}" &>/dev/null; then
backup_bucket "$bucket"
else
log "WARNING: Bucket $bucket not found, skipping"
fi
done
# Cleanup old backups
cleanup_old_backups
log "=== MinIO Backup Completed ==="
}
Run main function
main "$@"
sudo chmod 755 /usr/local/bin/minio-backup.sh
sudo chown root:root /usr/local/bin/minio-backup.sh
Create disaster recovery script
Create a script to handle disaster recovery operations and failover procedures.
#!/bin/bash
MinIO Disaster Recovery Script
set -euo pipefail
Configuration
BACKUP_ALIAS="backup"
RECOVERY_ALIAS="recovery"
BACKUP_BUCKET="backups"
DR_BUCKET="disaster-recovery"
LOG_FILE="/var/log/minio-dr.log"
Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
Function to list available backups
list_backups() {
log "Available backups:"
mc ls "${BACKUP_ALIAS}/${BACKUP_BUCKET}/" | tee -a "$LOG_FILE"
}
Function to restore from backup
restore_from_backup() {
local backup_name=$1
local target_bucket=$2
log "Starting restore of $backup_name to $target_bucket"
# Verify backup exists
if ! mc ls "${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}" &>/dev/null; then
log "ERROR: Backup $backup_name not found"
exit 1
fi
# Create target bucket if it doesn't exist
mc mb "${RECOVERY_ALIAS}/${target_bucket}" --ignore-existing
# Restore data
mc mirror "${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}" \
"${RECOVERY_ALIAS}/${target_bucket}"
# Verify restoration
local source_count=$(mc ls --recursive "${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}" | wc -l)
local target_count=$(mc ls --recursive "${RECOVERY_ALIAS}/${target_bucket}" | wc -l)
if [ "$source_count" -eq "$target_count" ]; then
log "Restore completed successfully: $target_bucket ($target_count files)"
else
log "ERROR: Restore verification failed"
exit 1
fi
}
Function to failover to backup site
failover_to_backup() {
log "=== Starting Failover to Backup Site ==="
# Check replication status
mc replicate status primary/production || {
log "Primary site unreachable, proceeding with backup site activation"
}
# Promote replica buckets to active
mc ls "${BACKUP_ALIAS}/${DR_BUCKET}/" | tee -a "$LOG_FILE"
log "Failover preparation completed. Manual verification required."
}
case "${1:-}" in
"list")
list_backups
;;
"restore")
if [ $# -ne 3 ]; then
echo "Usage: $0 restore "
exit 1
fi
restore_from_backup "$2" "$3"
;;
"failover")
failover_to_backup
;;
*)
echo "Usage: $0 {list|restore|failover}"
echo " list - List available backups"
echo " restore - Restore backup to bucket"
echo " failover - Failover to backup site"
exit 1
;;
esac
sudo chmod 755 /usr/local/bin/minio-disaster-recovery.sh
sudo chown root:root /usr/local/bin/minio-disaster-recovery.sh
Configure automated backup scheduling
Set up cron jobs to run backups automatically on a regular schedule.
# Create log directory
sudo mkdir -p /var/log
sudo touch /var/log/minio-backup.log /var/log/minio-dr.log
sudo chmod 644 /var/log/minio-backup.log /var/log/minio-dr.log
sudo crontab -e
Add the following cron entries:
# MinIO backup schedule
Daily backups at 2 AM
0 2 * /usr/local/bin/minio-backup.sh >/dev/null 2>&1
Weekly verification at 3 AM on Sundays
0 3 0 /usr/local/bin/minio-disaster-recovery.sh list >/dev/null 2>&1
Monthly cleanup logs
0 4 1 find /var/log -name "minio-*.log" -size +100M -exec truncate -s 50M {} \;
Configure backup monitoring
Create monitoring scripts to track backup health and send alerts on failures.
#!/bin/bash
MinIO Backup Monitoring Script
set -euo pipefail
BACKUP_ALIAS="backup"
BACKUP_BUCKET="backups"
LOG_FILE="/var/log/minio-backup.log"
ALERT_EMAIL="admin@example.com"
MAX_BACKUP_AGE_HOURS=26 # Alert if no backup in 26 hours
Check if recent backups exist
check_recent_backups() {
local cutoff_time=$(date -d "-${MAX_BACKUP_AGE_HOURS} hours" +%Y%m%d-%H%M%S)
local recent_backups
recent_backups=$(mc ls "${BACKUP_ALIAS}/${BACKUP_BUCKET}/" | \
awk '{print $4}' | grep -E "[0-9]{8}-[0-9]{6}" | \
sort -r | head -1)
if [[ -z "$recent_backups" ]] || [[ "$recent_backups" < "$cutoff_time" ]]; then
echo "CRITICAL: No recent backups found within $MAX_BACKUP_AGE_HOURS hours"
return 1
else
echo "OK: Recent backup found: $recent_backups"
return 0
fi
}
Check backup log for errors
check_backup_logs() {
if grep -q "ERROR" "$LOG_FILE" 2>/dev/null; then
echo "WARNING: Errors found in backup log"
tail -20 "$LOG_FILE" | grep "ERROR"
return 1
else
echo "OK: No errors in recent backup logs"
return 0
fi
}
Check replication status
check_replication() {
if ! mc replicate status primary/production >/dev/null 2>&1; then
echo "WARNING: Replication status check failed"
return 1
else
echo "OK: Replication status healthy"
return 0
fi
}
Main monitoring function
main() {
local status=0
local report="MinIO Backup Health Report $(date)\n\n"
# Run checks
if ! check_recent_backups; then
status=1
fi
if ! check_backup_logs; then
status=1
fi
if ! check_replication; then
status=1
fi
# Send alert if issues found
if [ $status -ne 0 ]; then
echo "Issues detected in MinIO backup system" | \
mail -s "MinIO Backup Alert" "$ALERT_EMAIL" 2>/dev/null || \
logger "MinIO Backup Alert: Issues detected"
fi
exit $status
}
main
sudo chmod 755 /usr/local/bin/minio-backup-monitor.sh
sudo chown root:root /usr/local/bin/minio-backup-monitor.sh
Test backup and recovery procedures
Perform initial tests to verify your backup and disaster recovery setup works correctly.
# Test backup script
sudo /usr/local/bin/minio-backup.sh
Check backup was created
mc ls backup/backups/
Test monitoring script
sudo /usr/local/bin/minio-backup-monitor.sh
List available backups for recovery testing
/usr/local/bin/minio-disaster-recovery.sh list
Verify your setup
Confirm your MinIO backup and disaster recovery system is working properly.
# Check MinIO client configuration
mc alias ls
Verify replication status
mc replicate ls primary/production
mc replicate status primary/production
Check backup bucket contents
mc ls backup/backups/
mc ls backup/disaster-recovery/
Test backup script execution
sudo /usr/local/bin/minio-backup.sh
Check cron jobs are scheduled
sudo crontab -l | grep minio
Verify log files exist and have recent entries
ls -la /var/log/minio-*.log
tail -10 /var/log/minio-backup.log
Test disaster recovery script
/usr/local/bin/minio-disaster-recovery.sh list
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Permission denied accessing encryption keys | Incorrect file permissions | sudo chmod 600 /etc/minio/backup-keys/*.key |
| Backup script fails with connection error | MinIO alias not configured | Run mc alias set with correct credentials |
| Replication not working | Network connectivity or credentials | Test with mc ping primary backup |
| Cron jobs not running | Cron service not enabled | sudo systemctl enable --now cron (or crond) |
| Backup verification fails | Partial backup or corruption | Check disk space and network stability |
| Cannot restore from backup | Missing target alias or permissions | Configure recovery alias with mc alias set |
| Log files filling up disk | No log rotation configured | Add logrotate configuration for minio logs |
| Email alerts not working | Mail service not configured | Install and configure postfix or alternative |
Next steps
- Setup remote backup storage with S3-compatible encryption
- Set up Spark 3.5 Delta Lake with MinIO for ACID transactions
- Configure MinIO high availability clustering for production
- Implement MinIO security hardening with IAM policies and audit logging
- Setup MinIO monitoring with Prometheus and Grafana dashboards
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# MinIO Backup and Disaster Recovery Installation Script
# Configures automated snapshots, replication, and backup tools
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'
# Global variables
readonly SCRIPT_NAME=$(basename "$0")
readonly LOG_FILE="/var/log/minio-backup-install.log"
readonly BACKUP_DIR="/etc/minio/backup-keys"
readonly BACKUP_SCRIPT="/usr/local/bin/minio-backup.sh"
usage() {
echo "Usage: $SCRIPT_NAME PRIMARY_URL BACKUP_URL [PRIMARY_ACCESS_KEY] [PRIMARY_SECRET_KEY] [BACKUP_ACCESS_KEY] [BACKUP_SECRET_KEY]"
echo "Example: $SCRIPT_NAME https://minio1.example.com:9000 https://minio2.example.com:9000"
echo " $SCRIPT_NAME https://minio1.example.com:9000 https://minio2.example.com:9000 minioadmin SecurePass123 backupadmin BackupPass456"
exit 1
}
log() {
local level="$1"
shift
local message="$*"
local color=""
case "$level" in
ERROR) color="$RED" ;;
SUCCESS) color="$GREEN" ;;
WARNING) color="$YELLOW" ;;
INFO) color="$BLUE" ;;
esac
echo -e "${color}$(date '+%Y-%m-%d %H:%M:%S') [$level] $message${NC}" | tee -a "$LOG_FILE"
}
cleanup() {
log "WARNING" "Script interrupted. Cleaning up..."
# Add cleanup logic here if needed
exit 1
}
trap cleanup ERR INT TERM
check_prerequisites() {
log "INFO" "[1/8] Checking prerequisites..."
if [[ $EUID -ne 0 ]]; then
log "ERROR" "This script must be run as root or with sudo"
exit 1
fi
if ! command -v curl >/dev/null 2>&1; then
log "ERROR" "curl is required but not installed"
exit 1
fi
}
detect_distro() {
log "INFO" "[2/8] Detecting distribution..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
CRON_SERVICE="cron"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
CRON_SERVICE="crond"
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
CRON_SERVICE="crond"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
CRON_SERVICE="crond"
;;
*)
log "ERROR" "Unsupported distribution: $ID"
exit 1
;;
esac
log "SUCCESS" "Detected distribution: $PRETTY_NAME"
else
log "ERROR" "Cannot detect distribution"
exit 1
fi
}
update_system() {
log "INFO" "[3/8] Updating system packages..."
case "$PKG_MGR" in
apt)
$PKG_UPDATE
$PKG_INSTALL curl wget gnupg2 rsync gzip tar cron openssl
;;
dnf|yum)
$PKG_UPDATE
$PKG_INSTALL curl wget gnupg2 rsync gzip tar cronie openssl
systemctl enable --now "$CRON_SERVICE"
;;
esac
log "SUCCESS" "System packages updated"
}
install_minio_client() {
log "INFO" "[4/8] Installing MinIO client..."
curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc
chmod 755 /usr/local/bin/mc
chown root:root /usr/local/bin/mc
if ! mc --version >/dev/null 2>&1; then
log "ERROR" "MinIO client installation failed"
exit 1
fi
log "SUCCESS" "MinIO client installed successfully"
}
setup_backup_directories() {
log "INFO" "[5/8] Setting up backup directory structure..."
mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
chown root:root "$BACKUP_DIR"
mkdir -p /var/log
touch "$LOG_FILE"
chmod 644 "$LOG_FILE"
chown root:root "$LOG_FILE"
log "SUCCESS" "Backup directories created"
}
generate_encryption_key() {
log "INFO" "[6/8] Generating encryption keys..."
local key_file="$BACKUP_DIR/backup-encryption.key"
openssl rand -hex 32 > "$key_file"
chmod 600 "$key_file"
chown root:root "$key_file"
log "SUCCESS" "Encryption key generated at $key_file"
}
create_backup_script() {
log "INFO" "[7/8] Creating backup automation script..."
cat > "$BACKUP_SCRIPT" << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
# MinIO Backup Automation Script
readonly PRIMARY_ALIAS="primary"
readonly BACKUP_ALIAS="backup"
readonly BACKUP_BUCKET="backups"
readonly ENCRYPTION_KEY_FILE="/etc/minio/backup-keys/backup-encryption.key"
readonly LOG_FILE="/var/log/minio-backup.log"
readonly RETENTION_DAYS=30
readonly DATE=$(date +%Y%m%d-%H%M%S)
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
backup_bucket() {
local source_bucket=$1
local backup_name="${source_bucket}-${DATE}"
log "Starting backup of bucket: $source_bucket"
if [ -f "$ENCRYPTION_KEY_FILE" ]; then
local encryption_key=$(cat "$ENCRYPTION_KEY_FILE")
mc mirror --encrypt-key "${PRIMARY_ALIAS}/${source_bucket}=${encryption_key}" \
"${PRIMARY_ALIAS}/${source_bucket}" \
"${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}"
else
mc mirror "${PRIMARY_ALIAS}/${source_bucket}" \
"${BACKUP_ALIAS}/${BACKUP_BUCKET}/${backup_name}"
fi
log "Backup completed for bucket: $source_bucket"
}
cleanup_old_backups() {
log "Cleaning up backups older than ${RETENTION_DAYS} days"
mc find "${BACKUP_ALIAS}/${BACKUP_BUCKET}" --older-than "${RETENTION_DAYS}d" --exec "mc rm {}"
log "Old backup cleanup completed"
}
main() {
log "Starting MinIO backup process"
# Get list of buckets from primary
local buckets
buckets=$(mc ls "$PRIMARY_ALIAS" | awk '{print $5}' | grep -v "^$" || true)
if [ -z "$buckets" ]; then
log "No buckets found to backup"
exit 0
fi
# Backup each bucket
while IFS= read -r bucket; do
if [[ "$bucket" != "$BACKUP_BUCKET" ]]; then
backup_bucket "$bucket"
fi
done <<< "$buckets"
# Cleanup old backups
cleanup_old_backups
log "MinIO backup process completed successfully"
}
main "$@"
EOF
chmod 755 "$BACKUP_SCRIPT"
chown root:root "$BACKUP_SCRIPT"
log "SUCCESS" "Backup script created at $BACKUP_SCRIPT"
}
configure_minio_aliases() {
log "INFO" "[8/8] Configuring MinIO client aliases..."
local primary_url="$1"
local backup_url="$2"
local primary_access="${3:-minioadmin}"
local primary_secret="${4:-SecurePassword123!}"
local backup_access="${5:-minioadmin}"
local backup_secret="${6:-BackupPassword456!}"
# Configure aliases
mc alias set primary "$primary_url" "$primary_access" "$primary_secret" 2>/dev/null || {
log "WARNING" "Could not connect to primary MinIO instance. Please configure manually:"
log "INFO" "mc alias set primary $primary_url <access_key> <secret_key>"
}
mc alias set backup "$backup_url" "$backup_access" "$backup_secret" 2>/dev/null || {
log "WARNING" "Could not connect to backup MinIO instance. Please configure manually:"
log "INFO" "mc alias set backup $backup_url <access_key> <secret_key>"
}
# Create backup buckets if connection successful
if mc alias ls primary >/dev/null 2>&1; then
mc mb primary/backups 2>/dev/null || log "INFO" "Bucket 'backups' may already exist"
mc version enable primary/backups 2>/dev/null || true
fi
if mc alias ls backup >/dev/null 2>&1; then
mc mb backup/disaster-recovery 2>/dev/null || log "INFO" "Bucket 'disaster-recovery' may already exist"
mc mb backup/snapshots 2>/dev/null || log "INFO" "Bucket 'snapshots' may already exist"
mc version enable backup/disaster-recovery 2>/dev/null || true
mc version enable backup/snapshots 2>/dev/null || true
fi
log "SUCCESS" "MinIO aliases configured"
}
verify_installation() {
log "INFO" "Verifying installation..."
local errors=0
if [ ! -f /usr/local/bin/mc ]; then
log "ERROR" "MinIO client not found"
((errors++))
fi
if [ ! -f "$BACKUP_SCRIPT" ]; then
log "ERROR" "Backup script not found"
((errors++))
fi
if [ ! -d "$BACKUP_DIR" ]; then
log "ERROR" "Backup directory not found"
((errors++))
fi
if [ ! -f "$BACKUP_DIR/backup-encryption.key" ]; then
log "ERROR" "Encryption key not found"
((errors++))
fi
if [ $errors -eq 0 ]; then
log "SUCCESS" "Installation completed successfully!"
log "INFO" "Next steps:"
log "INFO" "1. Review and test backup script: $BACKUP_SCRIPT"
log "INFO" "2. Set up cron job for automated backups"
log "INFO" "3. Configure bucket replication with: mc replicate add primary/bucket backup/disaster-recovery"
log "INFO" "4. Test disaster recovery procedures"
else
log "ERROR" "Installation completed with $errors errors"
exit 1
fi
}
main() {
if [ $# -lt 2 ]; then
usage
fi
local primary_url="$1"
local backup_url="$2"
local primary_access="${3:-}"
local primary_secret="${4:-}"
local backup_access="${5:-}"
local backup_secret="${6:-}"
log "INFO" "Starting MinIO backup and disaster recovery setup"
check_prerequisites
detect_distro
update_system
install_minio_client
setup_backup_directories
generate_encryption_key
create_backup_script
configure_minio_aliases "$primary_url" "$backup_url" "$primary_access" "$primary_secret" "$backup_access" "$backup_secret"
verify_installation
log "SUCCESS" "MinIO backup and disaster recovery setup completed!"
}
main "$@"
Review the script before running. Execute with: bash install.sh