exiguus.blog

Personal blog

Simple Restic Backup Monitoring with Telegram Notifications

Created: 2025-12-10

Introduction

Restic is a powerful, efficient, and secure backup tool that works with local and remote repositories. However, even the best backup solution is useless if you don't verify that backups are actually being created. This article presents a simple yet effective bash script that monitors your restic repositories and sends you daily Telegram notifications about their status.

Important: While this script helps you monitor backup creation, it does not verify that your backups can be restored. Regular restore tests remain essential for a complete backup strategy.

The Monitoring Script

The following script checks all restic repositories in a specified directory, identifies those with outdated snapshots, and sends a formatted report to Telegram:

#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

TELEGRAM_TOKEN="YOUR_BOT_TOKEN"
TELEGRAM_CHAT_ID="YOUR_CHAT_ID"
readonly LOG_FILE="/var/log/restic-backup-check-telegram.log"
readonly LOG_TIMESTAMP_FORMAT='+%Y-%m-%d %H:%M:%S%z'

today=$(date +%Y-%m-%d)
backup_base="/path/to/your/backup/repos"

all_entries=""
non_today_entries=""
today_date=$(date +%Y-%m-%d)

log_line() {
  printf '[%s] %s\n' "$(date "${LOG_TIMESTAMP_FORMAT}")" "$1" >>"${LOG_FILE}"
}

log_stream() {
  local line=""
  while IFS= read -r line || [[ -n "$line" ]]; do
    log_line "$line"
  done
}

log_message() {
  printf '%s\n' "$1" | log_stream
}

for dir in "$backup_base"/*/; do
    latest_file=$(find "$dir"snapshots/ -type f -printf '%T@ %p\n' 2>/dev/null | sort -n | tail -1 | cut -d' ' -f2-)
    if [[ -n "$latest_file" ]]; then
        latest_date=$(stat -c '%y' "$latest_file" | cut -d' ' -f1)
        latest_time=$(stat -c '%y' "$latest_file" | cut -d' ' -f2 | cut -d':' -f1-2)
        all_entries+=$(printf "%s %s %s\n" "$latest_date" "$latest_time" "$dir")
        all_entries+=$'\n'
        if [[ "$latest_date" != "$today_date" ]]; then
            non_today_entries+=$(printf "%s %s %s\n" "$latest_date" "$latest_time" "$dir")
            non_today_entries+=$'\n'
        fi
    fi
done

all_entries=$(echo "$all_entries" | sort)
non_today_entries=$(echo "$non_today_entries" | sort)

# Send results via Telegram
HOSTNAME=$(hostname -f 2>/dev/null || hostname)

MESSAGE="[$HOSTNAME] Restic Backup Check ($today)


=== WARNING: Current Backup Status ===

$non_today_entries

=== INFO: Current Backup Status ===

$all_entries

"

URL="https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage"
if curl -s -X POST "$URL" -d chat_id="$TELEGRAM_CHAT_ID" -d text="$MESSAGE" >/dev/null; then
  log_message "Telegram restic backup status sent."
else
  log_message "Warning: failed to send Telegram restic backup status."
fi

# Append to log file with timestamped lines
log_message "$MESSAGE"

How It Works

1. Repository Discovery

The script scans the specified backup_base directory for all subdirectories, treating each as a separate restic repository. This matches the common pattern of having one repository per host or system.

2. Snapshot Detection

For each repository, it:

3. Status Classification

The script categorizes repositories into two groups:

4. Notification

The script sends a formatted message to Telegram using the bot API, including:

5. Local Logging

All actions and messages are logged to /var/log/restic-backup-check-telegram.log with timestamps for local auditing.

Example Output

Here's what a typical daily Telegram message looks like:

[professor-farnsworth] Restic Backup Check (2025-12-10)


=== WARNING: Current Backup Status ===

2025-12-09 10:29 /path/to/backup/repos/server-bender/
2025-12-09 00:00 /path/to/backup/repos/server-fry/

=== INFO: Current Backup Status ===

2025-12-09 10:29 /path/to/backup/repos/server-bender/
2025-12-09 00:00 /path/to/backup/repos/server-fry/
2025-12-10 00:00 /path/to/backup/repos/server-leela/
2025-12-10 00:00 /path/to/backup/repos/server-zoidberg/
2025-12-10 00:00 /path/to/backup/repos/server-amy/
2025-12-10 00:00 /path/to/backup/repos/server-hermes/
2025-12-10 00:00 /path/to/backup/repos/server-nibbler/
2025-12-10 00:00 /path/to/backup/repos/server-kif/
2025-12-10 00:00 /path/to/backup/repos/server-scruffy/
2025-12-10 00:00 /path/to/backup/repos/server-calculon/
2025-12-10 00:00 /path/to/backup/repos/server-morbo/
2025-12-10 00:00 /path/to/backup/repos/server-zapp/

In this example, two repositories (server-bender and server-fry) have not been updated today, triggering a warning.

Repository Structure

The script expects a directory structure like this:

/home/backup/repos/
├── restic-server-leela/
│   ├── snapshots/
│   │   ├── 12345678
│   │   └── ...
│   └── ...
├── restic-server-zoidberg/
│   ├── snapshots/
│   └── ...
└── restic-server-nibbler/
    ├── snapshots/
    └── ...

Each subdirectory represents a separate restic repository, typically corresponding to one host or system being backed up.

Issues the script can detect and its limitations

1. Lock File Issues

When managing multiple remote repositories (e.g., 10 remotes with daily snapshots), you may encounter lock file conflicts (once or twice a month from my own experience). Restic uses lock files to prevent concurrent access to a repository. If a backup process crashes or is interrupted, the lock file might not be released, causing subsequent backup attempts to fail.

This script will not detect lock file issues directly, but it may show outdated snapshots if backups are failing due to locks.

2. Snapshot vs. Backup Success

This script only verifies that snapshot files exist and are recent. It does not check:

With restic check or restic restore, you can verify the integrity of your backups, but those checks are separate and should be performed on the backup host where restic secrets are available.

3. No Restore Verification

This monitoring approach does not test whether your backups can actually be restored. A snapshot file might exist but be corrupted, or the repository might have undetected issues.

4. Repository Access Permissions

The script requires read access to the repository directories and files (not the snapshots itself):

Setup Instructions

1. Create a Telegram Bot

  1. Open Telegram and search for @BotFather
  2. Send /newbot command
  3. Follow the prompts to name your bot and get your TELEGRAM_TOKEN
  4. Start a chat with your new bot
  5. Send any message to the bot, then visit https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates to find your TELEGRAM_CHAT_ID

2. Configure the Script

  1. Replace YOUR_BOT_TOKEN with your actual Telegram bot token
  2. Replace YOUR_CHAT_ID with your chat ID (use a group chat ID for team notifications)
  3. Set backup_base to your restic repositories directory
  4. Adjust LOG_FILE if you want logs stored elsewhere

3. Make It Executable

chmod +x restic-monitor.sh

4. Test the Script

./restic-monitor.sh

Check your Telegram for the test message.

5. Schedule Daily Execution

Add a cron job to run the script daily:

0 8 * * * /path/to/restic-monitor.sh

This example runs the check at 8 AM every day.

Conclusion

This simple bash script provides an effective way to monitor your restic backup repositories and receive daily status updates via Telegram. While it has important limitations—particularly around snapshot integrity and lack of restore verification—it serves as a valuable first line of defense in ensuring your backups are being created as expected.

Because this script does not need any restic repository secrets, the secrets can stay securely on the backup hosts. Integrity checks and restore tests can be performed separately; on the backup host which is the only system that has the restic secrets for its own repository. This separation of concerns allows for a more secure and efficient monitoring setup, while still ensuring that you are aware of any issues with backup creation in a timely manner.

Resources

Feedback

Have thoughts or experiences you'd like to share? I'd love to hear from you! Whether you agree, disagree, or have a different perspective, your feedback is always welcome. Drop me an email and let's start a conversation.

<​​​​simple-restic-backup-monitoring​​​@exiguus​.​​blog​​​>

Tags