By default, you can store the snapshots you take of your Btrfs subvolumes in the same Btrfs filesystem, but it is not possible to store the snapshots of one Btrfs filesystem directly to another Btrfs filesystem. However, the Btrfs filesystem provides you with the necessary tools to back up snapshots of one Btrfs filesystem to another Btrfs filesystem. This article shows you how to back up Btrfs snapshots to an external Btrfs filesystem on an external drive.

Prerequisites

To try out the examples included in this article, you must fulfill the following prerequisites:

  • Have the Btrfs filesystem installed on your computer.
  • Have a hard disk or SSD with at least 2 free partitions (of any size).

I have the 20 GB hard disk, sdb, on my Ubuntu machine. I have created two partitions, sdb1 and sdb2, on this hard disk.

Note: Your hard disk or SSD will have a different name than mine, and so will the partitions. So, be sure to replace these names with yours from now on.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image29.png" data-lazy- height="300" src="data:image/svg xml,” width=”711″>

I will create Btrfs filesystems on the sdb1 and the sdb2 partitions. The snapshots created on the Btrfs filesystem (sdb1) will be backed up to the Btrfs filesystem created on the sdb2 partition. The Btrfs filesystem created on the sdb2 partition will act as the external drive. You may use a USB thumb drive or an external hard drive, as well; just be sure to format it with the Btrfs filesystem.

For assistance with installing the Btrfs filesystem in Ubuntu, check out my article Install and Use Btrfs on Ubuntu 20.04 LTS.

For assistance with installing the Btrfs filesystem in Fedora, check out my article Install and Use Btrfs on Fedora 33.

Creating Required Btrfs Filesystems

I will format both the sdb1 and sdb2 partitions as Btrfs. I will use the sdb1 partition for storing the data and Btrfs snapshots. I will use the sdb2 partition for backing up the snapshots of the Btrfs filesystem created on the sdb1 partition.

To create a Btrfs filesystem on the sdb1 partition and give it the filesystem label data, run the following command:

$ sudo mkfs.btrfs -L data /dev/sdb1

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image31.png" data-lazy- height="83" src="data:image/svg xml,” width=”621″>

A Btrfs filesystem should now be created on the sdb1 partition.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image30.png" data-lazy- height="556" src="data:image/svg xml,” width=”633″>

To create a Btrfs filesystem on the sdb2 partition and give it the filesystem label snapshots, run the following command:

$ sudo mkfs.btrfs -L snapshots /dev/sdb2

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image33.png" data-lazy- height="83" src="data:image/svg xml,” width=”666″>

A Btrfs filesystem should now be created on the sdb2 partition.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image32.png" data-lazy- height="575" src="data:image/svg xml,” width=”716″>

Create the directories /data and /snapshots for mounting the sdb1 and sdb2 partitions, respectively, as follows:

$ sudo mkdir -v /{data,snapshots}

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image35.png" data-lazy- height="154" src="data:image/svg xml,” width=”638″>

Mount the Btrfs filesystem you have created on the sdb1 partition on the /data directory, as follows:

$ sudo mount /dev/sdb1 /data

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image34.png" data-lazy- height="87" src="data:image/svg xml,” width=”625″>

In the same way, mount the Btrfs filesystem you have created on the sdb2 partition on the /snapshots directory, as follows:

$ sudo mount /dev/sdb2 /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image37.png" data-lazy- height="87" src="data:image/svg xml,” width=”616″>

As you can see in the screenshot below, both the Btrfs filesystems (sdb1 and sdb2 partitions) have been mounted correctly.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image36.png" data-lazy- height="176" src="data:image/svg xml,” width=”627″>

In this section, we will create the dummy project web1 on the /data/projects/web1 Btrfs subvolume. We will take a snapshot of that subvolume in this section, as well as some other snapshots in later sections of this article.

First, create the new directory /data/projects, as follows:

$ sudo mkdir -v /data/projects

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image40.png" data-lazy- height="130" src="data:image/svg xml,” width=”642″>

Next, create the new subvolume web1 in the /data/projects directory, as follows:

$ sudo btrfs subvolume create /data/projects/web1

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image38.png" data-lazy- height="133" src="data:image/svg xml,” width=”777″>

Finally, create the new file index.html in the /data/projects/web1 subvolume with the nano text editor, as follows:

$ sudo nano /data/projects/web1/index.html

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image39.png" data-lazy- height="86" src="data:image/svg xml,” width=”712″>

Type in the following lines of code in the index.html file:

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image41.png" data-lazy- height="497" src="data:image/svg xml,” width=”842″>

Once you are done, press <Ctrl> X followed by Y and <Enter> to save the index.html file.

In the same way, create the new file style.css in the /data/projects/web1 subvolume as follows:

$ sudo nano /data/projects/web1/style.css

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image42.png" data-lazy- height="87" src="data:image/svg xml,” width=”695″>

Type the following lines of code in the style.css file:

h1 {

        color: green;

}

Once you are done, press <Ctrl> X followed by Y and <Enter> to save the style.css file.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image43.png" data-lazy- height="495" src="data:image/svg xml,” width=”833″>

Now, the /data/projects/web1 subvolume contains the index.html and style.css file.

$ ls -lh /data/projects/web1

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image44.png" data-lazy- height="180" src="data:image/svg xml,” width=”584″>

We will keep all the snapshots of this Btrfs filesystem in the /data/.snapshots directory.

First, create the /data/.snapshots directory with the following command:

$ sudo mkdir -v /data/.snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image45.png" data-lazy- height="133" src="data:image/svg xml,” width=”610″>

Next, create the read-only snapshot /data/.snapshots/web1-2020-12-30 of the /data/projects/web1 subvolume with the following command:

$ sudo btrfs subvolume snapshot -r /data/projects/web1 /data/.snapshots/web1-20201230

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image46.png" data-lazy- height="131" src="data:image/svg xml,” width=”1207″>

As you can see, the new snapshot /data/.snapshots/web1-2020-12-30 has been created.

$ sudo btrfs subvolume list /data

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image47.png" data-lazy- height="167" src="data:image/svg xml,” width=”752″>

Backing up Snapshots to External Drive

To back up the snapshot /data/.snapshots/web1-2020-12-30 to another Btrfs filesystem (external drive sdb2, in this case) mounted on the /snapshots directory, run the following command:

$ sudo btrfs send /data/.snapshots/web1-20201230 | sudo btrfs receive /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image48.png" data-lazy- height="78" src="data:image/svg xml,” width=”1092″>

The snapshot /data/.snapshots/web1-2020-12-30 should be backed up to the external Btrfs filesystem (sdb2) mounted on the /snapshots directory.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image19-1.png" data-lazy- height="153" src="data:image/svg xml,” width=”1101″>

As you can see, the new subvolume web1-2020-12-30 has been created on the external Btrfs filesystem.

$ sudo btrfs subvolume list /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image20-1.png" data-lazy- height="128" src="data:image/svg xml,” width=”720″>

The snapshot web1-2020-12-30 should have the same files/directories as the /data/.snapshots/web1-2020-12-30 snapshot.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image21-1.png" data-lazy- height="238" src="data:image/svg xml,” width=”706″>

You can obtain more information about the backed-up snapshot /snapshosts/web1-2020-12-30 as follows:

$ sudo btrfs subvolume show /snapshots/web1-20201230

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image22-2.png" data-lazy- height="397" src="data:image/svg xml,” width=”837″>

Incremental Back-up of Snapshots to External Drive

If there are a lot of files in the snapshots to back up to an external drive, then incremental backups will help you speed up the back-up operation. In this case, Btrfs will only update the files that have changed since the last snapshot and copy new files that were not available in the last snapshot.

In this section, I will show you how to perform incremental back-ups of Btrfs snapshots to external Btrfs filesystems.

First, open the index.html file from the /data/projects/web1 subvolume, as follows:

$ sudo nano /data/projects/web1/index.html

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image23-1.png" data-lazy- height="93" src="data:image/svg xml,” width=”702″>

Make any changes you want to the index.html file. Once you are done, press <Ctrl> X followed by Y and <Enter> to save the index.html file.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image24-1.png" data-lazy- height="575" src="data:image/svg xml,” width=”795″>

Take a new read-only snapshot of the /data/projects/web1 subvolume, as follows:

$ sudo btrfs subvolume snapshot -r /data/projects/web1 /data/.snapshots/web1-20201231

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image25.png" data-lazy- height="134" src="data:image/svg xml,” width=”1160″>

As you can see, the new snapshot /data/.snapshots/web1-2020-12-31 of the /data/projects/web1 subvolume has been created.

$ sudo btrfs subvolume list /data

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image26-1.png" data-lazy- height="186" src="data:image/svg xml,” width=”768″>

Now, we are ready to take an incremental backup.

To take an incremental backup, you will need a common snapshot of both the source and the destination (external drive) Btrfs filesystems. The common snapshot is usually the latest snapshot of a Btrfs subvolume. When you take a new snapshot on the source Btrfs filesystem, the new snapshot is compared with the latest snapshot (available on both the source and the destination Btrfs filesystem) of the source Btrfs filesystem. Btrfs will calculate the difference and send only the required data to the destination Btrfs filesystem (the external drive).

For example, to take an incremental backup of the /data/.snapshots/web1-2020-12-31 snapshot, you must specify the parent snapshot (the latest snapshot available on both the source and destination Btrfs filesystems), /data/.snapshots/web1-2020-12-30, as well.

An incremental backup of the /data/.snapshots/web1-2020-12-31 snapshot can be taken to an external Btrfs filesystem, as follows:

$ sudo btrfs send -p /data/.snapshots/web1-20201230 /data/.snapshots/web1-20201231 | sudo btrfs receive /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image27.png" data-lazy- height="112" src="data:image/svg xml,” width=”1148″>

An incremental backup of the /data/.snapshots/web1-2020-12-31 snapshot should be taken.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image28.png" data-lazy- height="170" src="data:image/svg xml,” width=”1146″>

As you can see, the web1-2020-12-31 snapshot has been backed up to the external Btrfs filesystem mounted on the /snapshots directory.

$ sudo btrfs subvolume list /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image9-6.png" data-lazy- height="152" src="data:image/svg xml,” width=”798″>

As you can see in the screenshot below, the changes you have made to the index.html file are available in the web1-2020-12-31 snapshot that has been backed up to the external Btrfs filesystem.

$ cat /snapshots/web1-20201231/index.html

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image10-5.png" data-lazy- height="335" src="data:image/svg xml,” width=”755″>

In the same way, you may take as many incremental backups of your snapshots as you want.

I will show you how to do an incremental backup one more time. I will not take the time to explain it again. Instead, I will just show you the process for clarity.

Open the index.html file from the /data/projects/web1 subvolume, as follows:

$ sudo nano /data/projects/web1/index.html

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image11-4.png" data-lazy- height="86" src="data:image/svg xml,” width=”686″>

Make any changes you want to the index.html file. Once you are done, press <Ctrl> X followed by Y and <Enter> to save the index.html file.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image12-3.png" data-lazy- height="615" src="data:image/svg xml,” width=”652″>

Take a new read-only snapshot of the /data/projects/web1 subvolume, as follows:

$ sudo btrfs subvolume snapshot -r /data/projects/web1 /data/.snapshots/web1-20201231_2

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image13-3.png" data-lazy- height="129" src="data:image/svg xml,” width=”1169″>

Take an incremental backup of the /data/.snapshots/web1-2020-12-31_2 snapshot to an external Btrfs filesystem, as follows:

$ sudo btrfs send -p /data/.snapshots/web1-20201231 /data/.snapshots/web1-20201231_2 | sudo btrfs receive /snapshots

Note: Now, the parent snapshot to which the /data/.snapshots/web1-2020-12-31_2 snapshot will be compared is /data/.snapshots/web1-2020-12-31.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image14-3.png" data-lazy- height="179" src="data:image/svg xml,” width=”1166″>

As you can see, the web1-2020-12-31_2 snapshot has been backed up to the external Btrfs filesystem mounted on the /snapshots directory.

$ sudo btrfs subvolume list /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image15-3.png" data-lazy- height="169" src="data:image/svg xml,” width=”703″>

As you can see in the screenshot below, the recent changes made to the index.html file are available on the web1-2020-12-31_2 snapshot backed up to the external Btrfs filesystem.

$ cat /snapshots/web1-20201231_2/index.html

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image16-1.png" data-lazy- height="337" src="data:image/svg xml,” width=”723″>

Keeping Things Clean

If you back up your Btrfs snapshots frequently, you will end up with a lot of snapshots, and it may become difficult to manage them. Luckily, you can remove any snapshot from the Btrfs filesystem.

If you are using a large enough external drive for keeping backups of the Btrfs snapshots, then you can keep a few snapshots on your Btrfs filesystem and back up all the snapshots on your external drive.

If you are using a smaller external drive, then you can selectively keep only the most important snapshots backed up on the external drive.

To perform backups of your Btrfs snapshots, you need to keep at least the latest snapshot on both the source (/data/.snapshots) and the destination (/snapshots – external drive) Btrfs filesystems. So, feel free to remove any snapshots other than the latest snapshot on both ends.

For example, in this case, the latest snapshot is web1-2020-12-31_2. So, to perform incremental backups, this snapshot must be kept on the source and the destination (external drive) Btrfs filesystems.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image17-1.png" data-lazy- height="290" src="data:image/svg xml,” width=”718″>

Suppose, you want to remove the /data/.snapshots/web1-2020-12-30 snapshot.

To do this, run the following command:

$ sudo btrfs subvolume delete /data/.snapshots/web1-20201230

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image18-1.png" data-lazy- height="80" src="data:image/svg xml,” width=”888″>

The Btrfs snapshot /data/.snapshots/web1-2020-12-30 should now be removed.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image1-13.png" data-lazy- height="128" src="data:image/svg xml,” width=”893″>

In the same way, you can remove the /data/.snapshots/web1-2020-12-31 snapshot, as follows:

$ sudo btrfs subvolume delete /data/.snapshots/web1-20201231

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image2-13.png" data-lazy- height="129" src="data:image/svg xml,” width=”900″>

Now, only the latest snapshot, /data/.snapshots/web1-2020-12-31_2, is available on the Btrfs filesystem, mounted on the /data directory. The other snapshots are backed up on the external drive, mounted on the /snapshots directory.

$ sudo btrfs subvolume list /data

$ sudo btrfs subvolume list /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image3-11.png" data-lazy- height="247" src="data:image/svg xml,” width=”725″>

Restoring Snapshots from External Drive

If you have backed up your snapshots on the external drive, you can restore them at any time from the external drive.

For example, I have removed the web1-2020-12-30 snapshot from my Btrfs filesystem, mounted on the /data directory. But, this snapshot is backed up on the external drive, mounted on the /snapshots directory. Let us restore this snapshot.

$ sudo btrfs subvolume list /snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image4-10.png" data-lazy- height="176" src="data:image/svg xml,” width=”758″>

To restore the web1-2020-12-30 snapshot from the external drive, run the following command:

$ sudo btrfs send /snapshots/web1-20201230 | sudo btrfs receive /data/.snapshots

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image5-9.png" data-lazy- height="87" src="data:image/svg xml,” width=”1110″>

The snapshot web1-2020-12-30 should be restored on the Btrfs filesystem mounted on the /data directory.

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image6-7.png" data-lazy- height="149" src="data:image/svg xml,” width=”1099″>

As you can see, the web1-2020-12-30 snapshot is restored on the Btrfs filesystem mounted on the /data directory.

$ sudo btrfs subvolume list /data

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image7-6.png" data-lazy- height="186" src="data:image/svg xml,” width=”825″>

And, as you can see, the contents of the index.html file from the web1-2020-12-30 snapshot. This is the first version of the index.html file from before.

$ cat /data/.snapshots/web1-20201230/index.html

<img alt="" data-lazy- data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/image8-6.png" data-lazy- height="328" src="data:image/svg xml,” width=”775″>

Conclusion

In this article, you learned how to back up snapshots of your Btrfs filesystem to an external drive. You also learned how to take incremental backups of your Btrfs snapshots to an external drive. Finally, you learned how to remove existing snapshots from a Brtfs filesystem and restore snapshots from the external drive, as well.

About the author

<img alt="Shahriar Shovon" data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/photo2-150×150.png6003c2fc08455.jpg" height="112" src="data:image/svg xml,” width=”112″>

Shahriar Shovon

Freelancer & Linux System Administrator. Also loves Web API development with Node.js and JavaScript. I was born in Bangladesh. I am currently studying Electronics and Communication Engineering at Khulna University of Engineering & Technology (KUET), one of the demanding public engineering universities of Bangladesh.