STABILITY: PROTOTYPE
Le restique is a wrapper around the restic backup tool that
allows using multiple backup profiles defined in a JSON configuration file.
You should be familiar with restic before using this. Read the restic manual first.
It's written in Python and uses only core modules so that there are no extra
dependencies to install, and no compilation or build steps.
You can literally just copy this into /usr/bin/ and you're done.
๐ I don't really know Python. So if you see some bad things in the code please feel free to file an issue or create a pull request. It will be appreciated.
Jump: Installation | Usage | Configuration | Examples | License
First, install Python 3. You probably already have it. Then install
restic. Then download the restique executable and put it
somewhere in your PATH. Don't forget to chmod +x path/to/restique
๐ง This program has only been tested on Linux with Python 3.6. It might not work with older Python versions or on other platforms.
restique [-h] [--debug] [--config PATH] [--profile NAME] command [resticargs]
-
-h, --help: Print the help / usage text. -
-V, --version: Print the version number. -
-d, --debug: Set the log level to debug. -
-c PATH, --config PATH: Specify the path to the configuration file. If not specified restic will check./.restiquerc,~/.restiquerc,~/.config/restique/config,/etc/restique.rcin this exact order and use the first one that exists. -
-p NAME(S), --profile NAME(S): Specify the name of the backup profile to be used. If not specified, restique will use the"default_profile"provided in the config file.
Multiple profile names can be specified as a comma-separated list (without spaces). If multiple profile names are provided they will be merged into each other in the order they are specified. This can be useful when combining partial profiles. -
command: The restic command to run. E.g. "init", "backup", "restore", ... check out the restic manual for a complete list. -
resticargs: All additional arguments will be directly passed to the restic command.
# Run a backup
restique -p home backup
# Restore the latest backup to /tmp/restore-home
restique -p home restore latest --target /tmp/restore-home{
"restic_path": "/path/to/restic_executable",
"default_profile": "my_profile",
"global": {
// ... profile config applied to all profiles
},
"profiles": {
"my_profile": {
"json": true,
"no_lock": true,
"quiet": true,
"files": [
"/path/to/directory/or/file_to_backup",
"/path/to/directory/or/another_file_to_backup"
],
"excludes": [
"*.go",
"foo/**/bar"
],
"keep_daily": 5,
"keep_weekly": 4,
"keep_monthly": 6,
"keep_yearly": 10,
"keep_tags": ["important"],
"password": "correct horse battery staple",
"repository": "/path/to/repo",
"aws_access_key": "...",
"aws_secret_key": "...",
"b2_account_id": "...",
"b2_account_key": "...",
"azure_account_name": "...",
"azure_account_key": "...",
"google_project_id": "...",
"google_application_credentials": "...",
"hooks": {
"pre_repo": [
"some-shell-commands"
],
"post_repo": [
// ...
],
"pre_<COMMAND>": [
// ...
],
"post_<COMMAND>": [
// ...
]
}
},
"my_other_profile": {
// ...
},
...
}
}-
restic_path(string, optional, default: which(restic)): Path to theresticexecutable. If not specified it will look up the path in thePATH. -
default_profile(string, optional): The name of the profile that will be used when no profile name is specified through the--profileargument.
Multiple profile names can be specified as a comma-separated list (without spaces). If multiple profile names are provided they will be merged into each other in the order they are specified. This can be useful when combining partial profiles. -
global(object, optional): A global profile that will be merged into all other profiles. If the non-global profile contains the same options the global options will be overridden by the profile. Exceptfilesandexcludeswill be combined. -
profiles.[NAME].initialize(boolean, optional, default: false): If true, it will automatically initialize an uninitialized repository. -
profiles.[NAME].json(boolean, optional, default: false): Calls restic with the--jsonargument. -
profiles.[NAME].no_lock(boolean, optional, default: false): Calls restic with the--no-lockargument. -
profiles.[NAME].quiet(boolean, optional, default: false): Calls restic with the--quietargument. -
profile.[NAME].files(array, required): A list of paths to files and or directories that will be backed up. -
profile.[NAME].excludes(array, optional): A list of file patterns that will be excluded from the backup.
Note that this only applies to thebackupcommand. Exclude patterns for therestorecommand must be provided through the--excludeand--includearguments. -
profile.[NAME].forget_tags(array, optional): List of tags to consider when running theforgetcommand. Equivalent of multiple--tag targuments. -
profile.[NAME].forget_hosts(array, optional): List of hosts to consider when running theforgetcommand. Equivalent of multiple--host harguments. -
profile.[NAME].keep_last(number, optional): Number of most recent snapshots to keep. Equivalent of--keep-last n. Only used withforgetcommand. -
profile.[NAME].keep_hourly(number, optional): Number of hourly snapshots to keep. Equivalent of--keep-hourly n. Only used withforgetcommand. -
profile.[NAME].keep_daily(number, optional): Number of daily snapshots to keep. Equivalent of--keep-daily n. Only used withforgetcommand. -
profile.[NAME].keep_weekly(number, optional): Number of weekly snapshots to keep. Equivalent of--keep-weekly n. Only used withforgetcommand. -
profile.[NAME].keep_monthly(number, optional): Number of monthly snapshots to keep. Equivalent of--keep-monthly n. Only used withforgetcommand. -
profile.[NAME].keep_yearly(number, optional): Number of yearly snapshots to keep. Equivalent of--keep-yearly n. Only used withforgetcommand. -
profile.[NAME].keep_tags(array, optional): List of snapshot tags to keep. Equivalent of using multiple--keep-tag targuments. Only used withforgetcommand. -
profile.[NAME].keep_within(string, optional): Diration within to keep all snapshots. For example2y5m7d3h. Equivalent of--keep-within d. Only used withforgetcommand. -
profile.[NAME].password(string, required): The password that will be used to encrypt and sign the backup. -
profile.[NAME].repository(string, required): The repository path for the backup. Read the restic docs to see how to format the repository path for your storage backend. -
profile.[NAME].aws_access_key(string, optional): S3 access key. Used only when hosting the repository on S3. -
profile.[NAME].aws_secret_key(string, optional): S3 secret key. Used only when hosting the repository on S3. -
profile.[NAME].b2_account_id(string, optional): Backblaze B2 account ID. Used only when hosting the repository on Backblaze B2. -
profile.[NAME].b2_account_key(string, optional): Backblaze B2 access key. Used only when hosting the repository on Backblaze B2. -
profile.[NAME].azure_account_name(string, optional): Microsoft Azure account name. Used only when hosting the repository on Microsoft Azure. -
profile.[NAME].azure_account_key(string, optional): Microsoft Azure account key. Used only when hosting the repository on Microsoft Azure. -
profile.[NAME].google_project_id(string, optional): Google Cloud Storage project ID. Used only when hosting the repository on Google Cloud Storage. -
profile.[NAME].google_application_credentials(string, optional): File path to Google Cloud Storage application credentials file. Used only when hosting the repository on Google Cloud Storage. -
profile.[NAME].hooks.pre_repo(array of strings, optional): An array of shell commands that will be executed sequentially and in order before each restic command that accesses the repo. If one of the shell commands fails (i.e. exits with a non-zero exit code) all following commands including the restic command will not run and the program will exit. -
profile.[NAME].hooks.post_repo(array of strings, optional): An array of shell commands that will be executed sequentially and in order after each restic command that accesses the repo. If one of the shell commands fails (i.e. exits with a non-zero exit code) all following commands will not run and the program will exit. -
profile.[NAME].hooks.pre_[COMMAND](array of strings, optional): An array of shell commands that will be executed sequentially and in order before each restic[COMMAND]command. If one of the shell commands fails (i.e. exits with a non-zero exit code) all following commands including the restic command will not run and the program will exit. -
profile.[NAME].hooks.post_[COMMAND](array of strings, optional): An array of shell commands that will be executed sequentially and in order after each resticCOMMANDcommand. If one of the shell commands fails (i.e. exits with a non-zero exit code) all following commands will not run and the program will exit.
Hooks can be used to do stuff before and after the repo is accessed, or before
and after a specific command is executed. For example, a USB drive could be
mounted in the pre_repo hook and then unmounted in the post_repo hook.
Each hook is executed in a separate shell and has access to all environment variables including the ones passed to restic. Hooks are executed in the following order:
pre_repopre_[COMMAND](unless pre_repo failed)- call to restic (unless pre_[COMMAND] failed)
post_[COMMAND](unless the restic command failed)post_repo(unless post_[COMMAND] failed)
So in case of restique backup it would call pre_repo, pre_backup, restic backup, post_backup, and finally post_repo.
Config:
{
"default_profile": "home",
"profiles": {
"home": {
"repository": "/mnt/my_external_drive/backups",
"password": "correct horse battery staple",
"files": [
"/home"
],
"excludes": [
"pr0n/**/*.mp4"
]
}
}
}Initialize:
restique initBackup:
restique backupIntegrity check:
restique checkRestore:
restique restore latest --target /tmp/home-restoredConfig:
{
"default_profile": "dockerimages",
"profiles": {
"dockerimages": {
"repository": "b2:mydockerbackups:/images",
"b2_account_id": "1a2345b67890",
"b2_account_key": "1234a5678b901c3d45678ef901g2h34567i89jklmn",
"password": "correct horse battery staple"
}
}
}Initialize:
restique initExport and backup the busybox docker image:
docker save busybox | restique backup --stdin --stdin-name busybox.tarList the contents of the latest snapshot:
restique ls latestOutput:
snapshot fb120820 of [busybox.tar] at 2017-10-01 20:30:03.222656757 +0200 CEST):
/busybox.tar
Restore the docker image:
restique restore latest --target /tmp/ --include busybox.tardocker load < /tmp/busybox.tarHere we are going to create four partial profiles. Two of them contain information about different backups that we want to make, and the other two contain information about two different repositories where we want to store our backups. By combining one of the former profiles with one of the latter we can save the same backup on different repositories.
Config:
{
"global": {
"password": "correct horse battery staple"
},
"profiles": {
"personal": {
"files": [ "/home/user" ],
"excludes": [ "/home/user/work" ]
},
"work": {
"files": [ "/home/user/work" ]
},
"local": {
"repository": "/mnt/my_external_drive/backups"
},
"remote": {
"repository": "s3:s3.amazonaws.com/my_backups_bucket",
"aws_access_key": "AAABBB999CCC666UU000",
"aws_secret_key": "aaaa/BBBbBbBBbbbbBBBBBbBbBB/CCCcCcccCCCC"
}
}
}Initialize S3 repository:
restique -p remote initInitialize local repository:
restique -p local initBackup personal files to S3:
restique -p personal,remote backupBackup personal files locally:
restique -p personal,local backupBackup work files to S3:
restique -p work,remote backupBackup work files locally:
restique -p work,local backupRestore a snapshot from the S3 repository:
restique -p remote restore e61c4ad7 --target /tmp/work-restoredRestore a snapshot from the local repository:
restique -p local restore 0eb99523 --target /tmp/personal-restoredConfig:
{
"default_profile": "home",
"profiles": {
"home": {
"repository": "/mnt/my_external_drive/backups",
"password": "correct horse battery staple",
"files": [
"/home"
],
"hooks": {
"pre_repo": [
"mountpoint -q '/mnt/my_external_drive/backups'"
]
}
}
}
}Try backup:
restique backupOutput:
ERROR: Command 'mountpoint -q '/mnt/my_external_drive/backups'' returned non-zero exit status 1.
ERROR: One or more 'pre_repo' hooks failed.
Copyright (c) 2017 Max Kueng