Server Backup Script

devops

Automated backup script using Restic (restic.net) for encrypted, deduplicated backups to AWS S3. Backs up web applications and MySQL databases with Slack notifications, error handling, and automatic retention policies (7 daily, 4 weekly, 6 monthly).

bash restic aws-s3 mysql
Files
backup.sh
1#!/bin/bash
2 
3# ============================================
4# Server Backup Script
5#
6# Automated backup for web servers using Restic
7# (https://restic.net) with AWS S3 storage.
8#
9# Features:
10# - MySQL database dumps
11# - Encrypted, deduplicated backups
12# - Slack notifications (success/failure)
13# - Automatic retention policies
14#
15# Schedule: Daily via cron (e.g., 0 3 * * *)
16# ============================================
17 
18# AWS S3 Configuration
19export AWS_ACCESS_KEY_ID="your-access-key"
20export AWS_SECRET_ACCESS_KEY="your-secret-key"
21export RESTIC_REPOSITORY="s3:s3.eu-central-1.amazonaws.com/your-bucket"
22export RESTIC_PASSWORD="your-restic-password"
23 
24LOG_FILE="/var/log/backup.log"
25SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
26WEB_ROOT="/var/www"
27 
28# Slack notification function
29notify_slack() {
30 local status=$1
31 local message=$2
32 local color=$([[ "$status" == "success" ]] && echo "good" || echo "danger")
33 local emoji=$([[ "$status" == "success" ]] && echo ":white_check_mark:" || echo ":x:")
34 
35 curl -s -X POST "$SLACK_WEBHOOK" \
36 -H 'Content-type: application/json' \
37 -d "{
38 \"attachments\": [{
39 \"color\": \"$color\",
40 \"text\": \"$emoji *Server Backup*\n$message\",
41 \"footer\": \"Restic Backup\",
42 \"ts\": $(date +%s)
43 }]
44 }" > /dev/null
45}
46 
47# Error handler
48handle_error() {
49 local error_msg="$1"
50 echo "$(date): ERROR - $error_msg" >> $LOG_FILE
51 notify_slack "error" "Backup failed: $error_msg"
52 rm -rf /tmp/db_backups 2>/dev/null
53 exit 1
54}
55 
56# Set error trap
57trap 'handle_error "Unexpected error on line $LINENO"' ERR
58 
59echo "$(date): Starting backup" >> $LOG_FILE
60 
61# Dump databases (excluding system DBs)
62echo "$(date): Dumping databases..." >> $LOG_FILE
63mkdir -p /tmp/db_backups
64mysql -N -e "SHOW DATABASES" | grep -v -E "^(information_schema|performance_schema|mysql|sys)$" | while read db; do
65 mysqldump --single-transaction --no-tablespaces "$db" > "/tmp/db_backups/${db}.sql" || handle_error "Failed to dump database: $db"
66done
67 
68# Create backup with restic
69echo "$(date): Creating restic backup..." >> $LOG_FILE
70restic backup \
71 --verbose \
72 --exclude "$WEB_ROOT/*/node_modules" \
73 --exclude "$WEB_ROOT/*/vendor" \
74 --exclude "$WEB_ROOT/*/.git" \
75 --exclude "$WEB_ROOT/*/storage/logs/*" \
76 --exclude "$WEB_ROOT/*/storage/framework/cache/*" \
77 --exclude "$WEB_ROOT/*/storage/framework/sessions/*" \
78 --exclude "$WEB_ROOT/*/.cache" \
79 "$WEB_ROOT" \
80 /tmp/db_backups \
81 2>> $LOG_FILE
82 
83# Cleanup database dumps
84rm -rf /tmp/db_backups
85 
86# Prune old backups (keep 7 daily, 4 weekly, 6 monthly)
87echo "$(date): Pruning old backups..." >> $LOG_FILE
88restic forget \
89 --keep-daily 7 \
90 --keep-weekly 4 \
91 --keep-monthly 6 \
92 --prune \
93 2>> $LOG_FILE
94 
95echo "$(date): Backup completed successfully" >> $LOG_FILE
96notify_slack "success" "Backup completed successfully"
Chat with me 👋🏻
William

Ask William

Available to chat