Git Product home page Git Product logo

erikw / restic-automatic-backup-scheduler Goto Github PK

View Code? Open in Web Editor NEW
581.0 12.0 100.0 448 KB

Automatic restic backup using Backblaze B2 storage and either Linux systemd timers, macOS LaunchAgent, Windows ScheduledTask or simply cron.

License: BSD 3-Clause "New" or "Revised" License

Shell 70.95% Makefile 25.04% PowerShell 4.01%
restic-backups restic backup backup-script systemd systemd-service systemd-timer email-notification script cron

restic-automatic-backup-scheduler's Introduction

Automatic restic Backups using Native OS Task Schedulers

formerly named restic-systemd-automatic-backup

GitHub Stars GitHub Forks
Lint Code Base Latest tag AUR version AUR maintainer Homebrew Formula Open issues Closed issues Closed PRs License OSS Lifecycle SLOC Top programming languages used

Contributors including these top contributors:

Intro

restic is a command-line tool for making backups, the right way. Check the official website for a feature explanation. As a storage backend, I recommend Backblaze B2 as restic works well with it, and it is (at the time of writing) very affordable for the hobbyist hacker! (anecdotal: I pay for my full-systems backups each month typically < 1 USD).

Unfortunately restic does not come pre-configured with a way to run automated backups, say every day. However, it's possible to set this up yourself using built-in tools in your OS and some wrappers. For Linux with systemd, it's convenient to use systemd timers. For macOS systems, we can use built-in LaunchAgents. For Windows we can use ScheduledTasks. Any OS having something cron-like will also work!

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 restic's supported storage backends. The setup should be similar, but you will have to use other configuration variables to match your backend of choice.

Project Scope

Update: this project is feature complete (see reasoning below). Only bug fixes wull be accepted. Feel free to fork if you want to add more features; forking vase was the initial scope of this project!

The scope for this is not to be a full-fledged super solution that solves all the problems and all possible setups. The aim is to be a hackable code base for you to start sewing up the perfect backup solution that fits your requirements!

Nevertheless, the project should work out of the box, be minimal but still open the doors for configuration and extensions by users.

To use a different storage backend than B2, you should only need to tweak a few settings variables in the backup profile as well as some restic arguments inside restic_backup.sh.

Notes

  • Tip: Navigate this document easily from the Section icon in the top left corner. README Sections
  • Note: in the command listing in this document, $ means a user shell and # means a root shell (or use sudo).

Requirements

  • restic >=v0.9.6
  • bash >=v4.0.0
  • (recommended) GNU make if you want an automated install
    • Arch: part of the base-devel meta package, Debian/Ubuntu: part of the build-essential meta package, macOS: use the pre-installed or a more recent with Homebrew

Setup

Depending on your system, the setup will look different. Choose one of:

Setup Linux Systemd

Note The Linux setup here will assume an installation to /.

Many Linux distributions nowadays use Systemd, which features good support for running services and scheduled jobs. If your distribution is no on Systemd, check out the cron setup instead.

TL;DR setup

  1. Create B2 bucket + credentials
  2. Install scripts, configs systemd units/timers:
    • With make:
    $ sudo make install-systemd
    • Arch Linux users: use the AUR package, e.g.
    $ yay -S restic-automatic-backup-scheduler
  3. Fill out configuration values in /etc/restic.
  4. Initialize the remote repo. Source the profile to make all needed configuration available to restic(1). All commands after this assumes the profile is sourced in the current shell.
     # source /etc/restic/default.env.sh
     # restic init
  5. Configure how often backups should be done.
  6. Enable automated backup for starting with the system & make the first backup:
    # systemctl enable --now [email protected]
  7. Watch the first backup progress with Systemd journal:
    # journalctl -f --lines=50 -u restic-backup@default
  8. Verify the backup
    # restic snapshots
  9. (recommended) Enable the check job that verifies that the backups for the profile are all intact.
    # systemctl enable --now [email protected]
  10. (optional) Define multiple profiles: just make a copy of the default.env.sh 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.
    # systemctl enable restic-backup@other_profile.timer
  11. Consider more optional features.

Setup macOS LaunchAgent

Note The macOS setup here will assume a Homebrew installation to the recommended default location. This is $HOMEBREW_PREFIX (brew --prefix) , which is /usr/local on Intel Macs and /opt/homebrew on Apple Silicon.

Launchd is the modern built-in service scheduler in macOS. It has support for running services as root (Daemon) or as a normal user (Agent). Here we set up a LaunchAgent to be run as your normal user for starting regular backups.

TL;DR setup

  1. Create B2 bucket + credentials
  2. Install scripts, configs and LaunchAgent:
     $ brew install erikw/tap/restic-automatic-backup-scheduler
    • Using make:
     $ make PREFIX=$(brew --prefix) install-launchagent
  3. Fill out configuration values in $(brew --prefix)/etc/restic.
  4. Initialize the remote repo. Source the profile to make all needed configuration available to restic(1). All commands after this assumes the profile is sourced in the current shell.
     $ source $(brew --prefix)/etc/restic/default.env.sh
     $ restic init
  5. Configure how often backups should be done. If needed, edit OnCalendar in
    • Homebrew install: ~/Library/LaunchAgents/homebrew.mxcl.restic-automatic-backup-scheduler.plist.
    • make install: ~/Library/LaunchAgents/com.github.erikw.restic-backup.plist.
  6. Enable automated backup for starting with the system & make the first backup:
    • Homebrew install:
    $ brew services start restic-automatic-backup-scheduler
    • make install:
    $ launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.github.erikw.restic-backup.plist
    $ launchctl enable gui/$UID/com.github.erikw.restic-backup
    $ launchctl kickstart -p gui/$UID/com.github.erikw.restic-backup
    As a convenience, a shortcut for the above commands are $ make activate-launchagent-backup.
  7. Watch the first backup progress from the log files:
    $ tail -f ~/Library/Logs/restic/backup*
  8. Verify the backup
    $ restic snapshots
  9. (recommended) Enable the check job that verifies that the backups for the profile are all intact.
    • Homebrew install:
    $ brew services start restic-automatic-backup-scheduler-check
    • make install:
    $ launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.github.erikw.restic-check.plist
    $ launchctl enable gui/$UID/com.github.erikw.restic-check
    $ launchctl kickstart -p gui/$UID/com.github.erikw.restic-check
    As a convenience, a shortcut for the above commands are $ make activate-launchagent-check.
  10. Consider more optional features.

Homebrew Setup Notes

Then control the service with homebrew:

$ brew services start restic-automatic-backup-scheduler
$ brew services restart restic-automatic-backup-scheduler
$ brew services stop restic-automatic-backup-scheduler

If services start fails, it might be due to previous version installed. In that case remove the existing version and try again:

$ launchctl bootout gui/$UID/com.github.erikw.restic-backup
$ brew services start restic-automatic-backup-scheduler

Make Setup Notes

Use the disable command to temporarily pause the agent, or bootout to uninstall it.

$ launchctl disable gui/$UID/com.github.erikw.restic-backup
$ launchctl bootout gui/$UID/com.github.erikw.restic-backup

If you updated the .plist file, you need to issue the bootout followed by bootrstrap and enable sub-commands of launchctl. This will guarantee that the file is properly reloaded.

Setup Windows ScheduledTask

Windows comes with a built-in task scheduler called ScheduledTask. The frontend app is "Task Scheduler" (taskschd.msc) and we can use PowerShell commands to install a new scheduled task.

I describe here one of may ways you can get restic and this backup script working on Windows. Here I chose to work with scoop and git-bash.

TL;DR setup

  1. Install scoop
  2. Install dependencies from a PowerShell with administrator privileges. pwsh should be installed to be able to run powershell in shebang scripts.
     powershell> scoop install restic make git pwsh
  3. In a non-privileged PowerShell, start git-bash and clone this repo
     powershell> git-bash
     git-bash$ mkdir ~/src && cd ~/src/
     git-bash$ git clone https://github.com/erikw/restic-automatic-backup-scheduler.git && cd $(basename "$_" .git)
  4. Install scripts, configs and ScheduledTasks
     git-bash$ make install-schedtask
  5. Fill out configuration values in /etc/restic.
     git-bash$ vim /etc/restic/*
    Note that you should use cygwin/git-bash paths. E.g. in default.env.sh you could have
     export RESTIC_BACKUP_PATHS='/c/Users/<username>/My Documents'
  6. Initialize the remote repo. Source the profile to make all needed configuration available to restic(1). All commands after this assumes the profile is sourced in the current shell.
     git-bash$ source /etc/restic/default.env.sh
     git-bash$ restic init
  7. Make the first backup
     git-bash$ restic_backup.sh
  8. Verify the backup
     git-bash$ restic snapshots
  9. Inspect the installed ScheduledTasks and make a test run
    1. Open the app "Task Scheduler" (taskschd.msc)
    2. Go to the local "Task Scheduler Library"
    3. Right click on one of the newly installed tasks e.g. restic_backup and click "run".
      • If the tasks are not there, maybe you opended it up before make install-schedtask: just close and start it again to refresh.
    4. Now a git-bash window should open running restic_backup.sh, and the next time the configured schedule hits!
  10. Consider more optional features.

With taskschd.msc you can easily start, stop, delete and configure the scheduled tasks to your liking: Windows Task Schedulder

Setup Cron

Note There are many different cron implementations out there and they all work slightly different.

Any system that has a cron-like system can easily setup restic backups as well. However if you system supports any of the previous setups, those are recommended over cron as they provide more features and reliability for your backups.

TL;DR setup

  1. Create B2 bucket + credentials
  2. Install scripts, configs systemd units/timers:
    $ sudo make install-cron
    • This assumes that your cron supports dropping files into /etc/cron.d/. If that is not the case, simply copy the relevant contents of the installed /etc/cron.d/restic in to your /etc/crontab.
    # grep "^@.*restic_" /etc/cron.d/restic >> /etc/crontab
  3. Fill out configuration values in /etc/restic.
  4. Initialize the remote repo. Source the profile to make all needed configuration available to restic(1). All commands after this assumes the profile is sourced in the current shell.
     # source /etc/restic/default.env.sh
     # restic init
  5. Make the first backup
     # restic_backup.sh
  6. Verify the backup
    # restic snapshots
  7. Configure how often backups should be done by directly editing /etc/cron.d/restic (or /etc/crontab).
  8. Consider more optional features.

Detailed Manual Setup

This is a more detailed explanation than the TL;DR sections above that will give you more understanding in the setup. This section is more general, but uses Linux + Systemd as the example setup.

0. Clone Repo

$ git clone https://github.com/erikw/restic-automatic-backup-scheduler.git && cd $(basename "$_" .git)

Make a quick search-and-replace in the source files:

$ find bin etc usr Library ScheduledTask -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.

-export RESTIC_PASSWORD_FILE="{{ INSTALL_PREFIX }}/etc/restic/pw.txt"
+export RESTIC_PASSWORD_FILE="/etc/restic/pw.txt"

Why? The OS specific TL;DR setups above all use the Makefile or a package manager to install these files. The placeholder string {{ INSTALL_PREFIX }} is in the source files for portability reasons, so that the Makefile can support all different operating systems. make users can set a different $PREFIX when installing like PREFIX=/usr/local make install-systemd.

In this detailed manual setup we will copy all files manually to /etcand /bin. Thus, we need to remove the placeholder string {{ INSTALL_PREFIX }} in the source files as a first step.

1. Create Backblaze B2 Account, Bucket and Keys

In short:

  1. Create a Backblaze account (use 2FA!).
  2. Create a new B2 bucket.
    • Private, without B2 encryption and without the object lock feature
  3. Create a pair of keyId and applicationKey
    • Limit scope of the new id and key pair to only the above created bucket.

First, see this official Backblaze tutorial 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.

For restic to be able to connect to your bucket, you want to in the B2 settings create a pair of keyID and applicationKey. It's a good idea to create a separate pair of ID and Key with for each bucket that you will use, with limited read&write access to only that bucket.

2. Configure B2 Credentials Locally

Put these files in /etc/restic/:

  • _global.env.sh: Fill this file out with your global settings including B2 keyID & applicationKey.
  • default.env.sh: This is the default profile. Fill this out with bucket name, backup paths and retention policy. This file sources _global.env.sh and is thus self-contained and can be sourced in the shell when you want to issue some manual restic commands. For example:
    $ source /etc/restic/default.env.sh
    $ 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 (single line) 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:
    $ openssl rand -base64 128 | tr -d '\n' > /etc/restic/pw.txt
  • 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!

3. Initialize remote repo

Now we must initialize the repository on the remote end:

$ sudo -i
# source /etc/restic/default.env.sh
# restic init

4. Script for doing the backup

Put this file in /bin:

  • 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.sh 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.

  • /etc/restic/backup_exclude.txt - global exclude list. You can use only this one if your setup is easy. This is set in _global.env.sh. If you need a different file for another profile, you can override the envvar RESTIC_BACKUP_EXCLUDE_FILE in this profile.
  • .backup_exclude.txt per backup path. If you have e.g. an USB disk mounted at /mnt/media and this path is included in the $RESTIC_BACKUP_PATHS, you can place a file /mnt/media/.backup_exclude.txt 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!

5. Make first backup

Now see if the backup itself works, by running as root

# source /etc/restic/default.env.sh
# /bin/restic_backup.sh

6. Verify the backup

As the default.env.sh is already sourced in your root shell, you can now just list the snapshost

# restic snapshots

Alternatively you can mount the restic snapshots to a directory set /mnt/restic

# restic mount /mnt/restic
# ls /mnt/restic

7. Backup automatically

All OS setups differs in what task scheduler they use. As a demonstration, let's look at how we can do this with systemd under Linux here.

Put these files in /etc/systemd/system (note that the Makefile installs as package to /usr/lib/systemd/system)

  • [email protected]: A service that calls the backup script with the specified profile. The profile is specified by the value after @ when running it (see below).
  • [email protected]: A timer that starts the former backup every day (same thing about profile here).
    • If needed, edit this file to configure how often back up should be made. See the OnCalendar key in the file.

Now simply enable the timer with:

# systemctl enable --now [email protected]

You can see when your next backup is scheduled to run with

# systemctl list-timers | grep restic

and see the status of a currently running backup with:

# systemctl status restic-backup

or start a backup manually:

$ systemctl start restic-backup@default

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

$ journalctl -f -u [email protected]

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

Recommended: 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 usr/lib/systemd/system/ and bin/ and copy what you need over to their corresponding locations.

# systemctl enable --now [email protected]

Optional Features

Optional: Multiple profiles

To have different backup jobs having e.g. different buckets, backup path of schedule, just make a copy of the default.env.sh and use the defined profile name in place of default in the previous steps.

To create a different backup and use you can do:

# cp /etc/restic/default.env.sh /etc/restic/other.env.sh
# vim /etc/restic/other.env.sh  # Set backup path, bucket etc.
# source /etc/restic/other.env.sh
# restic_backup.sh

Optional: Summary stats log

When enabled, it will write to a CSV log file the stats after each backup. Can be enabled by uncommenting its env variable (RESTIC_BACKUP_STATS_DIR) on the global environment file or defining it on a specific profile.

The stats log (as well as) the desktop notifications incur in an additional run of restic snapshots and restic diff. This execution is shared with the notifications (no extra run).

Optional: Desktop Notifications

It's a good idea to be on top of your backups to make sure that they don't increase a lot in size and incur high costs. However, it's notoriously tricky to make GUI notifications correctly from a non-user process (e.g. root).

Therefore, this project provides a lightweight solution for desktop notifications that works like this: Basically restic_backup.sh will append a summary line of the last backup to a user-owned file (the user running your OS's desktop environment) in a fire-and-forget fashion. Then the user has a process that reads this and forward each line as a new message to the desktop environment in use.

To set desktop notifications up:

  1. Create a special FIFO file as your desktop user:
    $ mkfifo /home/user/.cache/notification-queue
  2. In your profile, e.g. /etc/restic/default.sh, set:
    RESTIC_BACKUP_NOTIFICATION_FILE=/home/user/.cache/notification-queue
  3. Create a listener on the notification queue file that forwards to desktop notifications

Optional: Email Notification on Failure

Systemd

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. Follow the instructions over there.

Put this file in /bin:

  • 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 file in /etc/systemd/system/:

  • [email protected]: A service that can notify you via email when a systemd service fails. Edit the target email address in this file, and replace or remove {{ INSTALL_PREFIX }} according to your installation.

Now edit /usr/lib/systemd/system/[email protected] and /usr/lib/systemd/system/[email protected] to call this service failure.

OnFailure=status-email-user@%n.service

Cron

Use bin/cron_mail: A wrapper for running cron jobs, that sends output of the job as an email using the mail(1) command. This assumes that the mail program is correctly setup on the system to send emails.

To use this, wrap the restic script command with it in your cron file like:

-@midnight	root	. /etc/restic/default.sh && restic_backup.sh
+@midnight	root	. /etc/restic/default.sh && cron_mail restic_backup.sh

Optional: No Backup on Metered Connections (Linux/systemd only)

For a laptop, it can make sense to not do heavy backups when your on a metered connection like a shared connection from you mobile phone. To solve this we can set up a systemd service that is in success state only when a connection is unmetered. Then we can tell our backup service to depend on this service simply! When the unmetered service detects an unmetered connection it will go to failed state. Then our backup service will not run as it requires this other service to be in success state.

  1. Edit [email protected] and [email protected] to require the new service to be in success state:
    Requires=nm-unmetered-connection.service
    After=nm-unmetered-connection.service
    
  2. Copy and paste the command below, it will install the following files and refresh systemd daemon:
  3. Put this file in /etc/systemd/system/:
    • nm-unmetered-connection.service: A service that is in success state only if the connection is unmetered.
  4. Install this file in /bin:
    • nm-unmetered-connection.sh: Detects metered connections and returns an error code if one is detected. This scripts requires the Gnome NetworkManager to be installed (modify this script if your system has a different network manager).
  5. Reload systemd with
    # systemctl daemon-reload

Tip: All steps but the first can be done in one go if you use the Makefile. Set $PREFIX as needed or leave empty for install to /.

sudo bash -c 'export PREFIX=
 make build/usr/lib/systemd/system/nm-unmetered-connection.service
 install -m 0644 build/usr/lib/systemd/system/nm-unmetered-connection.service $PREFIX/etc/systemd/system
 install -m 0555 bin/nm-unmetered-connection.sh /bin
 systemctl daemon-reload
'

Optional: Restic Wrapper Script

For convenience there's a restic wrapper script that makes loading profiles and running restic straightforward (it needs to run with sudo to read environment). Just run:

  • sudo resticw WHATEVER (e.g. sudo resticw snapshots) to use the default profile.
  • You can run the wrapper by passing a specific profile: resticw -p anotherprofile snapshots.
  • The wrapper has extras on top of restic like --diff-latest option.

Useful commands:

Command Description
resticw snapshots List backup snapshots
resticw diff <snapshotId-1> <snapshotId-2> Show the changes between backup snapshots
resticw stats / resticw stats snapshotId ... Show the statistics for the whole repo or the specified snapshots
resticw mount /mnt/restic Mount your remote repository
resticw --diff-latest Show latest snapshot changes: Runs restic diff after finding the latest 2 snapshots

Uninstall

There is a make target to remove all files (scripts and configs) that were installed by sudo make install-*. Just run:

$ sudo make uninstall

Debugging

The best way to debug what's going on is to run the restic_backup.sh script with bash's trace function. You can activate it by running the script with bash -x:

$ source /etc/restic/default.env.sh
$ bash -x /bin/restic_backup.sh

To debug smaller portions of the backup script, insert these lines at the top and bottom of the relevant code portions e.g.:

set -x
exec 2>/tmp/restic-automatic-backup-scheduler.log
<code to debug>
set +x

and then inspect the outputs like

$ less /tmp/restic-automatic-backup-scheduler.log
$ tail -f /tmp/restic-automatic-backup-scheduler.log # or follow output like this.

Development

  • To not mess up your real installation when changing the Makefile simply install to a $PREFIX like
    $ PREFIX=/tmp/restic-test make install-systemd
  • Updating the resticw parser: If you ever update the usage DOC, you will need to refresh the auto-generated parser:
    $ pip install doctopt.sh
    $ doctopt.sh usr/local/bin/resticw

Releasing

To make a new release:

  1. Create a new tag:
    $ vi CHANGELOG.md && git commit -am "Update CHANGELOG.md"
    $ git tag vX.Y.Z
    $ git push && git push --tags
  2. Update version in the AUR PKGBUILD
  3. Update version in the Homebrew Formulas (see the repo README):

restic-automatic-backup-scheduler's People

Contributors

adidalal avatar antedebaas avatar billwanjohi avatar bobsaintcool avatar erikw avatar gerardbosch avatar giuaig avatar joolsr avatar lahdekorpi avatar mikhailbot avatar mmardegan avatar nettnikl avatar pdecat avatar shwang avatar svengo avatar tbm avatar toddejohnson avatar upbeatastronaut avatar wvolz avatar wyattjoh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

restic-automatic-backup-scheduler's Issues

PREFIX=/usr/local tries to install to /usr/local/usr/local..

By default, it should install to /sbin/, so that $ PREFIX=/usr/local make installinstalls as expected to/usr/local/sbin`

I'm working on a fix already, but will not make PR or merge until we've merged #45

If PREFIX is set, we need to sed(1) update all references inside the files as well so that e.g. we look at $PREFIX/etc/restic.
(or just sed-set one global $PREFIX variable which is used everywhere?)

Remember to update the PKGBUILD accordingly

  • Change Makefile to use /usr/lib/systemd instead of /etc/systemd, so that the PKG build does not need to set anything else than PREFIX

Why is restic_backup.sh managing its own logfile?

Hi,

# Redirect stdout ( > ) into a named pipe ( >() ) running "tee" to a file, so we can observe the status by simply tailing the log file.
me=$(basename "$0")
now=$(date +%F_%R)
log_dir=/var/local/log/restic
log_file="${log_dir}/${now}_${me}.$$.log"
test -d $log_dir || mkdir -p $log_dir
exec > >(tee -i $log_file)
exec 2>&1

Is there any non-obvious reason for doing this instead of printing to stdout and using journalctl -f -u restic-backup.service?

make install twice ends in error

Hi there! 👋

I think the following problem was introduced in https://github.com/erikw/restic-systemd-automatic-backup/pull/41/files#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52R6

or maybe the root cause comes from here #15

Run sudo make install and again sudo make install. The second time you run it you get:

install -d /tmp/a/b/usr/local/sbin
install -m 0744 usr/local/sbin/nm-unmetered-connection.sh usr/local/sbin/restic_backup.sh usr/local/sbin/restic_check.sh usr/local/sbin/systemd-email /tmp/a/b/usr/local/sbin
install -d /tmp/a/b/etc/restic
install -m 0600 etc/restic/b2_env.sh  etc/restic/b2_env.sh etc/restic/b2_pw.txt  etc/restic/b2_pw.txt etc/restic/backup_exclude /tmp/a/b/etc/restic
install: will not overwrite just-created '/tmp/a/b/etc/restic/b2_env.sh' with 'etc/restic/b2_env.sh'
install: will not overwrite just-created '/tmp/a/b/etc/restic/b2_pw.txt' with 'etc/restic/b2_pw.txt'
make: *** [Makefile:45: install-conf] Error 1

This is because once make install has run once, SRCS_CONF = $(patsubst %.template, %, $(wildcard etc/restic/*)) expands to duplicated file names that fail on cp/install command, as 2 input files with the same name cannot be copied into the same directory –actually only a single file exists, but the macro seems to expand wrongly as consider both %.template and *.


After looking at this, I'm not very clear what's the purpose of copying (and then keeping) the *.template files into repository's directory: etc/restic/b2_env.sh and etc/restic/b2_pwd.txt, as these files are already installed into the system directories.

What do you think is the best way to fix this? I guess one option would be to get rid of the non-template files in etc/restic, but I'm not sure if that was introduced on purpose or as a tactical thing to fix something here :)

What this line does?

Hi,

can you tell me what this line does?

[ -d /mnt/media ] && BACKUP_PATHS+=" /mnt/media"

newbie question

Can someone help me configure paths ?
BACKUP_PATHS="/opt/my_app"

what does this part mean ? [ -d /mnt/media ] && BACKUP_PATHS+=" /mnt/media"
Can i comment out this part? do i even need /mnt/media dir ?

Thanks for helpingout this newb.

Tag Release

It would be great to get a tag release so packagers can package a consistent version of the project instead of packaging master.

Check and Backup conflict

I hit my first run of both a check and backup this month and the check overruled the backup. It looks like there is a typo in the service file that was supposed to prevent this in the conflicts= line. I've submitted #27 to fix this.

restic_backup.sh - is this right?

First time user... I opened restic_backup.sh and saw this. Which is right?

"
How many network connections to set up to B2. Default is 5.
B2_CONNECTIONS=50
"

If envvars not set; print nice message for use

For someone executing restic_backup.sh or restic_check.sh, but the essential envvars are not set, instruct user to source a profile first.

Check all needed envvars in beginning of script

Onfailure results in error

I had Restic installed, but got an error. This error wasn't important, but what was was that the email that should have been sent to me was on a failure situation wasn't sent.

To debug this I tweaked the main backup file to have a deliberate mistake (ie calling 'vprune' command instead of prune. I've gone through the installed files very carefully a number of times, but can't see any inconsistencies between my install and the files on Github.

Specifically the error is when vprune is called, as part of the backup,

I’ve gone through the various files carefully but when i force an error in the backup script by having a ‘vprune’ command that results in a failure, this results in the following OnFailure state as it should be.

But the actual error occurs here, where the job called 'No such file or directory':-

Oct 12 21:17:43 cloud systemd[1]: restic-backup.service: Failed to enqueue OnFailure= job: No such file or directory

root@cloud:/etc/systemd/system# systemctl status restic-backup.service

  • restic-backup.service - Backup with restic to Backblaze B2
    Loaded: loaded (/etc/systemd/system/restic-backup.service; static; vendor preset: enabled)
    Active: failed (Result: exit-code) since Fri 2018-10-12 21:17:43 UTC; 10s ago
    Process: 33409 ExecStart=/usr/local/sbin/restic_backup.sh (code=exited, status=1/FAILURE)
    Main PID: 33409 (code=exited, status=1/FAILURE)

Oct 12 21:17:39 cloud systemd[1]: Started Backup with restic to Backblaze B2.
Oct 12 21:17:43 cloud restic_backup.sh[33409]: successfully removed locks
Oct 12 21:17:43 cloud restic_backup.sh[33409]: unknown command "vprune" for "restic"
Oct 12 21:17:43 cloud restic_backup.sh[33409]: Did you mean this?
Oct 12 21:17:43 cloud restic_backup.sh[33409]: prune
Oct 12 21:17:43 cloud systemd[1]: restic-backup.service: Main process exited, code=exited, status=1/FAILURE
Oct 12 21:17:43 cloud systemd[1]: restic-backup.service: Unit entered failed state.
Oct 12 21:17:43 cloud systemd[1]: restic-backup.service: Triggering OnFailure= dependencies.
Oct 12 21:17:43 cloud systemd[1]: restic-backup.service: Failed to enqueue OnFailure= job: No such file or directory
Oct 12 21:17:43 cloud systemd[1]: restic-backup.service: Failed with result 'exit-code'.

the backup works fine normally and the systemd timers working fine too. Install on Ubuntu 16.04 server. I can successfully send the error email ok via the test dbus method as mentioned in your README.

I can debug and provide further information as required.

Run a backup on demand? Storage backends other than Backblaze?

Hi there -

Thanks for this software, it's great! I'm using it on my NAS with great success.

I'm currently setting it up on my macOS laptop and I was wondering about two things:

  1. Is it possible to run a backup on-demand? I frequently download new photos from my camera to my laptop and would like to immediately trigger a backup. I tried resticw backup and get the output below.
  2. Is it possible to specify a storage backend other than Backblaze? Ideally I'd have my macOS laptop backing up to both my NAS (via SFTP or rest-server) and to Backblaze. I'm happy to configure this as two separate profiles, but AFAICT the code is actively asserting that Backblaze-specific environment variables are set and passes B2-specific options to restic.
❯ resticw backup
‣ Using profile: default  --  (/opt/homebrew/etc/restic/default.env.sh)

Fatal: nothing to backup, please specify target files/dirs

Add VERBOSITY configuration var

in config:

VERBOSITY_LEVEL=2

in restic_backup.sh & restic_check.sh, use like

restic backup \
	--verbose=${VERBOSITY_LEVEL} \

Backup paths question

Hello, thanks for this - it's really helpful.

Though I'm a still a bit of an inexperienced linux user and not sure how to add backup paths.
I have two folders I would like to backup up into separate buckets on B2:

/home/osmc/media-drive/backup1
/home/osmc/media-drive/backup2

How should I amend the code below, and what to do for two buckets:

BACKUP_PATHS="/ /boot /home"
[ -d /mnt/media ] && BACKUP_PATHS+=" /mnt/media"

Could you please show an example with my back up path?
Sorry for the dumb request - any help will be appreciated.

Thanks

Unable to source in current shell `sudo: source: command not found`

pi@mypi:~$ source /etc/restic/default.env.sh
-bash: /etc/restic/default.env.sh: Permission denied
pi@mypi:~$ sudo source /etc/restic/default.env.sh
sudo: source: command not found
pi@mypi:~$

Linux mypi 5.15.32-v8+ #1538 SMP PREEMPT Thu Mar 31 19:40:39 BST 2022 aarch64 GNU/Linux

pi@mypi:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

Restic version required

since we are using --verbose, we need restic version 0.9.6++ verbose flag was introduced in that version.

Restructure README

  • Make TL;DR for each OS, and link to general step-by-step for details.
  • Minimize OS-dependent parts in step-by-step
  • Create new section Optional and group all optional there. From TL;DR, simply link to top-level optional

support for --files-from?

Do you have any interested in supporting the --files-from option for the backup command? I need something like that to just include certain files from a path I want to backup. If it sounds interesting to you, I could try putting together a PR (my bash-fu is a little weak compared to yours, so any guidance would be helpful).

Also, thanks for putting this together, I think this is going to work great for me.

Mac OS LaunchAgent

brew services start restic-automatic-backup-scheduler

Afai can tell this LaunchAgent doesn't do anything. I've tried working through the manual steps and it won't start either. The launchctl status is 1 which I believe rates back to permissions error. I have double checked my launched shell script can run through terminal. I'm running on user permissions but root on the LaunchAgent didnt seem to change anything either. Is it maybe related to the $PATH variables in the LaunchAgent? I'm not 100% sure but I thought translating path variables in a launchagent wasn't supported?

Brew Service List didn't list a file associated with the service so that may be another issue.

Thank you!

Not an "issue" just a thank you for doing such a thorough write up of this process and sharing it. Many Thanks!!

resticw error

On running resticw snapshots I get the following error:

./resticw: line 129: INSTALL_PREFIX: unbound variable

This is on Ubuntu 20.04 installed with sudo make install-systemd.

plist Being Overwritten by Brew

Hi,

I'm using MacOS Ventura and trying to follow the instructions for installation, but can't get this to work. After editing the file homebrew.mxcl.restic-automatic-backup-scheduler, when I run brew services start restic-automatic-backup-scheduler, the plist file is overwritten and returned to its default state removing any edits I have made.

Also, it seems like the backup is not actually starting even though brew services is successful. When I run tail -f ~/Library/Logs/restic/backup*, I get:

zsh: no matches found: /Users/me/Library/Logs/restic/backup*

At this stage, I cannot even stop the service, but running launchctl bootout gui/$UID/com.github.erikw.restic-backup seems to fix this, but starting the service again gets me back to square one.

I'm not quite sure how to go about fixing this?

Thanks for your help.

Here is what I see if I try to look at the log after running brew services start:

2022-10-31 09:15:40.640690 (gui/501/com.github.erikw.restic-backup) <Notice>: internal event: WILL_SPAWN, code = 0
2022-10-31 09:15:40.640703 (gui/501/com.github.erikw.restic-backup) <Notice>: service state: spawn scheduled
2022-10-31 09:15:40.640704 (gui/501/com.github.erikw.restic-backup) <Notice>: service state: spawning
2022-10-31 09:15:40.640790 (gui/501/com.github.erikw.restic-backup) <Notice>: launching: speculative
2022-10-31 09:15:40.641010 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: xpcproxy spawned with pid 76018
2022-10-31 09:15:40.641014 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: internal event: SPAWNED, code = 0
2022-10-31 09:15:40.641017 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: service state: xpcproxy
2022-10-31 09:15:40.641452 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: internal event: SOURCE_ATTACH, code = 0
2022-10-31 09:15:40.658373 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: service state: running
2022-10-31 09:15:40.658387 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: internal event: INIT, code = 0
2022-10-31 09:15:40.658469 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: Successfully spawned bash[76018] because speculative
2022-10-31 09:15:40.705179 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: exited due to exit(1)
2022-10-31 09:15:40.705196 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: service state: exited
2022-10-31 09:15:40.705205 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: internal event: EXITED, code = 0
2022-10-31 09:15:40.705208 (gui/501 [100004]) <Notice>: service inactive: com.github.erikw.restic-backup
2022-10-31 09:15:40.705226 (gui/501/com.github.erikw.restic-backup [76018]) <Notice>: service state: not running

Add support for Windows

As discussed in #47, I already have had this backup script running perfectly fine in Windows using ScheduledTasks.

  • Integrate existing documentation to this repo from https://github.com/erikw/dotfiles/tree/personal/bin/restic-windows
    • Instruct on how to get restic with scoop for example, as this is tricker than on Linux/BSD/macOS
  • Integrate with the Makefile, maybe $ make install-windows ?
  • Make a winget or chocolately package?
  • How would this restic setup work in WSL? Try it out!

Easier configuration

Would it be ok to move the configuration related environmental variables from the /usr/local/sbin/restic_backup.sh to something like /etc/restic/backup_env.sh to make it more "unix like" and somewhat easier to configure?
Clearly a very minor change, but just wanted to check before making a PR.

These:

RETENTION_DAYS
RETENTION_WEEKS
RETENTION_MONTHS
RETENTION_YEARS
BACKUP_PATHS
BACKUP_EXCLUDES

Make extra scripts opt-in

From discussion in #45 and #60

These should be opt-in and not installed by default

  • Unmetered connection
  • Email notification scripts
  • resticw

How?

  • Maybe separate make target install-extras and/or specific tagets install-extras-resticw
  • Create clear Optional section in README, to keep the base install minimal, easier and quicker to follow.
  • Remove from base install with Makefile
  • Test on Linux
  • Test on Mac
  • Test on Windows

Makefile DEST_CONF .template

I'm trying to update the PKGBUILD and my chroot build is failing:

==> Starting package()...
install -d /build/restic-systemd-automatic-backup/pkg/restic-systemd-automatic-backup/usr/bin
install -m 0744 usr/local/sbin/nm-unmetered-connection.sh usr/local/sbin/restic_backup.sh usr/local/sbin/restic_check.sh usr/local/sbin/systemd-email /build/restic-systemd-automatic-backup/pkg/restic-systemd-automatic-backup/usr/bin
install -m 0600 etc/restic/b2_env.sh.template /etc/restic/b2_env.sh
install: cannot create regular file '/etc/restic/b2_env.sh': No such file or directory
make: *** [Makefile:36: etc/restic/b2_env.sh] Error 1
==> ERROR: A failure occurred in package().

Looks like they were rename to .template but the make file wasn't updated?:

b2_env.sh.template  b2_pw.txt.template

Congratulations on 1.0!!!

Provide optional desktop notifications with backup stats

Hi! As you know, I've been using very happily this project for some years 🎉 to backup my personal laptop.

But there is something that I have always find missing: Have a little feedback about the daily backup, and how my repository was growing.

This is mainly for 2-3 reasons:

  • To see if I added by mistake any directory that is not intended to be backed up, and be able to notice that and react fast to (a) add it to ~/.backup_exclude.txt; and (b) remove that heavy-sized snapshot from the repository to save money :)
  • Have non-intrusive notice that the backup is working, as if for example I realize that the notification didn't popped up in the last days, I need to troubleshoot something.
  • To see if my backup snapshot is growing more than I'd like.

But instead of digging daily in logs to see what happened the last day, I would like to see a small notification on my desktop. So with that in mind I wrote something to accomplish it the easiest way I could think of :) I put it as a draft PR #76, to see what you think, here is a sample of the result :)

image

Small mistake in README

HI,

A small correction that might help avoid confusion, this section calls for the B2 password to be stored in plaintext in the file.

The password to be stored in b2_pw.txt is actually the restic repository password and should probably not be the same as your B2 password.

So I propose to have the following text instead of "Put your B2 password in this file.":

This file should contain the restic repository password which is unique to this restic backup repository and is needed for restoring from it.

Run backup as restic user

Hello!

Following the example in the restic docs, I've set up restic to run as a separate user (rather than root). I believe I'll want to make use of the systemd timer implementation in this repo, but I'm not familiar enough with systemd timers to know for sure if my planned solution sounds like it'd work.

I think what I want to do is instead of installing the timer and service into /usr/lib/systemd/system like the Makefile does by default, I'll want to put it into ~restic/.config/systemd/user/ and enable lingering sessions for my restic user.

Does that sound about right? If I get this figured out, would it be valuable for me to contribute an option to make install that way back to this repo?

Thank you for putting this together! This is bound to really help me out with setting up my new backup system.

Possible error in Readme?

New to all this linux stuff, so excuse me if this is incorrect - but you state that the email address should be swapped in systemd-email, even though it accepts the email address as a variable that you set as recipinent. It seems to me after an hour of poking around and checking the pages you list for source that the email address should actually be specified in [email protected]. Testing this functions properly; running
systemd-email "[email protected]" "test"
generates an email to my inbox.

line 77: extra_args[@]: unbound variable

hello,

I use this script for wasabi. I changed B2_ACCOUNT_ID B2_ACCOUNT_KEY line to : AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY

I get this error:

/bin/restic_backup.sh: line 77: extra_args[@]: unbound variable

Can you help ?

Rename repo to `restic-automatic-backup-scheduler`

After #51 & #52 it would appropriate to rename this repo from restic-systemd-automatic-backup to

  • simply restic-automatic-backup
  • or restic-automatic-backup-systemd-cron-launchagent-scheduledtasks for discoverability
  • restic-automatic-backup-scheduler

Allow profiles to supply additional arguments to restic-backup

After #45 is merged, to not increase scope of this PR, allow profiles to set $RESTIC_BACKUP_EXTRA_ARGS to add extra arguments e.g. the handy --exclude-if-present .git which I like.

  • In global, export as empty string export RESTIC_BACKUP_EXTRA_ARGS=
  • Add out-commented in default-profile as example of adding more backup exclude files.

Implement forgotten restic-check LaunchAgent

Was forgotten for macOS

  • Adapt simpler naming
    • com.github.erikw.restic-backup
    • com.github.erikw.restic-check
  • Implement & test
    • How install multiple services for brew formula? What name do they get? Seems like I need to make a separata formula requiring this one, and that only installs the check LaunchAgent. Better: the main formula requires the check one!
  • Update README section to include this as recommended step.

Add support for macOS

As discussed in #47, I already have it running on a mac system for several years. However as a cron job.

  • Add instructions on how to set up on a mac in /usr/local/. #49 is a blocker for this
  • Create a proper solution using LaunchAgents
  • Integrate with the Makefile, maybe $ make install-launchagent ?
  • Create a Homebrew Formula in my tap https://github.com/erikw/homebrew-tap

Bash script for install

Hi there, great project, thanks for working on it.

Would you mind me writing a PR for an automated installation bash script? My .sh skills are not the best but I can work my way through it, and I think this would be massively helpful. Also, some of the documentation in the readme is not as clear as it could be for first-time users (for example, the need to chmod +x the restic_backup.sh files) and I would be glad to work a bit on this as well.

I just want to make sure I don't waste any efforts and that the maintainers would be OK with me doing this (and merging if the code/documentation is good quality).

Thanks!

Align envvars with B2 terminology for keys

Since this project was created, B2 has updated their terminology

  • Account ID -> keyID
  • Account Key -> applicationKey

Update the envvars to use the same name in this project.

How to allow user unmount?

Hi and thanks for simplifying the use of restic for backup!

To make it even more practical for family members I want to create a small "script button" or .desktop file that will allow mounting the backup under /media/$USER/restic/ so that it appears in Nautilus. (using --allow-other)
This works fine using pkexec to run the script as root to be able to source the default.env etc.
This however, leaves the user unable to unmount the "drive" in Nautilus the expected way.
I would like to avoid having a separate script with pkexec to unmount if at all possible, but I have tried a number of approaches without luck.
Any ideas are appreciated!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.