Recipes for managing repository environment variables

This is the best practice I’ve cooked up for getting restic environment variables everywhere I need them:

Create /root/.resticrc:

RESTIC_REPOSITORY=/srv/restic
RESTIC_PASSWORD=abcedef1234

To use restic in your interactive shell, append to ~/.bash_profile:

set -a
. ~/.resticrc
set +a

To use restic within a /etc/cron.{hourly,daily}/* script, prepend it with the same thing:

set -a
. ~/.resticrc
set +a

To use restic to pipe some snapshot content into the shell on your workstation:

ssh root@example.org 'env $(cat /root/.resticrc) restic dump 8b9954b7 postgres.sql.gz' | zless
1 Like

I usually deal with multiple repositories, and so my way of dealing with this is to create a script per repository, in /usr/local/sbin, and chmod 700.

#!/bin/sh

export RESTIC_REPOSITORY=...
export RESTIC_PASSWORD=...

exec restic "$@"

Then I can run restic-foo, restic-bar, etc. to operate on different repositories, without having to source any environment files. This also gives a centralized place to put options like --cache-dir.

1 Like

@cdhowie that’s an awesome approach too, thanks for sharing!

You could also put like a file with the environment inside like you do, but instead of source every time you use restic, make a bash script call it (use a friendly name for your env files with an extension like .rc, for example, and chmod 700 every one of them):

#!/usr/bin/env bash
# rc files to work with
rc_dir="/path/to/your/rc/files"
rc_file="$1"

# if rc file does not exists exit with code 1
if [[ ! "$rc_file" ]] ; then
  echo "You have not indicated a repo to work with"
  exit 1
elif [[ ! -e "$rc_dir/$rc_file.rc" ]] ; then
  echo "There is no 'rc' file called $rc_file"
  exit 1
fi

# source rc files
source "$rc_dir/$rc_file.rc"
export RESTIC_REPOSITORY=$var_inside_your_rc_file
export RESTIC_PASSWORD=$var_inside_your_rc_file

restic "${@:2}"
catch_errors="$?"

# report errors (if any) stored in catch_errors variable and exit the script
# with the same error or exit 0 if there is no errors
if [[ $"catch_errors" -ne 0 ]]; then 
  echo "Script finished with errors"
  echo "$(date)"
  echo "Exit code $catch_errors"
  exit "$catch_errors"
else 
  echo "$(basename $0) finished without errors"
  exit 0
fi

This way you can manage multiple repositories. Just have to name them with a friendly name and call them like this: scriptname reponame [restic_commands_flags_etc]".

I used this script (author @sulfuror) and simplified it to just wrap restic without any functions but the original script have a lot of functions and it is really long. I use it, tho. It simplifies a lot of basic restic commands and it have a nice output, log, etc, but it does not report any errors.

1 Like

I also use scripts. One for local backups, one for B2. But I hate to add credentials to my scripts, therefore I use zx2c4 pass to store password, and B2 bucket name, B2 application key etc. in a single encrypted spot. It’s easy to extract the values in a script with sed, awk, grep, whatever you prefer. Any password manager that comes with an usable command line interface would be good too, of course.

1 Like

Storing the variables in a GPG-encrypted file is another option. The GPG agent can remember passphrases for some amount of time; you can configure it to remember for 10 minutes or so and then you’d only have to enter the passphrase once within that timeframe to perform multiple operations on the repository.

1 Like

Nice approach! I really like it. I’m now tempted to use your script instead of mine, really! BTW, I’m trying to handle errors now. I know I told you, but any help would be appreciated. This next thing I want to do is to handle all errors and list them at the end of the script (not exit because some functions have more than one command) and then simplify a lot everything because I know it can be much simpler than it is right now.

1 Like

No doubt there are many improvements possible, but here’s my quick-and-dirty approach.

I use restic with multiple repositories, some local and some on cloud-based storage (wasabi.com), so I created two wrapper scripts that target them individually: rr (local) and wr (wasabi):

/usr/local/bin/rr:

#!/bin/bash
# rr.sh - restic wrapper
# this script forms a restic command that is pointed at a repository
# hosted locally
BASE_REPO="/mnt/repo_parent_dir/"

#check usage
[ -z "$1" ] && {
echo no repository specified.
echo usage: $0 repository-name operation parameters
echo example: $0 servers/server1 snapshots
exit
}

[ -z "$2" ] && {
echo no operation specified.
echo usage: $0 repository-name operation parameters
echo example: $0 servers/server1 snapshots
exit
}

#form the variables for the command execution
REPOSITORY=${BASE_REPO}$1
OPERATION=$2
shift 2

#execute the command
restic -r ${REPOSITORY} ${OPERATION} $*

/usr/local/bin/wr:

#!/bin/bash
# wr.sh - wasabi restic wrapper
# this script forms a restic command that is pointed at a repository
# hosted on wasabi.com.
export AWS_ACCESS_KEY_ID="myaccesskey"
export AWS_SECRET_ACCESS_KEY="mysecret"
BASE_REPO="s3:https://s3.us-west-1.wasabisys.com/mybucket/"

#check usage
[ -z "$1" ] && {
echo no repository specified.
echo usage: $0 repository-name operation parameters
echo example: $0 servers/server1 snapshots
exit
}

[ -z "$2" ] && {
echo no operation specified.
echo usage: $0 repository-name operation parameters
echo example: $0 servers/server1 snapshots
exit
}

#form the variables for the command execution
REPOSITORY=${BASE_REPO}$1
OPERATION=$2
shift 2

#execute the command
restic -r ${REPOSITORY} ${OPERATION} $*