My updated virtualmin BTRFS / snapper integration script

This week I finished setting up a new virtualmin server which uses BTRFS for /home. Each user has their own btrfs subvolume with about 10 automatic snapper snapshots going back 2 weeks. After configuring your vmin server as described below, each user can browse and read and recover old versions of (deleted) files by browsing their ~/.snapshots dir.

This is the poor mans version of what I previously did by integrating ZFS snapshots with virtualmin. I do not cover how I configured my btrfs /home dir here but this should still be useful for those familiar enough with BTRFS to configure your vmin servers disk config in a suitable manner.

I have already discussed the basics of configuring BTRFS quotas in a previous post on here;

If you wish to use snapper to create automatic btrfs snapshots of users home subvolumes, under Ubuntu and Debian you should configure /etc/snapper/config-templates/default first.

I use these snapper default settings to keep 10 snapshots per user subvol. BTRFS performance can start to suffer if you have more than about 15 or so snapshots per subvolume.


TIMELINE_LIMIT_HOURLY="3"
TIMELINE_LIMIT_DAILY="5"
TIMELINE_LIMIT_WEEKLY="2"
TIMELINE_LIMIT_MONTHLY="0"
TIMELINE_LIMIT_YEARLY="0"

This following script must be configured to be run via System Settings → Virtualmin Configuration → Actions upon server and user creation and pasting the full path to this script in the field next to Command to run before making changes to a server.

When you have this script configured to bed run from there, every time you create a new domain/user they will have snapper snapshots configured as well as a standardised btrfs quota limit configured for their subvolume. All of the users snapshots and their related snapper config files will be removed when you delete their domain/user using the regular virtualmin create/delete domain commands.

#!/bin/sh
if [ "$VIRTUALSERVER_ACTION" = "CREATE_DOMAIN" ]; then
      #Create a new subvol for the user
      /usr/bin/btrfs sub create /home/$VIRTUALSERVER_USER

      #Limit the subvol to 1GB
      /usr/bin/btrfs qgroup limit 1024M /home/$VIRTUALSERVER_USER
      
      #Create a snapper config for the new user/subvol
      /usr/bin/snapper -c $VIRTUALSERVER_USER create-config /home/$VIRTUALSERVER_USER

      #Configure the users snapper config to enable them to use the snapper tool to list snapshots
      /usr/bin/sed -i "/ALLOW_USERS/c\ALLOW_USERS=\"$VIRTUALSERVER_USER\"" /etc/snapper/configs/$VIRTUALSERVER_USER

       #Change the users .snapshots dir permissions to allow the user read access         
       /usr/bin/chown $VIRTUALSERVER_USER:$VIRTUALSERVER_USER /home/$VIRTUALSERVER_USER/.snapshots
       /usr/bin/chmod 500 /home/$VIRTUALSERVER_USER/.snapshots
fi
if [ "$VIRTUALSERVER_ACTION" = "DELETE_DOMAIN" ]; then
      #Remove the users snapper config and snapshots
      /usr/bin/snapper -c $VIRTUALSERVER_USER delete-config

      #Delete the users subvolume
      /usr/bin/btrfs sub delete /home/$VIRTUALSERVER_USER
fi
2 Likes

I should’ve tested this more thoroughly before posting it here. The script in the first post isn’t quite right because snapper insists that the ~/.snapshots dir is owned by root so if you want to allow normal users read access to their own snapshots you have to make each users ~/.snapshots dir readable by that users group. I would’ve edited the first post if I was able to do so but its too late for me to edit the first post now.

The correct Command to run before making changes to a server script from the first post should look like this:

#!/bin/sh
if [ "$VIRTUALSERVER_ACTION" = "CREATE_DOMAIN" ]; then
	  #Create a new subvol for the user
	  /usr/bin/btrfs sub create /home/$VIRTUALSERVER_USER

	  #Limit the subvol to 1GB
	  /usr/bin/btrfs qgroup limit 1024M /home/$VIRTUALSERVER_USER
	  
      #Create a snapper config for the new user/subvol
      /usr/bin/snapper -c $VIRTUALSERVER_USER create-config /home/$VIRTUALSERVER_USER

	  #Configure the users snapper config to allow snapper use
	  /usr/bin/snapper -c $VIRTUALSERVER_USER set-config ALLOW_USERS=$VIRTUALSERVER_USER 
fi
if [ "$VIRTUALSERVER_ACTION" = "DELETE_DOMAIN" ]; then
	  #Remove the users snapper config and snapshots
      /usr/bin/snapper -c $VIRTUALSERVER_USER delete-config

	  #Delete the users subvolume
	  /usr/bin/btrfs sub delete /home/$VIRTUALSERVER_USER
fi

A second script is required to give users read access to their ~/.snapshots directory. This script must be configured to run under System Settings → Virtualmin Configuration → Actions upon server and user creation-> Command to run after making changes to a server

#!/bin/sh
chown root:$VIRTUALSERVER_GID /home/$VIRTUALSERVER_USER/.snapshots/
chmod g+rx /home/$VIRTUALSERVER_USER/.snapshots/
3 Likes

Ilia pointed out on github that it would be tidier to run all of this code as part of the Command to run after making changes to a server instead of splitting it into two scripts. I’ve not tested that yet but it makes a lot of sense and its probably the way to go.

Before this thread gets closed, the tidy version would be run via Command to run after making changes to a server and would look like:

#!/bin/sh
if [ "$VIRTUALSERVER_ACTION" = "CREATE_DOMAIN" ]; then
	  #Create a new subvol for the user
	  /usr/bin/btrfs sub create /home/$VIRTUALSERVER_USER

	  #Limit the subvol to 1GB
	  /usr/bin/btrfs qgroup limit 1024M /home/$VIRTUALSERVER_USER
	  
      #Create a snapper config for the new user/subvol
      /usr/bin/snapper -c $VIRTUALSERVER_USER create-config /home/$VIRTUALSERVER_USER

	  #Configure the users snapper config to allow snapper use
	  /usr/bin/snapper -c $VIRTUALSERVER_USER set-config ALLOW_USERS=$VIRTUALSERVER_USER
	  
	  #Make users ~/.snapshots dir readable by the users group
	  chown root:$VIRTUALSERVER_GID /home/$VIRTUALSERVER_USER/.snapshots/
      chmod g+rx /home/$VIRTUALSERVER_USER/.snapshots/

fi
if [ "$VIRTUALSERVER_ACTION" = "DELETE_DOMAIN" ]; then
	  #Remove the users snapper config and snapshots
      /usr/bin/snapper -c $VIRTUALSERVER_USER delete-config

	  #Delete the users subvolume
	  /usr/bin/btrfs sub delete /home/$VIRTUALSERVER_USER
fi

There should be no need for a second script when it is run after making changes to a server, which in my case is caused whenever I run:

virtualmin create-domain ...

As part of my new user/domain creation script.

Oh and another thing I should’ve included in the first post. In /etc/snapper/config-templates/default you should also configure:

NUMBER_LIMIT="10"

Or however many snapshots you wish to retain per user. I wouldn’t keep much more than 10-15 to reduce the chances of degraded performance. 10 should be safe.

You should also have:

NUMBER_CLEANUP="yes"

So that the excess snapshots get removed but that is usually configured by default.