Truly support custom PREFIX= install
* Before, doing `$ PREFIX=/usr/local make install` would install files to`/usr/local/usr/local..` which is wrong * With this PR, files will be installed to the expected location e.g. `/usr/local/etc/restic` * `Makefile` almost completely rewritten * As e.g. `default.env` would source `_global.env`, `default.env` must be edited to find the right location of `_global.env` depending on what `$PREFIX` was set to. * see documented build stages in the `Makefile` itself. * Made sure that the rules are correct so that only modifed files are installed, not all at once unnecessarily like before. * A sub-goal was that the [PKGBUILD](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=restic-systemd-automatic-backup#n20) for Arch should not need to do any custom install configuration, to keep everything easier to maintain. `$ make install` should work out of the box for Arch. * Additionally added the `-b` flag to `install(1)` that makes a backup of existing `etc/restic/*` files before installing a newer version. Fixes #49
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,7 +1,5 @@
|
||||
# Prevent check-in of these sensitive files. Instead they are generated from the corresponding *.template file.
|
||||
etc/restic/pw.txt
|
||||
etc/restic/_global.env
|
||||
etc/restic/default.env
|
||||
# make install
|
||||
/build
|
||||
|
||||
# IntelliJ
|
||||
.idea/
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- `resticw` wrapper for working with different profiles without the need to source the profiles first.
|
||||
- `$make install` will now make a timestamped backup of any existing `/etc/restic/*` files before installing a newer version.
|
||||
|
||||
### Changed
|
||||
- **BREAKING CHANGE** moved systemd installation with makefile from `/etc/systemd/system` to `/usr/lib/systemd/system` as this is what packages should do. This is to be able to simplify the arch [PKGBUILD](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=restic-systemd-automatic-backup) so that it does not need to do anything else than `make install`.
|
||||
- If you upgrade form an existing install, you should disable and then re-enable the timer, so that the symlink is pointing to the new location of the timer.
|
||||
```console
|
||||
# systemctl disable restic-backup@<profile>.timer
|
||||
# systemctl enable restic-backup@<profile>.timer
|
||||
```
|
||||
- **BREAKING CHANGE** moved script installation with makefile from `/usr/local/sbin` to `/sbin` to have a simpler interface to work with `$PREFIX`.
|
||||
|
||||
### Fixed
|
||||
- Installation with custom `PREFIX` now works properly with Make: `$ PREFIX=/usr/local make install` whill now install everything at the expected location. With this, it's easy to use this script as non-root user on e.g. an macOS system.
|
||||
|
||||
## [4.0.0] - 2022-02-01
|
||||
### Fixed
|
||||
@@ -46,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
- `restic_backup.sh` now finds `.backup_exclude` files on each backup path as intended.
|
||||
- Install executeables to `$PREFIX/sbin` instead of `$PREFIX/user/local/sbin`, so that `$ PREFIX=/usr/local make install` does what is expected.
|
||||
|
||||
## [1.0.1] - 2021-12-03
|
||||
### Fixed
|
||||
|
||||
154
Makefile
154
Makefile
@@ -1,20 +1,77 @@
|
||||
# Not file targets.
|
||||
.PHONY: help install install-scripts install-conf install-systemd uninstall
|
||||
### Notes ###
|
||||
# This build process is done in three stages:
|
||||
# 1. copy source files to the local build directory.
|
||||
# 2. replace the string "$INSTALL_PREFIX" with the value of $PREFIX
|
||||
# 3. copy files from the build directory to the target directory.
|
||||
#
|
||||
# Why this dance?
|
||||
# * To fully support that a user can install this project to a custom path e.g. $(PREFIX=/usr/local make install),
|
||||
# we need to modify the files that refer to other files on disk. We do this by having a placeholder "$INSTALL_PREFIX"
|
||||
# that is substituted with the value of $PREFIX when installed
|
||||
# * We don't want to modify the files that are controlled by git, thus let's copy them to a build directory and then modify.
|
||||
|
||||
### Non-file targets ###
|
||||
.PHONY: help install install-scripts install-conf install-systemd clean uninstall
|
||||
|
||||
### Macros ###
|
||||
SRCS_SCRIPTS = $(filter-out %cron_mail, $(wildcard usr/local/sbin/*))
|
||||
NOW := $(shell date +%Y-%m-%d_%H:%M:%S)
|
||||
|
||||
# Source: https://stackoverflow.com/a/14777895/265508
|
||||
ifeq ($(OS),Windows_NT)
|
||||
CUR_OS := Windows
|
||||
else
|
||||
CUR_OS := $(shell uname)
|
||||
endif
|
||||
|
||||
# GNU install and macOS install have incompatible command line arguments.
|
||||
ifeq ($(CUR_OS),Darwin)
|
||||
BAK_SUFFIX = -B .$(NOW).bak
|
||||
else
|
||||
BAK_SUFFIX = --suffix=.$(NOW).bak
|
||||
endif
|
||||
|
||||
# Create parent directories of a file, if not existing.
|
||||
# Reference: https://stackoverflow.com/a/25574592/265508
|
||||
MKDIR_PARENTS=sh -c '\
|
||||
dir=$$(dirname $$1); \
|
||||
test -d $$dir || mkdir -p $$dir \
|
||||
' MKDIR_PARENTS
|
||||
|
||||
|
||||
# Source directories.
|
||||
DIR_SCRIPTS = sbin
|
||||
DIR_CONF = etc/restic
|
||||
DIR_SYSTEMD = usr/lib/systemd/system
|
||||
|
||||
# Source files.
|
||||
SRCS_SCRIPTS = $(filter-out %cron_mail, $(wildcard $(DIR_SCRIPTS)/*))
|
||||
# $(sort) remove duplicates that comes from running make install >1 times.
|
||||
SRCS_CONF = $(sort $(patsubst %.template, %, $(wildcard etc/restic/*)))
|
||||
SRCS_SYSTEMD = $(wildcard etc/systemd/system/*)
|
||||
SRCS_CONF = $(sort $(patsubst %.template, %, $(wildcard $(DIR_CONF)/*)))
|
||||
SRCS_SYSTEMD = $(wildcard $(DIR_SYSTEMD)/*)
|
||||
|
||||
# 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))
|
||||
# Local build directory. Sources will be copied here, modified and then installed from this directory.
|
||||
BUILD_DIR := build
|
||||
BUILD_DIR_SCRIPTS = $(BUILD_DIR)/$(DIR_SCRIPTS)
|
||||
BUILD_DIR_CONF = $(BUILD_DIR)/$(DIR_CONF)
|
||||
BUILD_DIR_SYSTEMD = $(BUILD_DIR)/$(DIR_SYSTEMD)
|
||||
|
||||
# Sources copied to build directory.
|
||||
BUILD_SRCS_SCRIPTS = $(addprefix $(BUILD_DIR)/, $(SRCS_SCRIPTS))
|
||||
BUILD_SRCS_CONF = $(addprefix $(BUILD_DIR)/, $(SRCS_CONF))
|
||||
BUILD_SRCS_SYSTEMD = $(addprefix $(BUILD_DIR)/, $(SRCS_SYSTEMD))
|
||||
|
||||
# Destination directories
|
||||
DEST_DIR_SCRIPTS = $(PREFIX)/$(DIR_SCRIPTS)
|
||||
DEST_DIR_CONF = $(PREFIX)/$(DIR_CONF)
|
||||
DEST_DIR_SYSTEMD = $(PREFIX)/$(DIR_SYSTEMD)
|
||||
|
||||
# Destination files.
|
||||
DEST_SCRIPTS = $(addprefix $(PREFIX)/, $(SRCS_SCRIPTS))
|
||||
DEST_CONF = $(addprefix $(PREFIX)/, $(SRCS_CONF))
|
||||
DEST_SYSTEMD = $(addprefix $(PREFIX)/, $(SRCS_SYSTEMD))
|
||||
|
||||
INSTALLED_FILES = $(DEST_SCRIPTS) $(DEST_CONF) $(DEST_SYSTEMD)
|
||||
|
||||
### Targets ###
|
||||
# target: all - Default target.
|
||||
@@ -24,33 +81,9 @@ all: install
|
||||
help:
|
||||
@egrep "#\starget:" [Mm]akefile | sed 's/\s-\s/\t\t\t/' | cut -d " " -f3- | sort -d
|
||||
|
||||
# target: install - Install all files
|
||||
install: install-scripts install-conf install-systemd
|
||||
|
||||
|
||||
# target: install-scripts - Install executables.
|
||||
install-scripts:
|
||||
install -d $(DEST_SCRIPTS)
|
||||
install -m 0744 $(filter-out %/resticw, $(SRCS_SCRIPTS)) $(DEST_SCRIPTS)
|
||||
install -m 0755 usr/local/sbin/resticw $(DEST_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/_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.
|
||||
install-conf: | $(SRCS_CONF)
|
||||
install -d $(DEST_CONF)
|
||||
install -b -m 0600 $(SRCS_CONF) $(DEST_CONF)
|
||||
$(RM) etc/restic/_global.env etc/restic/default.env etc/restic/pw.txt
|
||||
|
||||
# target: install-systemd - Install systemd timer and service files.
|
||||
install-systemd:
|
||||
install -d $(DEST_SYSTEMD)
|
||||
install -m 0644 $(SRCS_SYSTEMD) $(DEST_SYSTEMD)
|
||||
# target: clean - Remove build files.
|
||||
clean:
|
||||
$(RM) -r $(BUILD_DIR)
|
||||
|
||||
# target: uninstall - Uninstall ALL files from the install targets.
|
||||
uninstall:
|
||||
@@ -58,3 +91,46 @@ uninstall:
|
||||
echo $(RM) $$file; \
|
||||
$(RM) $$file; \
|
||||
done
|
||||
|
||||
# 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
|
||||
# target: install - Install all files
|
||||
install: install-scripts install-conf install-systemd
|
||||
|
||||
# Install targets - add build sources to prereqa as well, so that build dir is re-created if deleted (expected behaviour).
|
||||
# target: install-scripts - Install executables.
|
||||
install-scripts: $(DEST_SCRIPTS)
|
||||
# target: install-conf - Install restic configuration files.
|
||||
install-conf: $(DEST_CONF) $(BUILD_SRCS_CONF)
|
||||
# target: install-systemd - Install systemd timer and service files.
|
||||
install-systemd: $(DEST_SYSTEMD)
|
||||
|
||||
|
||||
# Copies sources to build directory & replace "$INSTALL_PREFIX"
|
||||
# dir= line needs to be in the same subshell to use shared envvars. Reference: https://stackoverflow.com/a/36419671/265508
|
||||
$(BUILD_DIR)/% : %
|
||||
${MKDIR_PARENTS} $@
|
||||
cp $< $@
|
||||
sed -i.bak -e "s|\$$INSTALL_PREFIX|$$PREFIX|g" $@; rm $@.bak
|
||||
|
||||
|
||||
# For the destination files to be built, build-files must exist.
|
||||
#$(DEST_SCRIPTS): $(BUILD_SRCS_SCRIPTS)
|
||||
#$(DEST_CONF): $(BUILD_SRCS_CONF)
|
||||
#$(DEST_SYSTEMD): $(BUILD_SRCS_SYSTEMD)
|
||||
|
||||
# Install destination script files.
|
||||
$(DEST_DIR_SCRIPTS)/%: $(BUILD_DIR_SCRIPTS)/%
|
||||
${MKDIR_PARENTS} $@
|
||||
install -m 0744 $< $@
|
||||
|
||||
# Install destination conf files. Additionally backup existing files.
|
||||
$(DEST_DIR_CONF)/%: $(BUILD_DIR_CONF)/%
|
||||
${MKDIR_PARENTS} $@
|
||||
install -m 0600 -b $(BAK_SUFFIX) $< $@
|
||||
|
||||
# Install destination script files.
|
||||
$(DEST_DIR_SYSTEMD)/%: $(BUILD_DIR_SYSTEMD)/%
|
||||
${MKDIR_PARENTS} $@
|
||||
install -m 0644 $< $@
|
||||
|
||||
27
README.md
27
README.md
@@ -52,7 +52,7 @@ Nevertheless the project should work out of the box, be minimal but still open t
|
||||
* `/etc/restic/backup_exclude.txt` - 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`.
|
||||
* Edit if needed `OnCalendar` in `/usr/lib/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
|
||||
@@ -91,6 +91,18 @@ $ git clone https://github.com/erikw/restic-systemd-automatic-backup.git && cd $
|
||||
$ sudo make install
|
||||
````
|
||||
|
||||
If you want to install everything manually, we will install files to `/etc`, `/sbin`, and not use the `$make install` command, then you need to clean up a placeholder `$INSTALL_PREFIX` in the souce files first by running:
|
||||
```console
|
||||
$ find etc sbin -type f -exec sed -i.bak -e 's|$INSTALL_PREFIX||g' {} \; -exec rm {}.bak \;
|
||||
```
|
||||
and you should now see that all files have been changed like e.g.
|
||||
```diff
|
||||
-export RESTIC_PASSWORD_FILE="$INSTALL_PREFIX/etc/restic/pw.txt"
|
||||
+export RESTIC_PASSWORD_FILE="/etc/restic/pw.txt"
|
||||
```
|
||||
This prefix is there so that make users can set a different `$PREFIX` when installing like `PREFIX=/usr/local make install`. So if we don't use the makefile, we need to remove this prefix with the command above just.
|
||||
|
||||
|
||||
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
|
||||
@@ -126,7 +138,7 @@ $ restic init
|
||||
```
|
||||
|
||||
## 4. Script for doing the backup
|
||||
Put this file in `/usr/local/sbin`:
|
||||
Put this file in `/sbin`:
|
||||
* `restic_backup.sh`: A script that defines how to run the backup. The intention is that you should not need to edit this script yourself, but be able to control everything from the `*.env` profiles.
|
||||
|
||||
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.
|
||||
@@ -139,7 +151,7 @@ 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
|
||||
$ /sbin/restic_backup.sh
|
||||
````
|
||||
|
||||
## 6. Verify the backup
|
||||
@@ -159,8 +171,7 @@ $ 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/`:
|
||||
|
||||
Put these files in `/etc/systemd/system` (note that the Makefile installs as package to `/usr/lib/systemd/system`)
|
||||
* `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).
|
||||
@@ -204,7 +215,7 @@ $ journalctl -f -u restic-backup@default.service
|
||||
## 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`:
|
||||
Put this file in `/sbin`:
|
||||
* `systemd-email`: Sends email using sendmail(1). This script also features time-out for not spamming Gmail servers and getting my account blocked.
|
||||
|
||||
Put this files in `/etc/systemd/system/`:
|
||||
@@ -216,7 +227,7 @@ As you maybe noticed already before, `restic-backup.service` is configured to st
|
||||
## 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 is companion scripts, service and timer (`*check*`) to restic-backup.sh that checks the restic backup for errors; look in the repo in `etc/systemd/system` and `usr/local/sbin` and copy what you need over to their corresponding locations.
|
||||
There is companion scripts, service and timer (`*check*`) to restic-backup.sh that checks the restic backup for errors; look in the repo in `usr/lib/systemd/system/` and `sbin/` and copy what you need over to their corresponding locations.
|
||||
|
||||
```console
|
||||
$ sudo -i
|
||||
@@ -245,7 +256,7 @@ straightforward (it needs to run with sudo to read environment). Just run:
|
||||
If you want to run an all-classic cron job instead, do like this:
|
||||
|
||||
* `etc/cron.d/restic`: Depending on your system's cron, put this in `/etc/cron.d/` or similar, or copy the contents to $(sudo crontab -e). The format of this file is tested under FreeBSD, and might need adaptions depending on your cron.
|
||||
* `usr/local/sbin/cron_mail`: A wrapper for running cron jobs, that sends output of the job as an email using the mail(1) command.
|
||||
* `sbin/cron_mail`: A wrapper for running cron jobs, that sends output of the job as an email using the mail(1) command.
|
||||
|
||||
# Uninstall
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SHELL=/bin/sh
|
||||
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin/:/usr/local/sbin/
|
||||
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin/:$INSTALL_PREFIX/sbin/
|
||||
# Order of crontab fields
|
||||
# minute hour mday month wday command
|
||||
# Reference: https://www.freebsd.org/doc/handbook/configtuning-cron.html
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
|
||||
# The restic repository encryption key
|
||||
export RESTIC_PASSWORD_FILE="/etc/restic/pw.txt"
|
||||
export RESTIC_PASSWORD_FILE="$INSTALL_PREFIX/etc/restic/pw.txt"
|
||||
# The global restic exclude file
|
||||
export RESTIC_BACKUP_EXCLUDE_FILE="/etc/restic/backup_exclude.txt"
|
||||
export RESTIC_BACKUP_EXCLUDE_FILE="$INSTALL_PREFIX/etc/restic/backup_exclude.txt"
|
||||
|
||||
# Backblaze B2 credentials keyID & applicationKey pair.
|
||||
# Restic environment variables are documented at https://restic.readthedocs.io/en/latest/040_backup.html#environment-variables
|
||||
@@ -9,7 +9,7 @@
|
||||
# Thus you don't have to provide all the arguments like
|
||||
# $ restic --repo ... --password-file ...
|
||||
|
||||
source /etc/restic/_global.env
|
||||
source $INSTALL_PREFIX/etc/restic/_global.env
|
||||
|
||||
# Below envvar will override those in _global.env
|
||||
|
||||
@@ -3,5 +3,4 @@ Description=Check if the current NetworkManager connection is metered
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/nm-unmetered-connection.sh
|
||||
|
||||
ExecStart=$INSTALL_PREFIX/sbin/nm-unmetered-connection.sh
|
||||
@@ -10,4 +10,4 @@ Nice=10
|
||||
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'
|
||||
ExecStart=bash -c 'sleep $(shuf -i 0-300 -n 1) && source $INSTALL_PREFIX/etc/restic/%I.env && $INSTALL_PREFIX/sbin/restic_backup.sh | systemd-cat'
|
||||
@@ -8,4 +8,4 @@ Requires=nm-unmetered-connection.service
|
||||
Type=simple
|
||||
Nice=10
|
||||
# `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'
|
||||
ExecStart=bash -c 'source $INSTALL_PREFIX/etc/restic/%I.env && $INSTALL_PREFIX/sbin/restic_check.sh | systemd-cat'
|
||||
@@ -6,6 +6,6 @@ Description=Send status email for %i to user
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/systemd-email abc@gmail.com %i
|
||||
ExecStart=$INSTALL_PREFIX/sbin/systemd-email abc@gmail.com %i
|
||||
User=root
|
||||
Group=systemd-journal
|
||||
Reference in New Issue
Block a user