Encrypted, Automated Backups with Restic
This guide provides a comprehensive walkthrough for installing, configuring, and operating automated backup system on Linux system using Restic. It is built around a shell script that handles encryption, retention policies, logging, notifications, and reliable unattended operation.
This document covers first-time setup, daily use, data restoration, repository maintenance, and troubleshooting.
Overview & Features
This backup solution provides the following key features:
- Secure Backups: Employs Restic for client-side encryption, ensuring data is secure before it leaves server. It also supports deduplication and compression to save storage space.
- Centralized Configuration: All settings—sources, retention, performance, notifications, and exclusions—are managed in a single, well-commented
restic-backup.conffile. - Automation Script: The
restic-backup.shscript includes:- Pre-flight Checks: Validates dependencies, configuration, and repository connectivity before every run.
- Concurrency Control: Uses
flockto prevent multiple backup instances from running simultaneously. - Safe Operations: Features an interactive restore wizard with a dry-run mode, integrity checks, and stale lock handling.
- Automated Maintenance: Manages log rotation and applies sophisticated retention policies (
--forgetand--prune).
- Comprehensive Monitoring: Integrates with ntfy and Discord for detailed success, warning, and failure notifications, and supports Healthchecks.io for “dead man’s switch” monitoring.
System Requirements
- A modern Linux distribution with Bash and essential command-line utilities.
- A remote SFTP server (e.g., Hetzner Storage Box) or another Restic-supported backend.
- The required software packages, detailed in the installation section.
File Structure
It is a good idean to set restrictive permissions to protect configuration and credentials.
/root/scripts/backup/
├── restic-backup.sh # The main executable script (permissions: 700)
├── restic-backup.conf # Settings and credentials (permissions: 600)
└── restic-excludes.txt # Patterns to exclude from backups (optional)
1. Installation
Step 1: Install Prerequisites
The script relies on several common packages. Install them with system’s package manager.
On Debian/Ubuntu:
sudo apt-get update && sudo apt-get install -y restic jq gnupg curl bzip2 util-linux coreutils less
On CentOS/RHEL/Fedora:
sudo dnf install -y restic jq gnupg curl bzip2 util-linux coreutils less
| Package | Purpose |
|---|---|
restic | The core backup engine. The script can also auto-install/update this. |
jq | Required for the --diff command to parse JSON output. |
curl | Used for sending notifications and checking for updates. |
bzip2 | Required for decompressing the Restic binary during auto-updates. |
gnupg | Provides gpg to verify PGP signatures during secure auto-updates. |
util-linux | Provides flock for concurrency control and ionice for I/O scheduling. |
coreutils | Provides essential commands (date, grep, mktemp, etc.). |
less | Used for navigating file lists in the interactive --restore mode. |
Step 2: Download and Prepare Files
Create the directory and download the script files.
# Create the directory and navigate into it
mkdir -p /root/scripts/backup && cd /root/scripts/backup
# Download the script, config template, and excludes file
curl -LO https://github.com/buildplan/restic-backup-script/raw/main/restic-backup.sh
curl -LO https://github.com/buildplan/restic-backup-script/raw/main/restic-backup.conf
curl -LO https://github.com/buildplan/restic-backup-script/raw/main/restic-excludes.txt
# Set secure, executable permissions
chmod 700 restic-backup.sh
chmod 600 restic-backup.conf
Step 3: Let the Script Manage Restic (Recommended)
When run from an interactive terminal, the script will offer to download and install the latest version of Restic. This process is secure: it fetches the official PGP-signed checksums from GitHub and verifies them before installing the binary. This is the recommended way to ensure system has latest version of Restic.
2. Configuration
All operational settings are managed in restic-backup.conf. This centralized approach simplifies maintenance and keeps secrets out of the main script.
Key Configuration Fields:
-
Repository & Password
RESTIC_REPOSITORY: The location of backup repository. For SFTP, use the formatsftp:alias:/remote/path, wherealiasis an entry in/root/.ssh/config.RESTIC_PASSWORD_FILE: The absolute path to a file containing repository’s encryption password (e.g.,/root/.restic-password).
-
Backup Sources
BACKUP_SOURCES: A Bash array of absolute paths to back up. Each path must be a separate, quoted element. This syntax correctly handles paths with spaces.
# Correct array syntax BACKUP_SOURCES=("/var/www" "/home/user/my documents") -
Backup Options
BACKUP_TAG: A tag applied to each snapshot for easy identification (e.g.,daily-$(hostname)).COMPRESSION: Set toauto,max, oroff.maxis recommended for SFTP targets.ONE_FILE_SYSTEM: Iftrue, the backup will not cross filesystem boundaries (e.g., skip mounted drives within a source directory).
-
Retention Policy
KEEP_LAST,KEEP_DAILY,KEEP_WEEKLY,KEEP_MONTHLY,KEEP_YEARLY: Define how many snapshots to keep for each period during a--forgetoperation.
-
Performance
LOW_PRIORITY: Set totrueto useniceandioniceto reduce the script’s impact on system performance.
-
Logging
LOG_FILE: The path to the log file (e.g.,/var/log/restic-backup.log).MAX_LOG_SIZE_MB&LOG_RETENTION_DAYS: Configure automatic log rotation to manage disk space.
-
Notifications & Monitoring
NTFY_ENABLED/DISCORD_ENABLED: Enable and configure webhook URLs and tokens to receive alerts.HEALTHCHECKS_URL: An optional URL to ping on successful completion, enabling “dead man’s switch” monitoring.
-
Exclusions
EXCLUDE_FILE: Path to a file containing patterns to exclude, one per line.EXCLUDE_PATTERNS: A space-separated string of patterns for quick exclusions.
3. First-Time Setup
Step 1: Configure Passwordless SSH Access (for SFTP)
Using an SSH config alias is the most reliable way to connect to remote repository.
-
Generate an SSH key for the
rootuser if one doesn’t exist:sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519(Press Enter to accept the defaults).
-
Add the public key (
/root/.ssh/id_ed25519.pub) to remote server’sauthorized_keysfile. -
Create an SSH config file at
/root/.ssh/config:Host storagebox HostName u123456.your-storagebox.de User u123456 Port 23 IdentityFile /root/.ssh/id_ed25519 ServerAliveInterval 60 -
Set permissions and test the connection:
sudo chmod 600 /root/.ssh/config sudo ssh storagebox pwd # This should connect without a password
Step 2: Create the Repository Password File
This file holds the master encryption key for backup repository. Without this password, backed-up data is unrecoverable.
# Replace 'your-very-secure-password' with a strong, unique password
echo 'your-very-secure-password' | sudo tee /root/.restic-password
# Set read-only permissions for root
sudo chmod 400 /root/.restic-password
Step 3: Edit the Configuration File
Open /root/scripts/backup/restic-backup.conf and set RESTIC_REPOSITORY, RESTIC_PASSWORD_FILE, BACKUP_SOURCES, and desired notification and retention settings.
Step 4: Initialize the Repository
Run the script with the --init flag to create the Restic repository on remote target. This is a one-time operation.
sudo /root/scripts/backup/restic-backup.sh --init
4. Usage & Daily Operations
The Backup Lifecycle
When run, the script performs the following sequence:
- Pre-flight Checks: Verifies all dependencies, configuration files, source directories, and repository connectivity.
- Locking: Creates a lock file to ensure only one instance runs at a time.
- Backup: Executes
restic backupwith the options defined in configuration. - Retention: (On default run) Applies the
forgetandprunepolicy if enabled. - Logging & Notifications: Writes a detailed log and sends a status notification.
- Health Check: Pings Healthchecks.io URL if configured.
Common Commands
- Standard Backup:
sudo ./restic-backup.sh- Runs a standard backup and applies the retention policy. Designed for cron jobs.
- Verbose Mode:
sudo ./restic-backup.sh --verbose- Shows detailed, real-time progress in the terminal.
- Dry Run:
sudo ./restic-backup.sh --dry-run- Previews what files would be changed without creating a snapshot.
- Test Configuration:
sudo ./restic-backup.sh --test- Runs all pre-flight checks and reports success or failure. Perfect for validating setup.
5. Scheduling with Cron
Automate backups by adding the script to the root user’s crontab.
- Open the crontab editor:
sudo crontab -e - Add jobs for backup, retention, and periodic full checks.
# Ensure PATH includes /usr/local/bin where restic is often installed
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Run a standard backup every day at 3:00 AM
0 3 * * * /root/scripts/backup/restic-backup.sh > /dev/null 2>&1
# Apply retention policy every Sunday at 4:00 AM (if not done after each backup)
0 4 * * 0 /root/scripts/backup/restic-backup.sh --forget > /dev/null 2>&1
# Run a full integrity check on the first Sunday of the month at 5:00 AM
0 5 * * 0 [ $(date +\%d) -le 07 ] && /root/scripts/backup/restic-backup.sh --check-full > /dev/null 2>&1
Redirecting output to
/dev/nullis recommended, as the script handles its own logging and notifications.
6. Restoring Data
The script includes a safe, interactive restore wizard to guide through the process.
To start the wizard, run: sudo ./restic-backup.sh --restore
The wizard will:
- List available snapshots to choose from.
- Ask if user wants to view the contents of the selected snapshot to find specific files.
- Prompt for a destination path.
- Allow user to specify particular files or directories to restore, or restore the entire snapshot.
- Perform a dry run first to show user exactly what will happen.
- Ask for final confirmation before starting the actual restore.
Ownership Handling: If user restores to a directory under
/home(e.g.,/home/someuser/restore), the script will detect this and offer to automaticallychownthe restored files to the correct user.
7. Repository Maintenance
Listing and Deleting Snapshots
- List all snapshots:
sudo ./restic-backup.sh --snapshots - Interactively delete snapshots:
sudo ./restic-backup.sh --snapshots-delete- This provides a guided workflow to permanently remove one or more specific snapshots and then optionally prune the repository to reclaim space.
Integrity Checks
- Standard Check:
sudo ./restic-backup.sh --check- Verifies repository integrity by checking a random subset of data packs. This is fast and ideal for frequent checks.
- Full Check:
sudo ./restic-backup.sh --check-full- Verifies all data in the repository. This is slow and bandwidth-intensive but provides a complete guarantee of data integrity. Recommended to run monthly.
Handling Stale Locks
If a backup is interrupted, it may leave a stale lock file in the repository. The script prevents this with flock, but if a lock is present from another machine:
- Remove stale locks:
sudo ./restic-backup.sh --unlock- The script will first check for other running
resticprocesses and ask for confirmation before forcibly removing the lock.
- The script will first check for other running
8. Troubleshooting & Error Codes
Review the log file at /var/log/restic-backup.log for detailed error messages. The script uses specific exit codes to aid in debugging.
| Code | Meaning |
|---|---|
1 | Fatal Configuration Error: restic-backup.conf is missing or a required variable is not set. |
5 | Lock Contention: Another instance of the script is already running. |
10 | Missing Dependency: A required command (restic, curl, jq, etc.) is not installed. |
11 | Password File Error: The RESTIC_PASSWORD_FILE cannot be found or read. |
12 | Repository Access Error: Cannot connect to the repository. Check credentials, SSH config, or network connectivity. |
13 | Source Path Error: A directory in BACKUP_SOURCES does not exist or is not readable. |
14 | Exclude File Error: The EXCLUDE_FILE is defined but not readable. |
15 | Log File Error: The LOG_FILE or its directory is not writable. |
20 | Initialization Failed: The restic init command failed. |
9. Upgrading and Uninstalling
Upgrading the Script
When run interactively, the script automatically checks for new versions on GitHub. If an update is found, it will prompt to download and install it. The process verifies a checksum to ensure the downloaded file is authentic.
Uninstalling
- Remove the cron jobs with
sudo crontab -e. - Delete the script directory:
sudo rm -rf /root/scripts/backup. - Remove the password file:
sudo rm /root/.restic-password. - Remove the log file:
sudo rm /var/log/restic-backup.log.
This will not affect any data already stored in remote Restic repository.