Note:
- This tutorial is available in an Oracle-provided free lab environment.
- It uses example values for Oracle Cloud Infrastructure credentials, tenancy, and compartments. When completing your lab, substitute these values with ones specific to your cloud environment.
Use Btrfs Send and Receive to Create a Secure Remote Backup Facility
Introduction
Having a backup is essential to avoid losing data. Using Btrfs and its send and receive features, we can configure secure sender and receiver systems to securely and efficiently remote backup a subvolume over SSH. Then, set up Systemd timers to perform regular, timely backups.
Note that only the changes made on the sender system are copied to the receiver system, reducing the backup facility’s overhead. Since the systems use Btrfs snapshots, the disk usage for incremental backups is restricted only to the size of the changes.
Objectives
In this tutorial, you will learn how to:
- Configure SSH to facilitate secure network-based backup
- Create a Btrfs receiver script on the receiver system
- Create a Btrfs snapshot on the sender system
- Send the Btrfs snapshot to the receiver system
- Create an incremental backup snapshot
- Create an incremental backup script
- Configure a Systemd service and timer unit for regular incremental backups
Prerequisites
-
Minimum of two Oracle Linux systems running the UEK kernel
-
Each system should have Oracle Linux installed and configured with:
- A non-root user account with sudo access
- A block device attached to each system and formatted with Btrfs
- Key-based SSH, also known as password-less SSH, between the hosts
Deploy Oracle Linux
Note: If running in your own tenancy, read the linux-virt-labs
GitHub project README.md and complete the prerequisites before deploying the lab environment.
-
Open a terminal on the Luna Desktop.
-
Clone the
linux-virt-labs
GitHub project.git clone https://github.com/oracle-devrel/linux-virt-labs.git
-
Change into the working directory.
cd linux-virt-labs/ol
-
Install the required collections.
ansible-galaxy collection install -r requirements.yml
-
Update the Oracle Linux instance configuration.
cat << EOF | tee instances.yml > /dev/null compute_instances: 1: instance_name: "ol-sender" type: "server" 2: instance_name: "ol-receiver" type: "server" add_block_storage: true block_count: 1 passwordless_ssh: true EOF
-
Deploy the lab environment.
ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6" -e "@instances.yml"
The free lab environment requires the extra variable
local_python_interpreter
, which setsansible_python_interpreter
for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.The default deployment shape uses the AMD CPU and Oracle Linux 8. To use an Intel CPU or Oracle Linux 9, add
-e instance_shape="VM.Standard3.Flex"
or-e os_version="9"
to the deployment command.Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of Oracle Cloud Native Environment is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.
Prepare the Block Volumes
-
Open a terminal and connect via SSH to the ol-sender instance.
ssh oracle@<ip_address_of_instance>
-
Format the block volume with a Btrfs file system and then mount it.
sudo mkfs.btrfs /dev/sdb sudo mkdir /source sudo mount /dev/sdb /source
-
Repeat on the ol-receiver instance.
ssh ol-receiver \ "sudo mkfs.btrfs /dev/sdb; \ sudo mkdir /backup; \ sudo mount /dev/sdb /backup"
Set Up a Dedicated User on the Receiver System
By creating a dedicated user to handle the btrfs receive requests, you can limit the likelihood that the backup process can be used as an attack vector to compromise systems.
-
Create a new user.
ssh ol-receiver "sudo adduser btrfsrcv"
Create a Btrfs Receiver Script on the Receiver System
-
Create the
btrfs_receive.sh
backup script on the receiver system in thebtrfsrcv
user’s home directory.ssh ol-receiver sudo tee /home/btrfsrcv/btrfs_receive.sh > /dev/null << EOF #!/bin/bash sudo /sbin/btrfs receive /backup EOF
-
Set the ownership and mode of the script so that the
btrfsrcv
user can run it.ssh ol-receiver \ "sudo chown btrfsrcv /home/btrfsrcv/btrfs_receive.sh; \ sudo chmod +x /home/btrfsrcv/btrfs_receive.sh"
-
Create a sudoer configuration drop-in so the
btrfsrcv
user can run the/sbin/btrfs receive
command on the/backup
directory.ssh ol-receiver sudo tee /etc/sudoers.d/200-btrfsrcv > /dev/null << EOF btrfsrcv ALL = (root) NOPASSWD: /sbin/btrfs EOF
Configure SSH to Facilitate Secure Network-Based Backup
-
Create an SSH key pair on the sender system that you can restrict for backup purposes.
sudo ssh-keygen -t rsa -b 4096 -f /root/.ssh/btrfs_backup -N ""
The
-N ""
skips the request for a passphrase for this key. Restrictions on using this key are configured later in this tutorial. -
Review the public key and assign its contents to a variable.
We’ll use the variable to copy the public key to the configuration for the
btrfsrcv
user on the receiver system.PUBLIC_KEY=$(sudo cat /root/.ssh/btrfs_backup.pub)
-
Verify the variable contains the public key.
echo $PUBLIC_KEY
-
Add the public key to the authorized_keys file for the
btrfsrcv
user on the receiver system.Ensure you also create the .ssh directory if it doesn’t already exist.
ssh ol-receiver \ "sudo mkdir /home/btrfsrcv/.ssh; \ sudo chown btrfsrcv:btrfsrcv /home/btrfsrcv/.ssh; \ sudo chmod 700 /home/btrfsrcv/.ssh"
-
Add restrictions for the key to limit its usage.
Edit the authorized_keys file on the receiver system to restrict the backup SSH key to a specific command.
ssh ol-receiver sudo tee -a /home/btrfsrcv/.ssh/authorized_keys > /dev/null << EOF command="/home/btrfsrcv/btrfs_receive.sh",from="$(hostname -i)" $PUBLIC_KEY EOF
The format consists of:
command=”<script>“,from=”<sender_host>” <public_key>
Substitute the following values:
<script>
: the full path and name of the script to which you want to grant access<sender_host>
: the IP address or hostname of the sender system where we created the private key<public_key>
: the value of the public key that you created on the sender system
For this tutorial, edit
/home/btrfsrcv/.ssh/authorized_keys
and add the entry. -
Set the correct ownership and permissions on the authorized_keys file.
ssh ol-receiver \ "sudo chown btrfsrcv:btrfsrcv /home/btrfsrcv/.ssh/authorized_keys; \ sudo chmod 600 /home/btrfsrcv/.ssh/authorized_keys"
Test Sending a Btrfs Snapshot to the Receiver System
-
Touch a file in the Btrfs file system on the sender system.
sudo touch /source/testfile
-
Make a directory to store the local snapshots.
sudo mkdir /source/.snapshots
-
Create a Btrfs snapshot of the source file system.
sudo btrfs subvolume snapshot -r /source /source/.snapshots/test1
-
Send the snapshot to the receiver system.
sudo btrfs send /source/.snapshots/test1 | sudo ssh -T -i /root/.ssh/btrfs_backup btrfsrcv@ol-receiver
The
-T
in the SSH command avoids thePseudo-terminal will not be allocated
warning message. -
Validate that the snapshot gets copied to the receiver system and that the testfile is present.
ssh ol-receiver sudo ls /backup/test1
Create an Incremental Backup Snapshot
Create an incremental backup snapshot so that you can see the replicated changes.
-
Add some content to the Btrfs source directory on the sender system.
sudo touch /source/testfile2 echo "updated text in testfile"|sudo tee -a /source/testfile
-
Create a new backup snapshot to capture the changes.
sudo btrfs subvolume snapshot -r /source /source/.snapshots/test2
-
Send the updated snapshot to the receiver system.
sudo btrfs send /source/.snapshots/test2 | sudo ssh -T -i /root/.ssh/btrfs_backup btrfsrcv@ol-receiver
-
Validate that the snapshot gets copied.
Confirm that testfile2 is present and that the new content exists within the testfile.
ssh ol-receiver \ "sudo ls /backup/test2/testfile2 sudo cat /backup/test2/testfile"
Create an Incremental Backup Script
-
Create a script directory.
sudo mkdir /scripts
-
Create a backup script.
cat << 'EOF' | sudo tee /scripts/btrfs-backup.sh > /dev/null #!/bin/bash # Variables SOURCE="/source" SNAPSHOT_DIR="/source/.snapshots" LATEST_SNAPSHOT=$(ls -1 ${SNAPSHOT_DIR} | tail -n 1) NEW_SNAPSHOT="${SNAPSHOT_DIR}/$(date +'%Y%m%d%H%M%S')" RECEIVER="btrfsrcv@ol-receiver" # Create a new snapshot sudo btrfs subvolume snapshot -r ${SOURCE} ${NEW_SNAPSHOT} # Send the new snapshot if [ -z "${LATEST_SNAPSHOT}" ]; then sudo btrfs send ${NEW_SNAPSHOT} | sudo ssh -T -i /root/.ssh/btrfs_backup ${RECEIVER} else sudo btrfs send -p ${SNAPSHOT_DIR}/${LATEST_SNAPSHOT} ${NEW_SNAPSHOT} | sudo ssh -T -i /root/.ssh/btrfs_backup ${RECEIVER} fi EOF
Note: If running outside of the free lab environment, set the
RECEIVER
variable in the script tobtrfsrcv@
and the IP address or hostname of the receiver system. -
Change the mode on the backup script so that it can run.
sudo chmod +x /scripts/btrfs-backup.sh
-
Test the script by creating additional content in the Btrfs source directory.
sudo touch testfile3
-
Run the backup script.
sudo /scripts/btrfs-backup.sh
-
Check the backup directory on the receiver system to see if it contains the new snapshot.
ssh ol-receiver sudo ls /backup
Note that the backup script uses the date and time to name the snapshot directory.
Configure a Systemd Service and Timer Unit
You can configure a systemd service and timer unit on the sender system to perform regular incremental backups. This example creates a systemd unit to run the backup script daily.
-
Create a systemd service unit file for the backup script.
cat <<EOF | sudo tee /etc/systemd/system/btrfs_backup.service > /dev/null [Unit] Description=Btrfs Backup Service [Service] Type=oneshot ExecStart=/bin/bash /scripts/btrfs-backup.sh EOF
-
Create a systemd timer unit file to schedule the backup service.
cat <<EOF | sudo tee /etc/systemd/system/btrfs_backup.timer > /dev/null [Unit] Description=Run Btrfs Backup Service Daily [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target EOF
-
Enable and start the systemd timer to schedule the backups.
sudo systemctl enable --now btrfs_backup.timer
-
Verify that the systemd.timer unit is running correctly.
sudo systemctl status btrfs_backup.timer
-
Test the systemd service.
sudo systemctl start btrfs_backup.service
-
Check the backup directory on the receiver system to see if it contains the latest snapshot.
ssh ol-receiver sudo ls /backup
For More Information
More Learning Resources
Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.
For product documentation, visit Oracle Help Center.
Use Btrfs Send and Receive to Create a Secure Remote Backup Facility
G13035-01
August 2024