Skip to content

Commit 5e2781f

Browse files
authored
Merge pull request #18 from buildplan/fix_error_trap
Add support for Slack and MS Teams notifications. Reflector main operations. Improve help.
2 parents e5a8679 + e312fe7 commit 5e2781f

File tree

4 files changed

+352
-93
lines changed

4 files changed

+352
-93
lines changed

README.md

Lines changed: 109 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -9,66 +9,67 @@ This script automates encrypted, deduplicated backups of local directories to a
99

1010
## Features
1111

12-
- **Client-Side Encryption**: All data is encrypted on your server *before* being uploaded, ensuring zero-knowledge privacy from the storage provider.
13-
- **Deduplication & Compression**: Saves significant storage space by only storing unique data blocks and applying compression.
14-
- **Snapshot-Based Backups**: Creates point-in-time snapshots, allowing you to easily browse and restore files from any backup date.
15-
- **Advanced Retention Policies**: Sophisticated rules to automatically keep daily, weekly, monthly, and yearly snapshots.
16-
- **Unified Configuration**: All settings are managed in a single, easy-to-edit `restic-backup.conf` file.
17-
- **Notification Support**: Sends detailed success, warning, or failure notifications to ntfy and/or Discord.
18-
- **System Friendly**: Uses `nice` and `ionice` to minimize CPU and I/O impact during backups.
19-
- **Multiple Operation Modes**: Supports standard backups, dry runs, integrity checks, difference summaries, and a safe, interactive restore mode.
20-
- **Concurrency Control & Logging**: Prevents multiple instances from running simultaneously and handles its own log rotation.
21-
- **Pre-run Validation**: Performs checks for required commands and repository connectivity before execution.
22-
- **Cron Job Monitoring**: Optional integration with [Healthchecks.io](https://healthchecks.io) for alerts if a backup job fails to run on schedule.
12+
- **Client-Side Encryption**: All data is encrypted on your server *before* being uploaded, ensuring zero-knowledge privacy from the storage provider.
13+
- **Deduplication & Compression**: Saves significant storage space by only storing unique data blocks and applying compression.
14+
- **Snapshot-Based Backups**: Creates point-in-time snapshots, allowing you to easily browse and restore files from any backup date.
15+
- **Advanced Retention Policies**: Sophisticated rules to automatically keep daily, weekly, monthly, and yearly snapshots.
16+
- **Unified Configuration**: All settings are managed in a single, easy-to-edit `restic-backup.conf` file.
17+
- **Notification Support**: Sends detailed success, warning, or failure notifications to ntfy, Discord, Slack, and Microsoft Teams.
18+
- **Flexible File Exclusions**: Exclude files and directories using either a dedicated exclusion file or by listing patterns directly in the configuration.
19+
- **System Friendly**: Uses `nice` and `ionice` to minimize CPU and I/O impact during backups.
20+
- **Multiple Operation Modes**: Supports standard backups, dry runs, integrity checks, difference summaries, and a safe, interactive restore mode.
21+
- **Concurrency Control & Logging**: Prevents multiple instances from running simultaneously and handles its own log rotation.
22+
- **Pre-run Validation**: Performs checks for required commands and repository connectivity before execution.
23+
- **Cron Job Monitoring**: Optional integration with [Healthchecks.io](https://healthchecks.io) for alerts if a backup job fails to run on schedule.
2324

2425
-----
2526

2627
## Usage
2728

28-
#### Run Modes:
29-
30-
- `sudo ./restic-backup.sh` - Run a standard backup silently (suitable for cron).
31-
- `sudo ./restic-backup.sh --verbose` - Run with live progress and detailed output.
32-
- `sudo ./restic-backup.sh --dry-run` - Preview changes without creating a new snapshot.
33-
- `sudo ./restic-backup.sh --check` - Verify repository integrity by checking a subset of data.
34-
- `sudo ./restic-backup.sh --check-full` - Run a full check verifying all repository data.
35-
- `sudo ./restic-backup.sh --test` - Validate configuration, permissions, and SSH connectivity.
36-
- `sudo ./restic-backup.sh --install-scheduler` - Run the interactive wizard to set up an automated backup schedule (systemd/cron).
37-
- `sudo ./restic-backup.sh --uninstall-scheduler` - Remove a schedule created by the wizard.
38-
- `sudo ./restic-backup.sh --restore` - Start the interactive restore wizard.
39-
- `sudo ./restic-backup.sh --forget` - Manually apply the retention policy and prune old data.
40-
- `sudo ./restic-backup.sh --diff` - Show a summary of changes between the last two snapshots.
41-
- `sudo ./restic-backup.sh --stats` - Display repository size, file counts, and stats.
42-
- `sudo ./restic-backup.sh --unlock` - Forcibly remove stale locks from the repository.
43-
- `sudo ./restic-backup.sh --snapshots` - List all available snapshots in the repository.
44-
- `sudo ./restic-backup.sh --snapshots-delete` - Permanently delete specific snapshots.
45-
- `sudo ./restic-backup.sh --init` - (One-time setup) Initialize the remote repository.
46-
- `sudo ./restic-backup.sh --help` - Displays help and all the flags.
47-
29+
### Run Modes
30+
31+
- `sudo ./restic-backup.sh` - Run a standard backup silently (suitable for cron).
32+
- `sudo ./restic-backup.sh --verbose` - Run with live progress and detailed output.
33+
- `sudo ./restic-backup.sh --dry-run` - Preview changes without creating a new snapshot.
34+
- `sudo ./restic-backup.sh --check` - Verify repository integrity by checking a subset of data.
35+
- `sudo ./restic-backup.sh --check-full` - Run a full check verifying all repository data.
36+
- `sudo ./restic-backup.sh --test` - Validate configuration, permissions, and SSH connectivity.
37+
- `sudo ./restic-backup.sh --fix-permissions --test` - Run tests and interactively auto-correct insecure file permissions.
38+
- `sudo ./restic-backup.sh --install-scheduler` - Run the interactive wizard to set up an automated backup schedule (systemd/cron).
39+
- `sudo ./restic-backup.sh --uninstall-scheduler` - Remove a schedule created by the wizard.
40+
- `sudo ./restic-backup.sh --restore` - Start the interactive restore wizard.
41+
- `sudo ./restic-backup.sh --forget` - Manually apply the retention policy and prune old data.
42+
- `sudo ./restic-backup.sh --diff` - Show a summary of changes between the last two snapshots.
43+
- `sudo ./restic-backup.sh --stats` - Display repository size, file counts, and stats.
44+
- `sudo ./restic-backup.sh --unlock` - Forcibly remove stale locks from the repository.
45+
- `sudo ./restic-backup.sh --snapshots` - List all available snapshots in the repository.
46+
- `sudo ./restic-backup.sh --snapshots-delete` - Permanently delete specific snapshots.
47+
- `sudo ./restic-backup.sh --init` - (One-time setup) Initialize the remote repository.
48+
- `sudo ./restic-backup.sh --help` - Displays help and all the flags.
4849

4950
> *Default log location: `/var/log/restic-backup.log`*
5051
5152
#### Diagnostics & Error Codes
5253

5354
The script uses specific exit codes for different failures to help with debugging automated runs.
5455

55-
- **Exit Code `1`:** A fatal configuration error, such as a missing `restic-backup.conf` file or required variable.
56-
- **Exit Code `5`:** Lock contention; another instance of the script is already running.
57-
- **Exit Code `10`:** A required command (like `restic` or `curl`) is not installed.
58-
- **Exit Code `11`:** The `RESTIC_PASSWORD_FILE` cannot be found.
59-
- **Exit Code `12`:** The script cannot connect to or access the Restic repository.
60-
- **Exit Code `13`:** A source directory in `BACKUP_SOURCES` does not exist or is not readable.
61-
- **Exit Code `14`:** The `EXCLUDE_FILE` is not readable.
62-
- **Exit Code `15`:** The `LOG_FILE` is not writable.
63-
- **Exit Code `20`:** The `restic init` command failed.
56+
- **Exit Code `1`:** A fatal configuration error, such as a missing `restic-backup.conf` file or required variable.
57+
- **Exit Code `5`:** Lock contention; another instance of the script is already running.
58+
- **Exit Code `10`:** A required command (like `restic` or `curl`) is not installed.
59+
- **Exit Code `11`:** The `RESTIC_PASSWORD_FILE` cannot be found.
60+
- **Exit Code `12`:** The script cannot connect to or access the Restic repository.
61+
- **Exit Code `13`:** A source directory in `BACKUP_SOURCES` does not exist or is not readable.
62+
- **Exit Code `14`:** The `EXCLUDE_FILE` is not readable.
63+
- **Exit Code `15`:** The `LOG_FILE` is not writable.
64+
- **Exit Code `20`:** The `restic init` command failed.
6465

6566
-----
6667

6768
## File Structure
6869

6970
All files should be placed in a single directory (e.g., `/root/scripts/backup`).
7071

71-
```
72+
```bash
7273
/root/scripts/backup/
7374
├── restic-backup.sh (main script)
7475
├── restic-backup.conf (settings and credentials)
@@ -103,7 +104,7 @@ sudo apt-get update && sudo apt-get install -y restic jq gnupg curl bzip2 util-l
103104
sudo dnf install -y restic jq gnupg curl bzip2 util-linux coreutils less
104105
```
105106

106-
You could also download and install the latest version of `restic`.
107+
You could also download and install the latest version of `restic`.
107108

108109
**Note:** While `restic` can be installed from your system's package manager, it is often an older version. It is **recommended** to install it manually or allow the script's built-in auto-updater to fetch the latest [official version](https://github.com/restic/restic/releases) for you.
109110

@@ -138,31 +139,32 @@ sudo mv restic_* /usr/local/bin/restic
138139
| **`coreutils`** | Provides essential commands used throughout the script, such as `date`, `grep`, `sed`, `chmod`, `mv`, and `mktemp`. |
139140
| **`less`** | Paging through the list of files during an interactive restore (`--restore` mode). |
140141

142+
-----
141143

142144
### 2. Configure Passwordless SSH Login (Recommended)
143145

144146
The most reliable way for the script to connect to a remote server is via an SSH config file.
145147

146-
1. **Generate a root SSH key** if one doesn't already exist:
148+
1. **Generate a root SSH key** if one doesn't already exist:
147149

148150
```sh
149151
sudo ssh-keygen -t ed25519
150152
```
151153

152154
(Press Enter through all prompts).
153155

154-
2. **Add your public key** to the remote server's authorized keys. For a Hetzner Storage Box, you can paste the contents of `sudo cat /root/.ssh/id_ed25519.pub` into the control panel.
156+
2. **Add your public key** to the remote server's authorized keys. For a Hetzner Storage Box, you can paste the contents of `sudo cat /root/.ssh/id_ed25519.pub` into the control panel.
155157
156-
3. **Create an SSH config file** to define an alias for your connection:
158+
3. **Create an SSH config file** to define an alias for your connection:
157159
158160
```sh
159161
# Open the file in an editor
160162
sudo nano /root/.ssh/config
161163
```
162164
163-
4. **Add the following content**, adjusting the details for your server:
165+
4. **Add the following content**, adjusting the details for your server:
164166
165-
```
167+
```bash
166168
Host storagebox
167169
HostName u123456.your-storagebox.de
168170
User u123456-sub4
@@ -172,7 +174,7 @@ The most reliable way for the script to connect to a remote server is via an SSH
172174
ServerAliveCountMax 240
173175
```
174176
175-
5. **Set secure permissions** and test the connection:
177+
5. **Set secure permissions** and test the connection:
176178
177179
```sh
178180
sudo chmod 600 /root/.ssh/config
@@ -183,13 +185,13 @@ The most reliable way for the script to connect to a remote server is via an SSH
183185
184186
### 3. Place and Configure Files
185187
186-
1. Create your script directory:
188+
1. Create your script directory:
187189
188190
```sh
189191
mkdir -p /root/scripts/backup && cd /root/scripts/backup
190192
```
191193
192-
2. Download the script, configuration, and excludes files from the repository:
194+
2. Download the script, configuration, and excludes files from the repository:
193195
194196
```sh
195197
# Download the main script
@@ -202,25 +204,70 @@ The most reliable way for the script to connect to a remote server is via an SSH
202204
curl -LO https://github.com/buildplan/restic-backup-script/raw/refs/heads/main/restic-excludes.txt
203205
```
204206
205-
3. **Make the script executable**:
207+
3. **Make the script executable**:
206208
207209
```sh
208210
chmod +x restic-backup.sh
209211
```
210212
211-
4. **Set secure permissions** for your configuration file:
213+
4. **Set secure permissions** for your configuration file:
212214
213215
```sh
214216
chmod 600 restic-backup.conf
215217
```
216218
217-
5. **Edit `restic-backup.conf` and `restic-excludes.txt`** to specify your repository path, source directories, notification settings, and exclusion patterns.
219+
5. **Edit `restic-backup.conf` and `restic-excludes.txt`** to specify your repository path, source directories, notification settings, and exclusion patterns.
220+
221+
### Configuration (`restic-backup.conf`)
222+
223+
All script behavior is controlled by the `restic-backup.conf` file. Below is an overview of the key settings available.
224+
225+
#### Core Settings
226+
227+
- `RESTIC_REPOSITORY`: The connection string for your remote storage.
228+
- `RESTIC_PASSWORD_FILE`: The absolute path to the file containing your repository's encryption password.
229+
- `BACKUP_SOURCES`: A list of local directories to back up. Use Bash array syntax `("/path/one" "/path/two")` to handle spaces correctly.
230+
231+
#### Retention Policy
232+
233+
You can define how many snapshots to keep for various timeframes. The script will automatically remove older snapshots that fall outside these rules.
234+
235+
- `KEEP_LAST`: Number of the most recent snapshots to keep.
236+
- `KEEP_DAILY`: Number of daily snapshots to keep.
237+
- `KEEP_WEEKLY`: Number of weekly snapshots to keep.
238+
- `KEEP_MONTHLY`: Number of monthly snapshots to keep.
239+
- `KEEP_YEARLY`: Number of yearly snapshots to keep.
240+
241+
#### Notifications
242+
243+
The script can send detailed status notifications to multiple services. Each can be enabled or disabled individually.
244+
245+
- `NTFY_ENABLED`: Set to `true` to enable ntfy notifications.
246+
- `DISCORD_ENABLED`: Set to `true` to enable Discord notifications.
247+
- `SLACK_ENABLED`: Set to `true` to enable Slack notifications.
248+
- `TEAMS_ENABLED`: Set to `true` to enable Microsoft Teams notifications.
249+
- You must also provide the corresponding `_URL` and `_TOKEN` for each service you enable.
250+
251+
#### Exclusions
252+
253+
You have two ways to exclude files and directories from your backups:
254+
255+
1. **`EXCLUDE_FILE`**: Point this to a text file (like `restic-excludes.txt`) containing one exclusion pattern per line.
256+
2. **`EXCLUDE_PATTERNS`**: A space-separated list of patterns to exclude directly in the configuration file (e.g., `*.tmp *.log`).
257+
258+
#### Performance and Maintenance
259+
260+
- `LOW_PRIORITY`: Set to `true` to run the backup with lower CPU (`nice`) and I/O (`ionice`) priority, minimizing impact on other services.
261+
- `CHECK_AFTER_BACKUP`: Set to `true` to automatically run a repository integrity check after each successful backup.
262+
- `PRUNE_AFTER_FORGET`: Set to `true` to automatically prune the repository after applying the retention policy, which frees up storage space.
263+
264+
-----
218265

219266
### 4. Initial Repository Setup
220267

221268
Before the first backup, you need to create the repository password file and initialize the remote repository.
222269

223-
1. **Create the password file.** This stores the encryption key for your repository. **Guard this file carefully!**
270+
1. **Create the password file.** This stores the encryption key for your repository. **Guard this file carefully!**
224271

225272
```sh
226273
# Replace 'your-very-secure-password' with a strong, unique password
@@ -230,7 +277,7 @@ Before the first backup, you need to create the repository password file and ini
230277
sudo chmod 400 /root/.restic-password
231278
```
232279

233-
2. **Initialize the repository.** Run the script with the `--init` flag:
280+
2. **Initialize the repository.** Run the script with the `--init` flag:
234281

235282
```sh
236283
# Navigate to your script directory
@@ -244,12 +291,14 @@ Before the first backup, you need to create the repository password file and ini
244291

245292
The easiest and most reliable way to schedule your backups is to use the script's built-in interactive wizard. It will guide you through creating and enabling either a modern `systemd timer` (recommended) or a traditional `cron job`.
246293
247-
1. Navigate to your script directory:
294+
1. Navigate to your script directory:
295+
248296
```sh
249297
cd /root/scripts/backup
250298
```
251299
252-
2. Run the scheduler installation wizard:
300+
2. Run the scheduler installation wizard:
301+
253302
```sh
254303
sudo ./restic-backup.sh --install-scheduler
255304
```
@@ -262,13 +311,13 @@ If you prefer to manage the schedule manually instead of using the wizard, you c
262311
263312
To run the backup automatically, edit the root crontab.
264313
265-
1. Open the crontab editor:
314+
1. Open the crontab editor:
266315
267316
```sh
268317
sudo crontab -e
269318
```
270319
271-
2. Add the following lines to schedule your backups and maintenance.
320+
2. Add the following lines to schedule your backups and maintenance.
272321
273322
```crontab
274323
# Define a safe PATH that includes the location of restic
@@ -284,6 +333,7 @@ To run the backup automatically, edit the root crontab.
284333
0 3 * * 0 [ $(date +\%d) -le 07 ] && /root/scripts/backup/restic-backup.sh --check-full > /dev/null 2>&1
285334
286335
```
336+
287337
*For pune job in your `restic-backup.conf`, set `PRUNE_AFTER_FORGET=true`.*
288338
*For more details on how forget flag work, see the [official Restic documentation on removing snapshots](https://restic.readthedocs.io/en/stable/060_forget.html).*
289339
*Redirecting output to `/dev/null` is recommended, as the script handles its own logging and notifications.*

restic-backup.conf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ LOG_RETENTION_DAYS="30"
6363
# Enable notifications
6464
NTFY_ENABLED=true
6565
DISCORD_ENABLED=false
66+
SLACK_ENABLED=false
67+
TEAMS_ENABLED=false
6668

6769
# ntfy settings
6870
NTFY_TOKEN="xxxxxxxxxxxxxxxxxxx"
@@ -76,6 +78,12 @@ NTFY_PRIORITY_FAILURE=4
7678
# Discord webhook (if enabled)
7779
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/your/webhook_url_here"
7880

81+
# Slack webhook (if enabled)
82+
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/your/webhook_url_here"
83+
84+
# Microsoft Teams webhook (if enabled)
85+
TEAMS_WEBHOOK_URL="https://your-tenant.webhook.office.com/webhookb2/your/webhook_url_here"
86+
7987
# --- Healthchecks.io ---
8088
# URL for the "dead man's switch" service to ping on successful completion.
8189
# Leave blank to disable.
@@ -88,6 +96,10 @@ CHECK_AFTER_BACKUP=false
8896
# Prune repository after forget (removes unreferenced data)
8997
PRUNE_AFTER_FORGET=true
9098

99+
# Automatically fix insecure permissions on config/password files (600/400).
100+
# Enable only for interactive maintenance runs, not in cron/systemd:
101+
# AUTO_FIX_PERMS=false
102+
91103
# --- Exclusions ---
92104
# File containing exclude patterns (one per line)
93105
EXCLUDE_FILE="/etc/restic-excludes.txt"

0 commit comments

Comments
 (0)