Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d98d945b1 |
+32
-1
@@ -47,6 +47,37 @@ Run once, by hand, on the server:
|
||||
# create a remote named "scaleway", type S3, matching your Scaleway
|
||||
# Object Storage credentials and region
|
||||
```
|
||||
7. Set up email notifications (optional — skip this if you don't want mail):
|
||||
Install a mail transport agent (choose one):
|
||||
```bash
|
||||
# Option A: mailutils (Debian/Ubuntu) — includes /usr/bin/mail
|
||||
apt install -y mailutils
|
||||
|
||||
# Option B: msmtp + mailutils (lightweight, no full MTA)
|
||||
apt install -y msmtp msmtp-mta mailutils
|
||||
```
|
||||
Configure the recipient address. Either set `MAIL_TO` in the environment
|
||||
(`/etc/environment` or the cron file itself) or edit `borg-backup.sh`:
|
||||
```
|
||||
MAIL_TO="${MAIL_TO:-you@example.com}"
|
||||
```
|
||||
If using `msmtp`, configure `/etc/msmtprc`:
|
||||
```
|
||||
# /etc/msmtprc — example for Gmail SMTP
|
||||
defaults
|
||||
auth on
|
||||
tls on
|
||||
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
account default
|
||||
host smtp.gmail.com
|
||||
port 587
|
||||
from backup-sender@gmail.com
|
||||
user backup-sender@gmail.com
|
||||
password your-app-password
|
||||
```
|
||||
The script auto-detects which command is available (`mail` → `sendmail` → `msmtp`)
|
||||
and falls back silently if none is present — notifications are never fatal.
|
||||
|
||||
## 2. Deploying the Scripts
|
||||
|
||||
@@ -62,9 +93,9 @@ chmod +x /opt/backup-agent/dump_db.sh
|
||||
## 3. Scheduling
|
||||
|
||||
Add a cron entry to run the backup daily, off-peak:
|
||||
|
||||
```
|
||||
# /etc/cron.d/borg-backup
|
||||
MAIL_TO=you@example.com
|
||||
30 2 * * * root /opt/backup-agent/borg-backup.sh >> /var/log/borg/cron.log 2>&1
|
||||
```
|
||||
|
||||
|
||||
+71
-2
@@ -21,7 +21,7 @@ umask 077
|
||||
|
||||
# ========================= CONFIGURATION =========================
|
||||
|
||||
NAME="chaudron"
|
||||
NAME="borg-2025"
|
||||
REPO="/home/srv/files/backups/$NAME"
|
||||
TARGET="/home/srv/files/content"
|
||||
|
||||
@@ -37,7 +37,8 @@ LOGDIR="/var/log/borg"
|
||||
LOG_RETENTION_DAYS=90
|
||||
|
||||
RCLONE_REMOTE="scaleway"
|
||||
RCLONE_PATH="cyanet-backups-prod/$NAME"
|
||||
RCLONE_PATH="par-backup-1/$NAME"
|
||||
RCLONE_MAX_DELETE=200
|
||||
|
||||
LOCKFILE="/var/lock/borg-backup.lock"
|
||||
|
||||
@@ -57,6 +58,10 @@ REQUIRED_CMDS=(borg rclone docker timeout flock date find)
|
||||
|
||||
# =================================================================
|
||||
|
||||
# Email notification (set to your address to receive backup summary).
|
||||
# Leave empty to skip notifications. The script auto-detects mail/sendmail/msmtp.
|
||||
MAIL_TO="${MAIL_TO:-}"
|
||||
|
||||
SELF="$(readlink -f "$0")"
|
||||
mkdir -p "$LOGDIR"
|
||||
LOGFILE="${BORG_BACKUP_LOGFILE:-$LOGDIR/backup-$(date +%Y-%m-%d-%H%M%S).log}"
|
||||
@@ -88,6 +93,68 @@ run_cmd() {
|
||||
"$@"
|
||||
}
|
||||
|
||||
# Detect available mail transport. Returns the command name or empty string.
|
||||
find_mail_cmd() {
|
||||
for cmd in mail sendmail msmtp; do
|
||||
command -v "$cmd" >/dev/null 2>&1 && { echo "$cmd"; return 0; }
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Send an email notification about the backup result.
|
||||
# Called from cleanup() so the log file is complete.
|
||||
# Non-fatal — mail failures do not affect the backup exit code.
|
||||
send_notification() {
|
||||
local exit_code=$1 status started ended
|
||||
[[ -n "$MAIL_TO" ]] || return 0
|
||||
|
||||
local mail_cmd
|
||||
mail_cmd="$(find_mail_cmd)" || { log "Notification skipped: no mail command found"; return 0; }
|
||||
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
status="SUCCESS"
|
||||
else
|
||||
status="FAILED (exit $exit_code)"
|
||||
fi
|
||||
|
||||
started="$(head -1 "$LOGFILE" 2>/dev/null | sed -n 's/^\[\(.*\)\].*/\1/p' || echo "?")"
|
||||
ended="$(date '+%F %T')"
|
||||
|
||||
# Build message body with headers and log tail.
|
||||
{
|
||||
echo "Subject: Backup $status - $(hostname -s)"
|
||||
echo "To: $MAIL_TO"
|
||||
echo ""
|
||||
echo "===== Backup Summary ====="
|
||||
echo "Host: $(hostname -f)"
|
||||
echo "Archive: $ARCHIVE"
|
||||
echo "Status: $status"
|
||||
echo "Started: $started"
|
||||
echo "Ended: $ended"
|
||||
echo "Log: $LOGFILE"
|
||||
echo ""
|
||||
echo "----- Last 80 lines of backup log -----"
|
||||
tail -80 "$LOGFILE" 2>/dev/null || echo "(log unavailable)"
|
||||
} | case "$mail_cmd" in
|
||||
mail)
|
||||
mail -s "Backup $status - $(hostname -s)" "$MAIL_TO"
|
||||
;;
|
||||
sendmail)
|
||||
sendmail "$MAIL_TO"
|
||||
;;
|
||||
msmtp)
|
||||
msmtp "$MAIL_TO"
|
||||
;;
|
||||
esac
|
||||
|
||||
local rc=$?
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
log "Notification sent to $MAIL_TO (via $mail_cmd)"
|
||||
else
|
||||
log "WARNING: notification via $mail_cmd failed (exit $rc)"
|
||||
fi
|
||||
}
|
||||
|
||||
container_running() {
|
||||
[[ "$(docker inspect -f '{{.State.Running}}' "$1" 2>/dev/null || echo false)" == "true" ]]
|
||||
}
|
||||
@@ -142,6 +209,7 @@ cleanup() {
|
||||
log "=== Backup FAILED (exit $exit_code) ==="
|
||||
fi
|
||||
log "Full log: $LOGFILE"
|
||||
send_notification "$exit_code"
|
||||
}
|
||||
|
||||
# Returns 0 if the repo is encrypted, 1 if not.
|
||||
@@ -303,4 +371,5 @@ run_cmd timeout "$SYNC_TIMEOUT" \
|
||||
--retries-sleep 10s \
|
||||
--low-level-retries 20 \
|
||||
--s3-no-check-bucket \
|
||||
--max-delete "$RCLONE_MAX_DELETE" \
|
||||
"$REPO" "${RCLONE_REMOTE}:${RCLONE_PATH}"
|
||||
|
||||
Reference in New Issue
Block a user