Skip to Content
QBCore docs โ€“ powered by Nextra 4
MigrationToolsBackup & Restore Guide

Backup & Restore Guide

Comprehensive backup and restore procedures for QBCore servers. This guide covers everything from routine backups to disaster recovery, ensuring your server data is always protected during migrations and daily operations.

Overview

A robust backup strategy is essential for any QBCore server. This guide provides automated scripts, best practices, and recovery procedures to protect your valuable server data including:

  • Player data and character information
  • Database content and structure
  • Server files and configurations
  • Custom resources and modifications
  • Logs and historical data

๐Ÿšจ Critical Reminder

Never perform migrations or major changes without a complete, tested backup. Data loss can be irreversible and devastating to your community.

Quick Backup Commands

Essential Backup Commands

# Complete server backup (recommended before any changes) ./scripts/backup-complete.sh # Database-only backup mysqldump -u username -p database_name > backup-$(date +%Y%m%d-%H%M%S).sql # Resources-only backup tar -czf resources-backup-$(date +%Y%m%d).tar.gz resources/ # Configuration backup tar -czf config-backup-$(date +%Y%m%d).tar.gz server.cfg txAdmin/config/

Quick Restore Commands

# Restore database mysql -u username -p database_name < backup-file.sql # Restore resources tar -xzf resources-backup.tar.gz # Restore complete server ./scripts/restore-complete.sh backup-folder-name

Comprehensive Backup Strategy

1. Automated Backup System

Complete Backup Script

#!/bin/bash # backup-complete.sh - Complete QBCore server backup # Configuration BACKUP_BASE_DIR="/backups" SERVER_DIR="/opt/fivem-server" DB_USER="your_db_user" DB_PASS="your_db_password" DB_NAME="your_database" RETENTION_DAYS=30 # Create backup directory with timestamp BACKUP_DIR="$BACKUP_BASE_DIR/qbcore-backup-$(date +%Y%m%d-%H%M%S)" mkdir -p "$BACKUP_DIR" echo "๐Ÿš€ Starting QBCore Complete Backup" echo "Backup location: $BACKUP_DIR" # Function to log with timestamp log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # Function to handle errors handle_error() { log "โŒ ERROR: $1" exit 1 } # 1. Stop server gracefully log "Stopping FiveM server..." if pgrep -f "FXServer" > /dev/null; then pkill -TERM -f "FXServer" sleep 10 if pgrep -f "FXServer" > /dev/null; then log "โš ๏ธ Force stopping server..." pkill -KILL -f "FXServer" fi log "โœ… Server stopped" else log "โ„น๏ธ Server was not running" fi # 2. Database backup log "๐Ÿ“Š Backing up database..." if ! mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$BACKUP_DIR/database.sql"; then handle_error "Database backup failed" fi log "โœ… Database backup completed ($(du -h "$BACKUP_DIR/database.sql" | cut -f1))" # 3. Server files backup log "๐Ÿ“ Backing up server files..." SERVER_BACKUP_DIR="$BACKUP_DIR/server-files" mkdir -p "$SERVER_BACKUP_DIR" # Essential directories and files BACKUP_ITEMS=( "resources" "server.cfg" "run.sh" "txAdmin" "cache" "logs" ) for item in "${BACKUP_ITEMS[@]}"; do if [ -e "$SERVER_DIR/$item" ]; then log " ๐Ÿ“ฆ Backing up $item..." cp -r "$SERVER_DIR/$item" "$SERVER_BACKUP_DIR/" else log " โš ๏ธ $item not found, skipping..." fi done # 4. Custom configurations log "โš™๏ธ Backing up custom configurations..." CONFIG_DIR="$BACKUP_DIR/configs" mkdir -p "$CONFIG_DIR" # Find and backup all config files find "$SERVER_DIR/resources" -name "config*.lua" -exec cp {} "$CONFIG_DIR/" \; find "$SERVER_DIR/resources" -name "*.cfg" -exec cp {} "$CONFIG_DIR/" \; # 5. Player data extraction (JSON format for easy inspection) log "๐Ÿ‘ฅ Extracting player data..." mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e " SELECT citizenid, license, name, money, charinfo, job, gang, position, metadata, last_updated FROM players INTO OUTFILE '$BACKUP_DIR/players-data.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n';" # 6. Create backup manifest log "๐Ÿ“‹ Creating backup manifest..." cat > "$BACKUP_DIR/backup-manifest.json" << EOF { "backup_date": "$(date -I)", "backup_time": "$(date '+%H:%M:%S')", "qbcore_version": "$(grep -o 'version.*[0-9]' $SERVER_DIR/resources/[qb]/qb-core/version.lua || echo 'unknown')", "server_path": "$SERVER_DIR", "database_name": "$DB_NAME", "player_count": $(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -se "SELECT COUNT(*) FROM players;"), "backup_size": "$(du -sh "$BACKUP_DIR" | cut -f1)", "files_backed_up": [ $(find "$BACKUP_DIR" -type f | wc -l) ], "integrity_hash": "$(find "$BACKUP_DIR" -type f -exec md5sum {} \; | sort | md5sum | cut -d' ' -f1)" } EOF # 7. Compress backup log "๐Ÿ—œ๏ธ Compressing backup..." cd "$BACKUP_BASE_DIR" tar -czf "$(basename "$BACKUP_DIR").tar.gz" "$(basename "$BACKUP_DIR")" COMPRESSED_SIZE=$(du -h "$(basename "$BACKUP_DIR").tar.gz" | cut -f1) log "โœ… Backup compressed: $COMPRESSED_SIZE" # 8. Cleanup old backups log "๐Ÿงน Cleaning up old backups (older than $RETENTION_DAYS days)..." find "$BACKUP_BASE_DIR" -name "qbcore-backup-*" -type d -mtime +$RETENTION_DAYS -exec rm -rf {} + find "$BACKUP_BASE_DIR" -name "qbcore-backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete # 9. Restart server log "๐Ÿ”„ Restarting FiveM server..." cd "$SERVER_DIR" nohup ./run.sh > /dev/null 2>&1 & sleep 5 if pgrep -f "FXServer" > /dev/null; then log "โœ… Server restarted successfully" else log "โš ๏ธ Server restart may have failed, check manually" fi # 10. Backup verification log "๐Ÿ” Verifying backup integrity..." if [ -f "$BACKUP_DIR/database.sql" ] && [ -d "$BACKUP_DIR/server-files" ]; then log "โœ… Backup completed successfully!" log "๐Ÿ“Š Backup Summary:" log " Location: $BACKUP_DIR" log " Size: $(du -sh "$BACKUP_DIR" | cut -f1)" log " Compressed: $COMPRESSED_SIZE" log " Player count: $(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -se "SELECT COUNT(*) FROM players;")" else handle_error "Backup verification failed" fi echo "๐ŸŽ‰ Backup completed successfully!"

Automated Scheduling

# Add to crontab for automated backups crontab -e # Daily backup at 3 AM 0 3 * * * /opt/fivem-server/scripts/backup-complete.sh >> /var/log/fivem-backup.log 2>&1 # Weekly full backup on Sundays at 2 AM 0 2 * * 0 /opt/fivem-server/scripts/backup-complete.sh --full >> /var/log/fivem-backup.log 2>&1 # Quick database backup every 6 hours 0 */6 * * * /opt/fivem-server/scripts/backup-database.sh >> /var/log/fivem-backup.log 2>&1

2. Incremental Backup System

For large servers, incremental backups save space and time:

#!/bin/bash # backup-incremental.sh - Incremental backup system BACKUP_BASE="/backups" LAST_BACKUP_FILE="$BACKUP_BASE/.last-backup" CURRENT_TIME=$(date +%s) # Find last backup timestamp if [ -f "$LAST_BACKUP_FILE" ]; then LAST_BACKUP=$(cat "$LAST_BACKUP_FILE") else LAST_BACKUP=0 fi log "Starting incremental backup since $(date -d @$LAST_BACKUP)" # Database incremental backup (changes since last backup) mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" \ --where="last_updated > FROM_UNIXTIME($LAST_BACKUP)" \ --single-transaction \ > "$BACKUP_DIR/database-incremental.sql" # File system changes find "$SERVER_DIR" -type f -newer "$LAST_BACKUP_FILE" \ -not -path "*/cache/*" \ -not -path "*/logs/*" \ | tar -czf "$BACKUP_DIR/files-incremental.tar.gz" -T - # Update last backup timestamp echo "$CURRENT_TIME" > "$LAST_BACKUP_FILE"

3. Database-Specific Backup

#!/bin/bash # backup-database.sh - Comprehensive database backup # Hot backup with binary logs mysqldump -u"$DB_USER" -p"$DB_PASS" \ --single-transaction \ --routines \ --triggers \ --flush-logs \ --master-data=2 \ "$DB_NAME" > "db-backup-$(date +%Y%m%d-%H%M%S).sql" # Table-specific backups for critical data mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" << 'EOF' SELECT * INTO OUTFILE '/tmp/players_backup.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM players; SELECT * INTO OUTFILE '/tmp/player_vehicles_backup.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM player_vehicles; EOF # Verify backup integrity mysql -u"$DB_USER" -p"$DB_PASS" < "db-backup-$(date +%Y%m%d-%H%M%S).sql" \ --database="test_restore_db" && echo "โœ… Database backup verified"

Restore Procedures

1. Complete Server Restore

#!/bin/bash # restore-complete.sh - Complete server restore BACKUP_ARCHIVE=$1 RESTORE_DIR="/tmp/restore-$(date +%s)" if [ -z "$BACKUP_ARCHIVE" ]; then echo "Usage: $0 <backup-archive.tar.gz>" exit 1 fi echo "๐Ÿ”„ Starting complete server restore from $BACKUP_ARCHIVE" # Extract backup mkdir -p "$RESTORE_DIR" tar -xzf "$BACKUP_ARCHIVE" -C "$RESTORE_DIR" --strip-components=1 # Verify backup integrity if [ ! -f "$RESTORE_DIR/backup-manifest.json" ]; then echo "โŒ Invalid backup archive - missing manifest" exit 1 fi # Display backup information echo "๐Ÿ“Š Backup Information:" cat "$RESTORE_DIR/backup-manifest.json" | jq '.' read -p "Continue with restore? (y/N): " confirm if [ "$confirm" != "y" ]; then echo "Restore cancelled" exit 0 fi # Stop server echo "โน๏ธ Stopping server..." pkill -f "FXServer" sleep 10 # Backup current state before restore echo "๐Ÿ’พ Creating pre-restore backup..." mv "$SERVER_DIR" "${SERVER_DIR}-pre-restore-$(date +%s)" # Restore database echo "๐Ÿ“Š Restoring database..." mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$RESTORE_DIR/database.sql" # Restore server files echo "๐Ÿ“ Restoring server files..." mkdir -p "$SERVER_DIR" cp -r "$RESTORE_DIR/server-files/"* "$SERVER_DIR/" # Set correct permissions chmod +x "$SERVER_DIR/run.sh" chmod -R 755 "$SERVER_DIR/resources" # Restart server echo "๐Ÿš€ Starting server..." cd "$SERVER_DIR" nohup ./run.sh > /dev/null 2>&1 & # Verify restore sleep 10 if pgrep -f "FXServer" > /dev/null; then echo "โœ… Server restore completed successfully!" else echo "โš ๏ธ Server may not have started correctly" fi # Cleanup rm -rf "$RESTORE_DIR"

2. Selective Restore

#!/bin/bash # restore-selective.sh - Restore specific components BACKUP_DIR=$1 COMPONENT=$2 case "$COMPONENT" in "database") echo "๐Ÿ“Š Restoring database only..." mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$BACKUP_DIR/database.sql" ;; "resources") echo "๐Ÿ“ Restoring resources only..." cp -r "$BACKUP_DIR/server-files/resources/"* "$SERVER_DIR/resources/" ;; "config") echo "โš™๏ธ Restoring configurations only..." find "$BACKUP_DIR" -name "config*.lua" -exec cp {} "$SERVER_DIR/resources/[qb]/" \; ;; "players") echo "๐Ÿ‘ฅ Restoring player data only..." mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" << EOF DELETE FROM players; LOAD DATA INFILE '$BACKUP_DIR/players-data.csv' INTO TABLE players FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n'; EOF ;; *) echo "Usage: $0 <backup_dir> <component>" echo "Components: database, resources, config, players" exit 1 ;; esac

3. Database Point-in-Time Recovery

#!/bin/bash # restore-point-in-time.sh - Restore database to specific point in time TARGET_DATE="$1" # Format: YYYY-MM-DD HH:MM:SS if [ -z "$TARGET_DATE" ]; then echo "Usage: $0 'YYYY-MM-DD HH:MM:SS'" exit 1 fi echo "๐Ÿ• Restoring database to point in time: $TARGET_DATE" # Find appropriate backup BACKUP_FILE=$(find /backups -name "*.sql" -newermt "$TARGET_DATE" | head -1) if [ -z "$BACKUP_FILE" ]; then echo "โŒ No backup found for the specified date" exit 1 fi # Create test database for verification mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE IF EXISTS test_restore; CREATE DATABASE test_restore;" # Restore to test database mysql -u"$DB_USER" -p"$DB_PASS" test_restore < "$BACKUP_FILE" # Show data at target time mysql -u"$DB_USER" -p"$DB_PASS" test_restore -e " SELECT COUNT(*) as player_count, MAX(last_updated) as latest_update FROM players WHERE last_updated <= '$TARGET_DATE';" read -p "Proceed with restore to production? (y/N): " confirm if [ "$confirm" = "y" ]; then mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$BACKUP_FILE" echo "โœ… Point-in-time restore completed" else echo "Restore cancelled" fi # Cleanup test database mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE test_restore;"

Backup Validation & Testing

1. Backup Integrity Verification

#!/bin/bash # verify-backup.sh - Comprehensive backup verification BACKUP_DIR=$1 echo "๐Ÿ” Verifying backup integrity: $BACKUP_DIR" # Check backup completeness required_files=( "database.sql" "server-files" "backup-manifest.json" ) for file in "${required_files[@]}"; do if [ ! -e "$BACKUP_DIR/$file" ]; then echo "โŒ Missing required file: $file" exit 1 fi done # Verify database backup echo "๐Ÿ“Š Verifying database backup..." mysql -u"$DB_USER" -p"$DB_PASS" -e "CREATE DATABASE backup_test;" mysql -u"$DB_USER" -p"$DB_PASS" backup_test < "$BACKUP_DIR/database.sql" # Check table integrity EXPECTED_TABLES=("players" "player_vehicles" "apartments" "bank_accounts") for table in "${EXPECTED_TABLES[@]}"; do count=$(mysql -u"$DB_USER" -p"$DB_PASS" backup_test -se "SELECT COUNT(*) FROM $table;") echo " โœ… Table $table: $count records" done # Verify data integrity mysql -u"$DB_USER" -p"$DB_PASS" backup_test -e "CHECK TABLE players, player_vehicles;" # Cleanup mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE backup_test;" echo "โœ… Backup verification completed"

2. Automated Backup Testing

#!/bin/bash # test-backup-restore.sh - Automated backup/restore testing TEST_SERVER_DIR="/tmp/test-server" TEST_DB_NAME="qbcore_test" echo "๐Ÿงช Starting automated backup/restore test" # Create test environment mkdir -p "$TEST_SERVER_DIR" mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE IF EXISTS $TEST_DB_NAME; CREATE DATABASE $TEST_DB_NAME;" # Copy current server to test location cp -r "$SERVER_DIR/"* "$TEST_SERVER_DIR/" # Create test backup echo "๐Ÿ’พ Creating test backup..." ./backup-complete.sh --target "$TEST_SERVER_DIR" --database "$TEST_DB_NAME" # Simulate data corruption echo "๐Ÿ’ฅ Simulating data corruption..." mysql -u"$DB_USER" -p"$DB_PASS" "$TEST_DB_NAME" -e "DELETE FROM players LIMIT 10;" # Restore from backup echo "๐Ÿ”„ Testing restore..." LATEST_BACKUP=$(ls -t /backups/qbcore-backup-*.tar.gz | head -1) ./restore-complete.sh "$LATEST_BACKUP" --target "$TEST_SERVER_DIR" --database "$TEST_DB_NAME" # Verify restoration PLAYER_COUNT=$(mysql -u"$DB_USER" -p"$DB_PASS" "$TEST_DB_NAME" -se "SELECT COUNT(*) FROM players;") ORIGINAL_COUNT=$(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -se "SELECT COUNT(*) FROM players;") if [ "$PLAYER_COUNT" -eq "$ORIGINAL_COUNT" ]; then echo "โœ… Backup/restore test PASSED" else echo "โŒ Backup/restore test FAILED" echo " Expected: $ORIGINAL_COUNT players" echo " Got: $PLAYER_COUNT players" fi # Cleanup test environment rm -rf "$TEST_SERVER_DIR" mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE $TEST_DB_NAME;"

Cloud Backup Integration

1. AWS S3 Integration

#!/bin/bash # backup-to-s3.sh - Upload backups to Amazon S3 S3_BUCKET="your-qbcore-backups" AWS_REGION="us-east-1" LOCAL_BACKUP_DIR="/backups" # Install AWS CLI if not present if ! command -v aws &> /dev/null; then echo "Installing AWS CLI..." curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install fi # Upload latest backup to S3 LATEST_BACKUP=$(ls -t "$LOCAL_BACKUP_DIR"/qbcore-backup-*.tar.gz | head -1) echo "โ˜๏ธ Uploading to S3: $(basename "$LATEST_BACKUP")" aws s3 cp "$LATEST_BACKUP" "s3://$S3_BUCKET/$(date +%Y/%m/%d)/" \ --storage-class STANDARD_IA \ --metadata "server-name=$(hostname),backup-date=$(date -I)" # Lifecycle management - delete old backups aws s3api list-objects-v2 --bucket "$S3_BUCKET" \ --query "Contents[?LastModified<=\`$(date -d '30 days ago' --iso-8601)\`].[Key]" \ --output text | xargs -I {} aws s3 rm "s3://$S3_BUCKET/{}" echo "โœ… S3 upload completed"

2. Google Cloud Storage Integration

#!/bin/bash # backup-to-gcs.sh - Upload backups to Google Cloud Storage GCS_BUCKET="your-qbcore-backups" LOCAL_BACKUP_DIR="/backups" # Upload to Google Cloud Storage LATEST_BACKUP=$(ls -t "$LOCAL_BACKUP_DIR"/qbcore-backup-*.tar.gz | head -1) echo "โ˜๏ธ Uploading to GCS: $(basename "$LATEST_BACKUP")" gsutil cp "$LATEST_BACKUP" "gs://$GCS_BUCKET/$(date +%Y/%m/%d)/" # Set lifecycle policy for automatic deletion gsutil lifecycle set lifecycle-config.json "gs://$GCS_BUCKET" echo "โœ… GCS upload completed"

3. Encryption for Cloud Storage

#!/bin/bash # encrypt-backup.sh - Encrypt backups before cloud upload BACKUP_FILE=$1 ENCRYPTION_KEY_FILE="/secure/backup-key.txt" if [ ! -f "$ENCRYPTION_KEY_FILE" ]; then echo "Generating encryption key..." openssl rand -base64 32 > "$ENCRYPTION_KEY_FILE" chmod 600 "$ENCRYPTION_KEY_FILE" fi # Encrypt backup echo "๐Ÿ”’ Encrypting backup..." openssl aes-256-cbc -salt -in "$BACKUP_FILE" \ -out "${BACKUP_FILE}.enc" \ -kfile "$ENCRYPTION_KEY_FILE" # Upload encrypted file aws s3 cp "${BACKUP_FILE}.enc" "s3://$S3_BUCKET/" # Clean up local encrypted file rm "${BACKUP_FILE}.enc"

Disaster Recovery Planning

1. Complete Server Rebuild

#!/bin/bash # disaster-recovery.sh - Complete server rebuild from backup BACKUP_LOCATION=$1 # S3 URL or local path NEW_SERVER_PATH="/opt/fivem-server-new" echo "๐Ÿ†˜ Starting disaster recovery process" # Download backup from cloud if needed if [[ "$BACKUP_LOCATION" == s3://* ]]; then echo "โ˜๏ธ Downloading backup from S3..." aws s3 cp "$BACKUP_LOCATION" ./disaster-backup.tar.gz BACKUP_LOCATION="./disaster-backup.tar.gz" fi # Create new server directory mkdir -p "$NEW_SERVER_PATH" # Extract backup tar -xzf "$BACKUP_LOCATION" -C "$NEW_SERVER_PATH" --strip-components=1 # Install dependencies echo "๐Ÿ“ฆ Installing dependencies..." apt-get update apt-get install -y mysql-server nodejs npm # Setup database echo "๐Ÿ“Š Setting up database..." mysql_secure_installation mysql -u root -p -e "CREATE DATABASE qbcore; CREATE USER 'qbcore'@'localhost' IDENTIFIED BY 'secure_password';" mysql -u qbcore -p qbcore < "$NEW_SERVER_PATH/database.sql" # Configure FiveM server echo "๐ŸŽฎ Configuring FiveM server..." # Download latest FiveM artifacts wget https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/latest.tar.xz tar -xf latest.tar.xz -C "$NEW_SERVER_PATH" # Start server cd "$NEW_SERVER_PATH" chmod +x run.sh ./run.sh echo "โœ… Disaster recovery completed"

2. Data Recovery from Corruption

#!/bin/bash # recover-corrupted-data.sh - Recover from data corruption echo "๐Ÿฉน Starting data corruption recovery" # Create backup of corrupted state mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "corrupted-state-$(date +%s).sql" # Identify corruption extent mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" << 'EOF' -- Check for data inconsistencies SELECT 'Invalid JSON in money column' as issue, COUNT(*) as count FROM players WHERE NOT JSON_VALID(money) UNION ALL SELECT 'Missing character info', COUNT(*) FROM players WHERE charinfo IS NULL OR charinfo = '' UNION ALL SELECT 'Duplicate citizen IDs', COUNT(*) - COUNT(DISTINCT citizenid) FROM players; EOF # Restore from most recent clean backup echo "๐Ÿ”„ Restoring from clean backup..." CLEAN_BACKUP=$(find /backups -name "*.sql" -mtime -7 | head -1) mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$CLEAN_BACKUP" echo "โœ… Data recovery completed"

Monitoring & Alerting

1. Backup Health Monitoring

#!/bin/bash # monitor-backup-health.sh - Monitor backup system health BACKUP_DIR="/backups" ALERT_EMAIL="admin@yourserver.com" MAX_AGE_HOURS=26 # Alert if no backup in 26 hours # Check last backup age LAST_BACKUP=$(find "$BACKUP_DIR" -name "*.tar.gz" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-) LAST_BACKUP_TIME=$(stat -c %Y "$LAST_BACKUP") CURRENT_TIME=$(date +%s) AGE_HOURS=$(( (CURRENT_TIME - LAST_BACKUP_TIME) / 3600 )) if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then echo "๐Ÿšจ ALERT: Last backup is $AGE_HOURS hours old" | \ mail -s "QBCore Backup Alert - $(hostname)" "$ALERT_EMAIL" fi # Check backup integrity if ! tar -tzf "$LAST_BACKUP" >/dev/null 2>&1; then echo "๐Ÿšจ ALERT: Latest backup appears to be corrupted" | \ mail -s "QBCore Backup Corruption Alert - $(hostname)" "$ALERT_EMAIL" fi # Check disk space BACKUP_USAGE=$(df "$BACKUP_DIR" | awk 'NR==2{print $5}' | sed 's/%//') if [ "$BACKUP_USAGE" -gt 90 ]; then echo "๐Ÿšจ ALERT: Backup disk usage at ${BACKUP_USAGE}%" | \ mail -s "QBCore Backup Disk Space Alert - $(hostname)" "$ALERT_EMAIL" fi

2. Slack Integration

#!/bin/bash # slack-backup-notification.sh - Send backup notifications to Slack SLACK_WEBHOOK_URL="your-slack-webhook-url" send_slack_notification() { local message=$1 local color=$2 curl -X POST -H 'Content-type: application/json' \ --data "{ \"attachments\": [{ \"color\": \"$color\", \"fields\": [{ \"title\": \"QBCore Backup Status - $(hostname)\", \"value\": \"$message\", \"short\": false }] }] }" \ "$SLACK_WEBHOOK_URL" } # Success notification send_slack_notification "โœ… Backup completed successfully at $(date)" "good" # Error notification send_slack_notification "โŒ Backup failed at $(date)" "danger"

โœ… Backup Best Practices Summary

  • โ€ข 3-2-1 Rule: 3 copies, 2 different media, 1 offsite
  • โ€ข Test regularly: Verify backups can be restored
  • โ€ข Automate everything: Use scripts and scheduling
  • โ€ข Monitor health: Set up alerts for backup failures
  • โ€ข Document procedures: Keep recovery steps updated
  • โ€ข Encrypt sensitive data: Use encryption for cloud storage

Additional Resources

Last updated on