Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple profile configuration #45

Merged
merged 38 commits into from
Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
765523c
moved env variables out into separate .env files, with inheritance fr…
mfeif Jan 7, 2019
e186cc3
oops; wrong way to declare env variable for $HOME
mfeif Jan 7, 2019
a006731
Merge remote-tracking branch 'origin/master' into multi-repo
gerardbosch Jan 14, 2022
20705a0
Extract configuration to env profiles
gerardbosch Jan 14, 2022
f136bab
Merge remote-tracking branch 'origin/master' into multi-repo
gerardbosch Jan 17, 2022
1be6878
Merge remote-tracking branch 'origin/master' into multi-repo
gerardbosch Jan 17, 2022
53e246c
Add root note on README
gerardbosch Jan 17, 2022
7a31380
Merge remote-tracking branch 'origin/master' into multi-repo
gerardbosch Jan 17, 2022
13371f8
Align with the latest additions from master
gerardbosch Jan 17, 2022
58ac90d
Test contribution to PR
erikw Jan 17, 2022
3842699
Brush up documentation in .env files
erikw Jan 17, 2022
e534752
Fix .backup_exclude per backup path
erikw Jan 17, 2022
9a889c9
Prepare CHANGELOG.md
erikw Jan 17, 2022
80ed04c
Clarify PREFIX installation
erikw Jan 17, 2022
d4c7e56
Document in restic_*.sh how to run the scripts
erikw Jan 17, 2022
f9e44fb
Make TL;DR in README more concise
erikw Jan 17, 2022
d77c042
Correct comment about restic crashing
erikw Jan 17, 2022
424bb0c
Find backup exlude files in home directores again
erikw Jan 17, 2022
a49f672
Explain how backup exclude files works in README
erikw Jan 17, 2022
9eb647d
Fix spell
gerardbosch Jan 18, 2022
b6b7764
Update usr/local/sbin/restic_backup.sh
erikw Jan 18, 2022
6c16b60
Update usr/local/sbin/restic_backup.sh
erikw Jan 18, 2022
4675d99
Extract global exclude file into env RESTIC_BACKUP_EXCLUDE
gerardbosch Jan 18, 2022
38f9d5e
Merge remote-tracking branch 'origin/multi-repo' into multi-repo
gerardbosch Jan 18, 2022
47a6155
Align suggested function name with the call-site name
gerardbosch Jan 18, 2022
d689f80
Add sudo note on make install
gerardbosch Jan 18, 2022
9c384bc
Fix exclusion args function return
gerardbosch Jan 18, 2022
066f6f9
Fix duplicate exclusion argument entries
gerardbosch Jan 18, 2022
2ba0864
Remove automatic /home/user\*/.backup_exclude feature
erikw Jan 18, 2022
ef41587
After removing the home exclusions feature, sort_unique became dead code
gerardbosch Jan 19, 2022
1494871
README update suggestions from @mfeif
erikw Jan 31, 2022
e898fef
Fix URL sytnax
erikw Jan 31, 2022
cda0230
Random sleep on service execution
erikw Jan 31, 2022
0a4475c
Notes on password setup
erikw Jan 31, 2022
c2c6e75
README note
erikw Jan 31, 2022
df411de
Replace bash RANDOM with simpler to read shuf(1)
erikw Jan 31, 2022
ccd769d
s/RESTIC_BACKUP_EXCLUDE/RESTIC_BACKUP_EXCLUDE_FILE/
erikw Jan 31, 2022
ce62520
PR feedback fixes in README
erikw Feb 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Prevent check-in of these sensitive files. Instead they are generated from the corresponding *.template file.
/etc/restic/b2_pw.txt
/etc/restic/b2_env.sh
etc/restic/pw.txt
etc/restic/_global.env
etc/restic/default.env

# IntelliJ
.idea/
*.iml
# VSCode
.vscode/
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Extract all variables from `restic_backup.sh` to allow for having multiple backup profiles.

### Fixed
- `restic_backup.sh` now finds `.backup_exclude` files on each backup path as intended.

## [1.0.1] - 2021-12-03
### Fixed
Expand Down
14 changes: 7 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ SRCS_SCRIPTS = $(filter-out %cron_mail, $(wildcard usr/local/sbin/*))
SRCS_CONF = $(sort $(patsubst %.template, %, $(wildcard etc/restic/*)))
SRCS_SYSTEMD = $(wildcard etc/systemd/system/*)

# Just set PREFIX in environment, like
# $ PREFIX=/tmp/test make
# To change the installation root path, set the PREFIX variable in your shell's environment, like:
# $ PREFIX=/usr/local make install
# $ PREFIX=/tmp/test make install
DEST_SCRIPTS = $(PREFIX)/usr/local/sbin
DEST_CONF = $(PREFIX)/etc/restic
DEST_SYSTEMD = $(PREFIX)/etc/systemd/system

INSTALLED_FILES = $(addprefix $(PREFIX)/, $(SRCS_SCRIPTS) $(SRCS_CONF) $(SRCS_SYSTEMD)) \
$(DEST_CONF)/b2_env.sh $(DEST_CONF)/b2_pw.txt
INSTALLED_FILES = $(addprefix $(PREFIX)/, $(SRCS_SCRIPTS) $(SRCS_CONF) $(SRCS_SYSTEMD))

### Targets ###
# target: all - Default target.
Expand All @@ -35,16 +35,16 @@ install-scripts:

# Copy templates to new files with restricted permissions.
# Why? Because the non-template files are git-ignored to prevent that someone who clones or forks this repo checks in their sensitive data like the B2 password!
etc/restic/b2_env.sh etc/restic/b2_pw.txt:
etc/restic/_global.env etc/restic/default.env etc/restic/pw.txt:
install -m 0600 $@.template $@

# target: install-conf - Install restic configuration files.
# will create these files locally only if they don't already exist
# | means that dependencies are order-only i.e. only created if they don't already exist.
# `|` means that dependencies are order-only, i.e. only created if they don't already exist.
install-conf: | $(SRCS_CONF)
install -d $(DEST_CONF)
install -b -m 0600 $(SRCS_CONF) $(DEST_CONF)
$(RM) etc/restic/b2_env.sh etc/restic/b2_pw.txt
$(RM) etc/restic/_global.env etc/restic/default.env etc/restic/pw.txt

# target: install-systemd - Install systemd timer and service files.
install-systemd:
Expand Down
138 changes: 110 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![Open issues](https://img.shields.io/github/issues/erikw/restic-systemd-automatic-backup)](https://github.com/erikw/restic-systemd-automatic-backup/issues)
[![Closed issues](https://img.shields.io/github/issues-closed/erikw/restic-systemd-automatic-backup?color=success)](https://github.com/erikw/restic-systemd-automatic-backup/issues?q=is%3Aissue+is%3Aclosed)
[![Closed PRs](https://img.shields.io/github/issues-pr-closed/erikw/restic-systemd-automatic-backup?color=success)](https://github.com/erikw/restic-systemd-automatic-backup/pulls?q=is%3Apr+is%3Aclosed)
[![License](https://img.shields.io/badge/license-BSD--3-blue)](LICENSE.txt)
[![License](https://img.shields.io/badge/license-BSD--3-blue)](LICENSE)
[![OSS Lifecycle](https://img.shields.io/osslifecycle/erikw/restic-systemd-automatic-backup)](https://github.com/Netflix/osstracker)
[![Latest tag](https://img.shields.io/github/v/tag/erikw/restic-systemd-automatic-backup)](https://github.com/erikw/restic-systemd-automatic-backup/tags)
<br>
Expand All @@ -25,13 +25,56 @@ Unfortunately restic does not come pre-configured with a way to run automated ba

Here follows a step-by step tutorial on how to set it up, with my sample script and configurations that you can modify to suit your needs.


Note, you can use any of the supported [storage backends](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html). The setup should be similar but you will have to use other configuration variables to match your backend of choice.

# Requirements
* `restic >=v0.9.6`

# Set up
# TL;DR Setup
1. Create B2 credentials as instructed [below](#1-create-backblaze-b2-account)
1. Install config and scripts:
```console
$ sudo make install
```
gerardbosch marked this conversation as resolved.
Show resolved Hide resolved
☝ **Note**: `sudo` is required here, as some files are installed into system directories (`/etc/`
and `/usr/sbin`). Have a look to the `Makefile` to know more.
1. Fill out configuration values (edit with sudo):
* `/etc/restic/pw.txt` - Contains the password (single line) to be used by restic to encrypt the repository files. Should be different than your B2 password!
* `/etc/restic/_global.env` - Global environment variables.
* `/etc/restic/default.env` - Profile specific environment variables (multiple profiles can be defined by copying to `/etc/restic/something.env`).
* `/etc/restic/backup_exclude` - List of file patterns to ignore. This will trim down your backup size and the speed of the backup a lot when done properly!
1. Initialize remote repo as described [below](#3-initialize-remote-repo)
1. Configure [how often](https://www.freedesktop.org/software/systemd/man/systemd.time.html#Calendar%20Events) back up should be made.
* Edit if needed `OnCalendar` in `/etc/systemd/system/restic-check@.timer`.
1. Enable automated backup for starting with the system (`enable` creates symlinks):
```console
$ sudo systemctl start restic-backup@default.timer
$ sudo systemctl enable restic-backup@default.timer
```
1. And run an immediate backup if you want (if not, it will run on daily basis):
```console
$ sudo systemctl start restic-backup@default
```
1. Watch its progress with Systemd journal:
```console
$ journalctl -f --lines=50 -u restic-backup@default
```
1. Verify the backup
```console
$ sudo -i
$ source /etc/restic/default.env
$ restic snapshots
```
1. (optional) Define multiple profiles: just make a copy of the `default.env` and use the defined profile name in place of `default` to run backups or enable timers. Notice that the value after `@` works as a parameter.
1. (optional) Enable the check job that verifies that the backups for the profile are all intact.
```console
$ sudo systemctl start restic-check@default.timer
$ sudo systemctl enable restic-check@default.timer
````
1. (optional) Setup email on failure as described [here](#8-email-notification-on-failure)

# Step-by-step and manual setup
This is a more detailed explanation than the TL;DR section that will give you more understanding in the setup, and maybe inspire you to develop your own setup based on this one even!

Tip: The steps in this section will instruct you to copy files from this repo to system directories. If you don't want to do this manually, you can use the Makefile:

Expand All @@ -40,65 +83,97 @@ $ git clone https://github.com/erikw/restic-systemd-automatic-backup.git && cd $
$ sudo make install
````

Arch Linux users can install the aur package [restic-systemd-automatic-backup](https://aur.archlinux.org/packages/restic-systemd-automatic-backup/) e.g. :
Arch Linux users can install the aur package [restic-systemd-automatic-backup](https://aur.archlinux.org/packages/restic-systemd-automatic-backup/) e.g.:
```console
$ yaourt -S restic-systemd-automatic-backup
````

## 1. Create Backblaze B2 account

First, see this official Backblaze [tutorial](https://help.backblaze.com/hc/en-us/articles/115002880514-How-to-configure-Backblaze-B2-with-Restic-on-Linux) on restic, and follow the instructions ("Create Backblaze account with B2 enabled") there on how to create a new B2 bucket.
First, see this official Backblaze [tutorial](https://help.backblaze.com/hc/en-us/articles/4403944998811-Quickstart-Guide-for-Restic-and-Backblaze-B2-Cloud-Storage) on restic, and follow the instructions ("Create Backblaze account with B2 enabled") there on how to create a new B2 bucket. In general, you'd want a private bucket, without B2 encryption (restic does the encryption client side for us) and without the object lock feature.

Take note of the your account ID, application key and password for the next steps.
Take note of the your account ID and application key for the next steps. It's a good idea to create a separate application key that has access only to the newly created b2 bucket you created.


## 2. Configure your B2 account locally

> **Attention!** Going the manual way requires that most of the following commands are run as root.

Put these files in `/etc/restic/`:
* `b2_env.sh`: Fill this file out with your B2 bucket settings etc. The reason for putting these in a separate file is that it can be used also for you to simply source, when you want to issue some restic commands. For example:
* `default.env`: Fill this file out with your B2 bucket settings etc. The reason for putting these in a separate file is that it can be used also for you to simply source, when you want to issue some restic commands. For example:
```console
$ source /etc/restic/default.env
$ restic snapshots # You don't have to supply all parameters like --repo, as they are now in your environment!
````
* `pw.txt`: This file should contain the restic password used to encrypt the repository. This is a new password what soon will be used when initializing the new repository. It should be unique to this restic backup repository and is needed for restoring from it. Don't re-use your B2 login password, this should be different. For example you can generate a 128 character password (must all be on one line) with:

```console
$ source /etc/restic/b2_env.sh
$ restic snapshots # You don't have to supply all parameters like --repo, as they are now in your environment!
````
* `b2_pw.txt`: This file should contain the restic repository password. This is a new password what soon will be used when initializing the new repository. It should be unique to this restic backup repository and is needed for restoring from it. Don't re-use your B2 login password, this should be different.
$ openssl rand -base64 128 | tr -d '\n' > /etc/restic/pw.txt
```

## 3. Initialize remote repo
Now we must initialize the repository on the remote end:
```console
$ source /etc/restic/b2_env.sh
$ sudo -i
$ source /etc/restic/default.env
$ restic init
```

## 4. Script for doing the backup
Put this file in `/usr/local/sbin`:
* `restic_backup.sh`: A script that defines how to run the backup. Edit this file to respect your needs in terms of backup which paths to backup, retention (number of backups to save), etc.

Copy this file to `/etc/restic/backup_exclude` or `~/.backup_exclude`:
* `.backup_exclude`: A list of file pattern paths to exclude from you backups, files that just occupy storage space, backup-time, network and money.
Restic support exclude files. They list file pattern paths to exclude from you backups, files that just occupy storage space, backup-time, network and money. `restic_backup.sh` allows for a few different exclude files.
* `/etc/restic/backup_exclude` - global exclude list. You can use only this one if your setup is easy.
* `.backup_exclude` per backup path. If you have e.g. an USB disk mounted at /mnt/media and this path is included in the `$BACKUP_PATHS`, you can place a file `/mnt/media/.backup_exclude` and it will automatically picked up. The nice thing about this is that the backup paths are self-contained in terms of what they shoud exclude!
* Home directory exclude files - as a convenience, if either `/home` or `/Users` is added to the `$BACKUP_PATHS`, each user can have their own `.backup_exclude` files located in the home directory or in the default `$XDG_CONFIG_PATH`. For example these files would be automatically picked up respectivly:
* `/home/user1/.backup_exclude`
* `/home/user1/.config/restic/backup_exclude`
* `/Users/user1/.backup_exclude`
* `/Users/user1/.config/restic/backup_exclude`


## 5. Make first backup & verify
Now see if the backup itself works, by running
## 5. Make first backup
Now see if the backup itself works, by running as root

```console
$ sudo -i
$ source /etc/restic/default.env
$ /usr/local/sbin/restic_backup.sh
$ restic snapshots
````

## 6. Backup automatically; systemd service + timer
Now we can do the modern version of a cron-job, a systemd service + timer, to run the backup every day!
## 6. Verify the backup
As the `default.env` is already sourced in your root shell, you can now just list the snapshos
```console
$ sudo -i
$ source /etc/restic/default.env
$ restic snapshots
```

Alternatively you can mount the restic snapshots to a directory set `/mnt/restic`
```console
$ restic mount /mnt/restic
$ ls /mnt/restic
```

## 7. Backup automatically; systemd service + timer
Now we can do the modern version of a cron-job, a systemd service + timer, to run the backup every day!

Put these files in `/etc/systemd/system/`:
* `restic-backup.service`: A service that calls the backup script.
* `restic-backup.timer`: A timer that starts the backup every day.

* `restic-backup@.service`: A service that calls the backup script with the specified profile. The profile is specified
by the value after `@` when running it (see below).
* `restic-backup@.timer`: A timer that starts the former backup every day (same thing about profile here).
* If needed, edit this file to configure [how often](https://www.freedesktop.org/software/systemd/man/systemd.time.html#Calendar%20Events) back up should be made. See the `OnCalendar` key in the file.

Now simply enable the timer with:
```console
$ systemctl start restic-backup.timer
$ systemctl enable restic-backup.timer
$ systemctl start restic-backup@default.timer
$ systemctl enable restic-backup@default.timer
````

☝ **Note**: You can run it with different values instead of `default` if you use multiple profiles.

You can see when your next backup is scheduled to run with
```console
$ systemctl list-timers | grep restic
Expand All @@ -113,20 +188,20 @@ $ systemctl status restic-backup
or start a backup manually

```console
$ systemctl start restic-backup
$ systemctl start restic-backup@default
```

You can follow the backup stdout output live as backup is running with:

```console
$ journalctl -f -u restic-backup.service
$ journalctl -f -u restic-backup@default.service
````

(skip `-f` to see all backups that has run)



## 7. Email notification on failure
## 8. Email notification on failure
We want to be aware when the automatic backup fails, so we can fix it. Since my laptop does not run a mail server, I went for a solution to set up my laptop to be able to send emails with [postfix via my Gmail](https://easyengine.io/tutorials/linux/ubuntu-postfix-gmail-smtp/). Follow the instructions over there.

Put this file in `/usr/local/sbin`:
Expand All @@ -138,10 +213,17 @@ Put this files in `/etc/systemd/system/`:
As you maybe noticed already before, `restic-backup.service` is configured to start `status-email-user.service` on failure.


## 8. Optional: automated backup checks
## 9. Optional: automated backup checks
Once in a while it can be good to do a health check of the remote repository, to make sure it's not getting corrupt. This can be done with `$ restic check`.

There are some `*-check*`-files in this git repo. Install these in the same way you installed the `*-backup*`-files.
There are some `*check*`-files in this git repo. Install these in the same way you installed the `*-backup*`-files and enable with sytemd

```console
$ sudo -i
$ systemctl start restic-check@default.timer
$ systemctl enable restic-check@default.timer
````



# Cron?
Expand Down
20 changes: 20 additions & 0 deletions etc/restic/_global.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Global envionment variables
# These variables are sourced FIRST, and any values inside of *.env files for
# specific configurations will override if also defined there.


# Official instructions on how to setup the restic variables for Backblaze B2 can be found at
# https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#backblaze-b2


# The restic repository encryption key
export RESTIC_PASSWORD_FILE="/etc/restic/pw.txt"
# The global restic exclude file
export RESTIC_BACKUP_EXCLUDE="/etc/restic/backup_exclude"

# Backblaze B2 credentials
export B2_ACCOUNT_ID="<b2-account-id>" # TODO fill with your account info
export B2_ACCOUNT_KEY="<b2-account-key>" # TODO fill with your account info

# How many network connections to set up to B2. Default is 5.
export B2_CONNECTIONS=10
8 changes: 0 additions & 8 deletions etc/restic/b2_env.sh.template

This file was deleted.

1 change: 0 additions & 1 deletion etc/restic/b2_pw.txt.template

This file was deleted.

34 changes: 34 additions & 0 deletions etc/restic/default.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This is the default profile. Fill it with your desired configuration.
# Additionally, you can create and use more profiles by copying this file.

# This file (and other .env files) has two purposes:
# - being sourced by systemd timers to setup the backup before running restic_backup.sh
# - being sourced in a user's shell to work directly with restic commands e.g.
# $ source /etc/restic/default.env
# $ restic snapshots
# Thus you don't have to provide all the arguments like
# $ restic --repo ... --password-file ...

source /etc/restic/_global.env

# Below envvar will override those in _global.env

export RESTIC_REPOSITORY="b2:<b2-repo-name>" # TODO fill with your repo name

# What to backup (paths our mountpoints) e.g. "/ /boot /home /mnt/media".
# To backup only your home directory, set "/home/your-user"
export BACKUP_PATHS="" # TODO fill conveniently with one or multiple paths

# Example below of how to dynamically add a path that is mounted e.g. external USB disk.
# restic does not fail if a specified path is not mounted, but it's nicer to only add if they are available.
#test -d /mnt/media && BACKUP_PATHS+=" /mnt/media"

# A tag to identify backup snapshots.
export BACKUP_TAG=systemd.timer

# Retention policy - How many backups to keep.
# See https://restic.readthedocs.io/en/stable/060_forget.html?highlight=month#removing-snapshots-according-to-a-policy
export RETENTION_DAYS=14
export RETENTION_WEEKS=16
export RETENTION_MONTHS=18
export RETENTION_YEARS=3
1 change: 1 addition & 0 deletions etc/restic/pw.txt.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<restic-encryption-password>
11 changes: 0 additions & 11 deletions etc/systemd/system/restic-backup.service

This file was deleted.

13 changes: 13 additions & 0 deletions etc/systemd/system/restic-backup@.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Backup with restic to Backblaze B2
OnFailure=status-email-user@%n.service
Requires=nm-unmetered-connection.service

[Service]
Type=simple
Nice=10
# $HOME or $XDG_CACHE_HOME must be set for restic to find /root/.cache/restic/
Environment="HOME=/root"
# The random sleep (in seconds) is in the case of multiple backup profiles. Many restic instances started at the same time could case high load or network bandwith usage.
# `systemd-cat` allows showing the restic output to the systemd journal
ExecStart=bash -c 'sleep $(shuf -i 0-300 -n 1) && source /etc/restic/%I.env && /usr/local/sbin/restic_backup.sh | systemd-cat'
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ Requires=nm-unmetered-connection.service
[Service]
Type=simple
Nice=10
ExecStart=/usr/local/sbin/restic_check.sh
# `systemd-cat` allows showing the restic output to the systemd journal
ExecStart=bash -c 'source /etc/restic/%I.env && /usr/local/sbin/restic_check.sh | systemd-cat'