Giter Club home page Giter Club logo

btrfs-backup's Introduction

btrfs-backup

This project supports incremental backups for btrfs using snapshots and send/receive between filesystems. Think of it as a basic version of Time Machine.

Backups can be stored locally and/or remotely (e.g. via SSH). Multi-target setups are supported as well as dealing with transmission failures (e.g. due to network outage).

Its main goals are to be reliable and functional while maintaining user-friendliness. It should be easy to get started in just a few minutes without detailled knowledge on how btrfs send/receive works. However, you should have a basic understanding of snapshots and subvolumes.

btrfs-backup has almost no dependencies and hence is well suited for many kinds of setups with only minimal maintenance effort.

Originally, it started as a fork of a project with the same name, written by Chris Lawrence. Since then, most of the code has been refactored and many new features were added before this repository has been transferred to me. Many thanks to Chris for his work. The old code base has been tagged with legacy. If, for any reason, you want to continue using it and miss the new features, you can check that out.

Latest release:v0.3.0
Downloads:http://pypi.python.org/pypi/btrfs_backup
Source:https://github.com/efficiosoft/btrfs-backup
Platforms:Linux >= 3.12, Python >= 3.3
Keywords:backup, btrfs, snapshot, send, receive, ssh

Features

  • Initial creation of full backups
  • Incremental backups on subsequent runs
  • Different backup storage engines:
    • Local storage
    • Remote storage via SSH
    • Custom storage: Alternatively, the output of btrfs send may be piped to a custom shell command.
  • Multi-target support with tracking of which snapshots are missing at each location.
  • Retransmission on errors (e.g. due to network outage).
  • Simple and configurable retention policy for local and remote snapshots
  • Optionally, create snapshots without transferring them anywhere and vice versa.
  • Creation of backups without root privileges, if some special conditions are met
  • Detailled logging output with configurable log level

Installation

Requirements

  • Python 3.3 or later
  • Appropriate btrfs-progs; typically you'll want at least 3.12 with Linux 3.12/3.13
  • (optional) OpenSSH's ssh command - needed for remote backup pulling and pushing via SSH
  • (optional) sshfs - only needed for pulling via SSH
  • (optional) pv command for displaying progress during backups

Install via PIP

The easiest way to get up and running with the latest stable version is via PIP. If pip3 is missing on your system and you run a Debian-based distribution, simply install it via:

$ sudo apt-get install python3-pip python3-wheel

Then, you can fetch the latest version of btrfs-backup:

$ sudo pip3 install btrfs_backup

Pre-built packages

There are pre-built packages available for the following distributions.

  • Arch Linux (thanks to XenGi for maintaining this)

Manual installation

Alternatively, clone this git repository

$ git clone https://github.com/efficiosoft/btrfs-backup
$ cd btrfs-backup
$ git checkout tags/v0.3.0  # optionally checkout a specific version
$ sudo ./setup.py install

Sample usage

Not every feature of btrfs-backup is explained in this README, since there is a detailled and descriptive help included with the command.

However, there are some sections about the general concepts and different sample usages to get started as quick as possible.

For reference, a copy of the output of btrfs-backup --help is attached below.

As root:

$ btrfs-backup /home /backup

This will create a read-only snapshot of /home in /home/snapshot/YYMMDD-HHMMSS, and then send it to /backup/YYMMDD-HHMMSS. On future runs, it will take a new read-only snapshot and send the difference between the previous snapshot and the new one.

Note: Both source and destination need to be on btrfs filesystems. Additionally, the source has to be either the root or any other subvolume, but not just an ordinary directory because snapshots can only be created of subvolumes.

For the backup to be sensible, source and destination shouldn't be the same filesystem. Otherwise you could just snapshot and save the hassle.

You can backup multiple subvolumes to multiple subfolders or subvolumes at the destination. For example, you might want to backup both / and /home. The main caveat is you'll want to put the backups in separate folders on the destination drive to avoid confusion.

$ btrfs-backup / /backup/root
$ btrfs-backup /home /backup/home

If you really want to store backups of different subvolumes at the same location, you have to specify a prefix using the -p/--snapshot-prefix option. Without that, btrfs-backup can't distinguish between your different backup chains and will mix them up. Using the example from above, it could look like the following:

$ btrfs-backup --snapshot-prefix root / /backup
$ btrfs-backup --snapshot-prefix home /home /backup

You can specify -N/--num-snapshots <num> to only keep the latest <num> number of snapshots on the source filesystem. -n/--num-backups <num> does the same thing for the backup location.

Remote backups

Backing up to a remote server via SSH is as easy as:

$ btrfs-backup /home ssh://server/mnt/backups

btrfs-backup doesn't need to be installed on the remote side for this to work. It is recommended to set up public key authentication to eliminate the need for entering passwords. A full description of how to customize the ssh call can be found in the help text.

Pulling backups from a remote side is now supported as well! Simply use the ssh:// scheme as source.

You could even do something like:

$ btrfs-backup ssh://source_server/home ssh://dest_server/mnt/backups

to pull backups from source_server and store them at dest_server. This might be used if you can't install btrfs-backup on either remote host for any reason. But keep in mind that this procedure will generate double traffic (from source_server to you and from you to dest_server).

Okay, just one last example, because I really like that one:

$ btrfs-backup ssh://source_server/home \
               /mnt/backups \
               ssh://dest_server/mnt/backups

Can you guess what it does? Well, it does the same as the command before + an extra sending to your local /mnt/backups folder. Please note that btrfs-backup is not smart enough to prevent the same data from being pulled from source_server twice. But that wouldn't be easy to implement with the current design.

Help text

This is the output of btrfs-backup --help. Taking a look at it, you should get a good insight in what it can and can't do (yet).

Cooming at the release.

Configuration files

By default, btrfs-backup doesn't read any configuration file. However, you can create one or more and specify them at the command line:

$ btrfs-backup @path/to/backup_home.conf

Any argument prefixed by a @ is treated as file name of a configuration file.

The format of these files is simple. On every line, there may be one flag, option or argument you would normally specify at the command line. Valid configuration files might look like the following.

backup_home.conf:

# This is a comment and thus ignored, as well as blank lines.

# Include another configuration file here.
@global.conf

        # Indentation has no effect.
        -p home

# This is the source.
/home

# Back up to both local and remote storage.
/mnt/backups/home
ssh://server/mnt/btrfs_storage/backups/home

global.conf:

# This file gets included by the other one.
--quiet

--num-snapshots 1
--num-backups 3

A more detailled explanation about the format can be found in the help text.

What are locks?

btrfs-backup uses so called "locks" to keep track of failed snapshot transfers. There is a file called .outstanding_transfers created in the snapshot folder. This file is in JSON format and thus human-readable, if necessary.

Locking works as follows:

  1. When a snapshot transfer is started, an entry is created in that file, telling that a snapshot transfer of a specific snapshot to a specific destination has begun. We call this entry a lock.
  2. If the snapshot transfer used another snapshot as parent, that one gets an entry as well, but no lock, just the note that it's a parent for something that failed to transfer.
  3. When the transfer
    1. finishes without errors, the locks for the snapshot (and its parent) are removed.
    2. aborts (e.g. due to network outage or a full disk), the locks are kept.

Now, there are multiple options for dealing with those failed transfers.

When you run btrfs-backup the next time, it finds the corrupt snapshot at the destination and deletes it, together with the corresponding lock and parent notes. Afterwards, the way is free for a new transfer. You may also use --no-snapshot to only do the transfers without creating new snapshots.

There is a special flag called --locked-dests available. If supplied, it automatically adds all destinations which locks exist for as if they were specified at the command line. You might do something like:

$ btrfs-backup --no-snapshot --locked-dests /home

to retry all failed backup transfers of snapshots of /home. This could be executed periodically because it just does nothing if there are no locks.

Snapshots for which locks or parent notes exist are excluded from the retention policy and won't be purged until the locks are removed either automatically (because the partially transferred snapshots could be deleted from the destination) or manually (see below).

As a last resort for removing locks for transfers you don't want to retry anymore, there is a flag called --remove-locks. Use it with caution and only if you can assure that there are no corrupt snapshots at the destinations you apply the flag on.

$ btrfs-backup --no-snapshot --no-transfer --remove-locks /home ssh://nas/backups

will remove all locks for the destination ssh://nas/backups from /home/snapshot/.outstanding_transfers. Of course, using --locked-dests instead of specifying the destination explicitly is possible as well.

Backing up regularly

Note that there is no locking included with btrfs-backup. If you back up too often (i.e. more quickly than it takes the first call to finish, which can take several minutes, hours or even days on a filesystem with lots of files), you might end up with a new backup starting while an old one is still in progress.

You can workaround the lack of locking using the flock(1) command, as suggested at #4.

With anacron on Debian, you could simply add a file /etc/cron.daily/local-backup:

#!/bin/sh
flock -n /tmp/btrfs-backup-home.lock \
    ionice -c 3 btrfs-backup --quiet --num-snapshots 1 --num-backups 3 \
                /home /backup/home

You may omit the -n flag if you want to wait rather than fail in case a backup is already running.

More or less frequent backups could be made using other cron.* scripts.

Restoring a snapshot

If necessary, you can restore a whole snapshot by using e.g.

$ mkdir /home/snapshot
$ btrfs send /backup/YYMMDD-HHMMSS | btrfs receive /home/snapshot

Then you need to take the read-only snapshot and turn it back into a root filesystem:

$ cp -aR --reflink /home/snapshot/YYMMDD-HHMMSS /home

You might instead have some luck taking the restored snapshot and turning it into a read-write snapshot, and then re-pivoting your mounted subvolume to the read-write snapshot.

Alternative workflow

An alternative structure is to keep all subvolumes in the root directory

/
/active
/active/root
/active/home
/inactive
/snapshot/root/YYMMDD-HHMMSS
/snapshot/home/YYMMDD-HHMMSS

and have corresponding entries in /etc/fstab to mount the subvolumes from /active/*. One benefit of this approach is that restoring a snapshot can be done entirely with btrfs tools:

$ btrfs send /backup/root/YYMMDD-HHMMSS | btrfs receive /snapshot/root
$ btrfs send /backup/home/YYMMDD-HHMMSS | btrfs receive /snapshot/home
$ mv /active/root /inactive
$ mv /active/home /inactive
$ btrfs subvolume snapshot /snapshot/root/YYMMDD-HHMMSS /active/root
$ btrfs subvolume snapshot /snapshot/home/YYMMDD-HHMMSS /active/home

The snapshots from btrfs-backup may be placed in /snapshots by using the --snapshot-folder option.

Issues and Contribution

As in every piece of software, there likely are bugs. When you find one, please open an issue on GitHub. If you do so, please include the output with debug log level (-v debug) and provide steps to reproduce the problem. Thank you!

If you want to contribute, that's great! You can create issues (even for feature requests), send pull requests or contact me via email at [email protected].

Copyright

Copyright © 2017 Robert Schindler <[email protected]>
Copyright © 2014 Chris Lawrence <[email protected]>

btrfs-backup's People

Contributors

bob1de avatar lordsutch avatar timblechmann 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

Watchers

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

btrfs-backup's Issues

Dangling repetitive SSH mounts?

Not sure this would be explicitly a btrfs-backup issue but my remote server just crashed w/OOM and the culprit from the best we can tell was a ton of ssh mounts for our offsite backups via /tmp/mountPaths

fusermount -o rw,nosuid,nodev,fsname=backups:/,auto_unmount,subtype=sshfs -- /tmp/tmp83c_e6yb/mnt
sshfs -o auto_unmount -o reconnect -o cache=no backups:/ /tmp/tmp83c_e6yb/mnt

Taking advantage of this downtime to do OS updates but will be happy to provide more details once I have backups up and running again (and hopefully not eating memory)

[ERROR] [sourcedir] does not seem to be a btrfs subvolume

Hello,

thanks for btrfs-backup!
I have tried to use it:

root@homeserver:/home/henfri# btrfs-backup /srv/DataPool/Fotos/ /mnt/test/
21:46:29  [INFO ]  --[ Started at Mon Oct  4 21:46:29 2021 ]---------
21:46:29  [INFO ]  Preparing endpoint /srv/DataPool/Fotos/snapshot ...
21:46:29  [ERROR]  /srv/DataPool/Fotos does not seem to be a btrfs subvolume
root@homeserver:/home/henfri# btrfs subvolume show /srv/DataPool/Fotos/ |head
Fotos
        Name:                   Fotos
        UUID:                   3b7f5796-c053-8940-9809-7dfde837a47f
        Parent UUID:            -
        Received UUID:          -
        Creation time:          2019-04-28 21:50:08 +0200
        Subvolume ID:           1381
        Generation:             1002070
        Gen at creation:        260
        Parent ID:              5

Any idea, what the reason could be?

Best regards,
Hendrik

SSH Bad configuration option: auto_unmount

Hi,
I am trying to backup a snapshot to a remote server, but to this command:
btrfs-backup /tank ssh://my-pc/test-backups
I got the following:
11:45:04 [INFO ] --[ Started at Sun May 13 11:45:04 2018 ]--------- 11:45:04 [INFO ] Preparing endpoint /tank/snapshot ... 11:45:04 [INFO ] Preparing endpoint (SSH) my-pc/test-backups ... command-line: line 0: Bad configuration option: auto_unmount 11:45:04 [ERROR] Error on command: ['ssh', '-o', 'auto_unmount', '-o', 'reconnect', '-o', 'cache=no', 'my-pc', 'mkdir', '-p', '/test-backups']
(I'm sorry, I don't know how to set preformatted line-breaks in comments).
What is this auto_unmount option to ssh?

ioctl(BTRFS_IOC_TREE_SEARCH, subvol_id 359) ret=-1, error: Operation not permitted

After the other error was fixed, I now seem to get this error, same setup, I see the target directory created on the remote server and then this failure.

At subvol /home/user/lib/snapshot/20180418-002105
ioctl(BTRFS_IOC_TREE_SEARCH, subvol_id 359) ret=-1, error: Operation not permitted
ERROR: cannot resolve our subvol path
00:22:44  [ERROR]  Error during btrfs send / receive

Note: both servers were updated to 0.3.1 prior to testing.

Archlinux package

I made a package for Archlinux. You could link it in your README.
You can click the Flag package out-of-date button when you release a new version to notify me.

Instead of caveat, refer to flock(1)

Instead of contemplating reimplementing locking in btrfs-backup, you could just tell people to use flock(1) utility for locking. flock -n is perfect for this usecase :)

README.rst typo

Hi,
Almost at the end of the README.rst file I read,

_and have corresponding entries in /etc/fstab to mount the subvolumes from /active/*. One benefit of this approach is that restoring a snapshot can be done entirely with btrfs tools:

$ btrfs send /backup/root/YYMMDD-HHMMSS | btrfs receive /snapshot/home
$ btrfs send /backup/home/YYMMDD-HHMMSS | btrfs receive /snapshot/root_

.. unless I am missing something this restores root onto home and home onto root...

Repo transfer

Hi,

I'm not sure about notifications for comments on closed pull requests... Did you get them?

Just in case you didn't:

Everything seems merged ok and ready for transfer.

Best regards
Robert

Cleanup doesn't work with prefix

If you specify --snapshot-prefix foo, then the cleanup of old backups doesn't work:

backup complete
Traceback (most recent call last):
  File "/opt/btrfs-backup/btrfs-backup.py", line 224, in <module>
    delete_old_backups(backuploc,NUM_BACKUPS)
  File "/opt/btrfs-backup/btrfs-backup.py", line 115, in delete_old_backups
    bak_dir_to_remove = datestr(find_old_backup(bak_dir_time_objs, 0))
  File "/opt/btrfs-backup/btrfs-backup.py", line 84, in find_old_backup
    min_val = min(tmp) # find minimum time value
ValueError: min() arg is an empty sequence

This is caused by line 110 in delete_old_backups, where time.strptime() is applied to the snapshot directory names with the matching pattern %Y%m%d-%H%M%S, ignoring the prefix and thus not matching any directories:

                bak_dir_time_objs.append(time.strptime(directory, '%Y%m%d-%H%M%S'))

trying to snapshot over ssh

I'm trying to make a backup of the rootfs of my notebook and pushiung it to my server but it doesn't work. I can't really spot the error. Any ideas?

$ sudo btrfs-backup --sync --num-snapshots 1 --num-backups 3 --snapshot-folder '.snapshots' --snapshot-prefix 'mynotebook_root_' / ssh://username@myserver:22/home/username/backups --ssh-opt 'IdentityFile=/home/username/.ssh/id_rsa'
02:41:21  [INFO ]  --[ Started at Sun Jun 18 02:41:21 2017 ]---------
02:41:21  [INFO ]  --[ Preparing endpoints ... ]---------------------
02:41:21  [INFO ]  Creating directory: /.snapshots
02:41:21  [INFO ]  --[ Snapshotting ... ]----------------------------
02:41:21  [INFO ]  / -> /.snapshots/mynotebook_root_20170618-024121
02:41:21  [INFO ]  --[ Syncing disks ... ]---------------------------
02:41:22  [INFO ]  --[ Sending ... ]---------------------------------
02:41:22  [INFO ]  From:         mynotebook_root_20170618-024121
02:41:22  [INFO ]  To:           (SSH) username@myserver:22/home/username/backups
02:41:22  [INFO ]  No previous snapshot found, sending full backup.
At subvol /.snapshots/mynotebook_root_20170618-024121
Arch Linux \r (\l)

Enter passphrase for key '/home/username/.ssh/id_rsa': 
ioctl(BTRFS_IOC_TREE_SEARCH, subvol_id 480) ret=-1, error: Operation not permitted
ERROR: cannot resolve our subvol path
02:41:25  [ERROR]  Error during btrfs send / receive

/home/username/backups on the server is a mounted subvolume. If I just create a folder in the users homedir I get a different error:

$ sudo btrfs-backup --sync --num-snapshots 1 --num-backups 3 --snapshot-folder '.snapshots' --snapshot-prefix 'mynotebook_root_' / ssh://username@myserver:22/home/username/backups --ssh-opt 'IdentityFile=/home/username/.ssh/id_rsa'
02:46:55  [INFO ]  --[ Started at Sun Jun 18 02:46:54 2017 ]---------
02:46:55  [INFO ]  --[ Preparing endpoints ... ]---------------------
02:46:55  [INFO ]  --[ Snapshotting ... ]----------------------------
02:46:55  [INFO ]  / -> /.snapshots/mynotebook_root_20170618-024654
02:46:55  [INFO ]  --[ Syncing disks ... ]---------------------------
02:46:55  [INFO ]  --[ Sending ... ]---------------------------------
02:46:55  [INFO ]  From:         mynotebook_root_20170618-024654
02:46:55  [INFO ]  To:           (SSH) username@myserver:22/home/username/backups
02:46:55  [INFO ]  No previous snapshot found, sending full backup.
At subvol /.snapshots/mynotebook_root_20170618-024654
Arch Linux \r (\l)

Enter passphrase for key '/home/username/.ssh/id_rsa': 
ERROR: cannot open /home: Operation not permitted
02:46:59  [ERROR]  Error during btrfs send / receive

/home is a subvolume on the server.

Feature request: parse-able output (JSON?)

We are doing offsite backups from a VPS to a residential based server where the internet can be spotty at times... what I am noticing is that the backups will get synced the next time a successful remote connection is made from the host to the residential side... however, it would be nice to be able to indicate X snapshots transferred in Y seconds when these cases happen.

I push the results from btrfs-backup -P to a variable and then pipe that variable to pushbullet for a poor man's monitoring system... this results in a message like:

snapshotname=At snapshot 20180430-174503

Or when the remote connection fails...
snapshotname=

Would love to be able to output more meaningful logs to my client.

I'll take a stab at this myself as well, but python is not my forte these days.

Thanks again for an awesome utility!

Destination not available

Hi,

I've got a laptop with Ubuntu 16.04.
I've got 2 devices:

  • /dev/sda1 in /mnt/root with 2 subvolumes @ for the / and @home for /home.
  • /dev/sdb1 in /media/abz/datalx/ where I would like to store my backup (in a directory backup/home).

I have a crontab for backup like that:

/usr/local/bin/btrfs-backup -q -N 5 -n 10 -s /mnt/root/@home /media/abz/datalx/backup/home

My problem is when my second device /media/abz/datalx is not mounted (when I not on my desk) btrfs-backup create a directory on /dev/sda1.

How could I not send my bakcup if the device is not mounted ?
But I would like the snapshot being done in local (and send later).

btrfs-backup Version?

I try to make openSUSE RPM for btrfs-backup, but can't without Version.
Please add Version file or in README.md.

dependancies include setuptools

root@galileo:/usr/local/btrfs-backup# ./setup.py install
Traceback (most recent call last):
File "/usr/local/btrfs-backup/./setup.py", line 4, in
from setuptools import setup
ModuleNotFoundError: No module named 'setuptools'

pip3 install setuptools

and away we go.

Backup to dir?

Is it possible to send a backup to a directory? I want to backup my root drive to my local data drive, but the data drive does not use btrfs. How can I save a snapshot to that drive?

Bad configuration option: auto_unmount

Despite having installed sshfs and pv (since I noticed via debug that pv was missing) I still cannot manage to get around this error... Unfortunately, googling for it is nye impossible because ssh is such a prolific topic :(

Any suggestions? SSH is connecting just fine, as it creates the proper dir on the destination...

12:01:50 [INFO ] Sending 20180414-120149 ...
12:01:50 [INFO ] No parent snapshot available, sending in full mode.
12:01:50 [DEBUG] Checking for pv ...
12:01:50 [DEBUG] Executing: ['pv', '--help']
12:01:50 [DEBUG] -> pv is available
12:01:50 [DEBUG] Executing: ['btrfs', 'send', '/home/user/lib/snapshot/20180414-120149']
12:01:50 [DEBUG] Executing: ['pv']
12:01:50 [DEBUG] Executing: ['ssh', '-o', 'auto_unmount', '-o', 'reconnect', '-o', 'cache=no', 'backups', 'btrfs', 'receive', '/media/backups/user/snapshots/lib']
At subvol /home/user/lib/snapshot/20180414-120149
command-line: line 0: Bad configuration option: auto_unmount

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.