How to setup Raspberry Pi as Backup Server for Linux and Windows Desktops

The Raspberry Pi is a series of small single-board computers. They are rather cheap and are well suited for running a backup server or voip server. In february 2015 the Raspberry Pi 2 was released. It has more ram, newer cpu and features 4 onboard USB ports.

Current price for the Raspberry Pi 2 is $ 35.-. However in addition you need a few other things:

  • microSD card: The Raspberry Pi 2 requires a microSD card to boot from. Any should do with 4GB or more. For the backup server 4GB should be plenty. You might want to get one that reads fast.
  • Micro USB Power Charger: Also you'll need a power supply for it. It is powered by a micro usb port so very likely you'll have a charger at home from an old mobile phone that you don't need anymore.
  • External USB Storage: Since this howto is about setting up a backup server, you also need to get external USB storage. Maybe an external 512GB harddisk is enough, maybe you need a 4TB drive. That's all up to your storage needs.
  • Casing: The last thing is the casing. You don't strictly need casing but if you don't use one then you'll have just have the whole mainboard laying around somewhere and it's more suspectible to damage.

So the total costs will be like $ 35.- for the Raspberry Pi, about $10.- for the microSD card, about $10.- for the case, nothing for the micro usb charger since you probably have one, and then whatever the external usb drive costs.

Also, for retrieving backups I setup samba and the share is in read-only mode without any required credentials. If properly configured according to this guide, it will only be available in the lan and refused any connection attempt from outside the lan. Setting up also samba users and different credentials would go beyond the scope of thise howto. There are plenty of other howtos that explain it and it could be incorporated easily if there's a need for it.

Setting up the Raspberry Pi as backup server

Setting up the Raspberry Pi as backup server is the "most" difficult part of it since you first have to flash an image and then make everything ready. However the step-by-step guide should take you through it.

1. Download Raspian Image

First download the current Raspian Image from here https://www.raspberrypi.org/downloads/

2. Flash the image onto the microSD card

After downloading the image you'll need to flash it to the microSD card. Since there are already excellent guides out there for doing this, there's no point in repeating this over here. Best follow the guid here

3. First Boot / Configuration

After you have flashed the Raspberry Pi with the Raspian Image, attach a HDMI screen to it and boot it up. On first boot, you'll be presented a configuration screen. That configuration screen is pretty simple and there's a few things that you should set.

Disclaimer: The pics were taken with a cell phone so they aren't that great.

4. Expand Filesystem

First we want to have available the full space on the sdcard. For the backups it doesn't really matter as they will be stored on an external drive anyway. However I do like to have the space available. So select 1 Expand Filesystem and then you'll be prompted with a notification that upon next reboot, the filesystem will be expanded.

5. Change User Password

Then we want to alter the default password for the user "pi". So select 2 Change User Password and then type your desired password twice, each time followed by Enter. Again you'll be prompted with a notification that the password was changed.

6. Console Login

Afterwards we want to make sure that we don't start and gui. So select 3 Enable Boot to Desktop/Scratch. On the following screen select Console Text console, requiring login (default).

7. Localisation

Then we want to set the system language and other available languages, keyboard layout etc. For that we go into 4 Internationalisation Options. When you enter that, you'll be presented to change the languages, timezone and keyboard language. The dialogs are all easy, so I won't go into further details.

Notice: If you have selected on of those options, you'll end up at the main config screen again.

8. Advanced Options

Now go into the 8. Advanced Options. There we have another bunch of stuff we can set. The three important ones are A2 Hostname, A3 Memory Split and A4 SSH.

9. Set the Hostname

The hostname will allow you to access the Raspberry Pi by its hostname on the lan. Beware: You can only use letters and numbers. In this example I use as hostname rpi2bu - short for Raspberry Pi 2 Backup but it's all up to you.

10. Memory Split

Since we want to run this Raspberry Pi as backup server, we don't wanna waste precious ram on the gpu. Remember: This is a headless server. So set the ram split to 16MB.

11. Enable OpenSSH Server

Since we'll do our backups with rsync through ssh and since ssh access is good for remonte administration of the Raspberry Pi, enable also the OpenSSH Server in the advanced options menu.

11. Finish and Reboot

So, those are all the things to be set from the configuration screen and you can now select from the main configuration. Once you do, the Raspberry Pi reboots and after a while you'll be prompted for your login credentials. Currently the user is pi and the password is set what you did set in step 5. Also it will show you the current ip address of the Raspberry Pi.

12. Update and install required packages

To have the Raspberry Pi as backup server we will need to install two additional packages: rsync and samba. Rsync is the tool that syncs the files from your Windows / Linux computer and samba will then make the backups available on the network (in read-only mode).

Since there are always lots of changes and updates coming, we first run:

sudo apt-get update && sudo apt-get upgrade

and then we install the required packages by:

sudo apt-get install rsync samba

Notice:The default user pi can run system commands as root with the sudo command. When you use the sudo command you are again prompted for your login password. This password will also be cached for some time, so running two sudo commands after one another should only trigger once the password input.

13. Continue with Remote SSH connection or on the Raspberry Pi

The next steps can be done in the Raspberry Pi itself or through a ssh connection. I prefer ssh connections and on linux I just use Konsole in my KDE. On Windows, you could use Putty or Kitty

14. Locate and Format the external USB drive

Before we configure the samba server, we need to mount the external usb drive and create a backup user. Before we can mount the external usb drive, we'll need to format it and know it's UUID. So before you attach your external USB drive, run:

ls -al /dev/disk/by-uuid

and it will return something like this:

total 0
drwxr-xr-x 2 root root 100 Mai 19 18:22 .
drwxr-xr-x 6 root root 120 Jan  1  1970 ..
lrwxrwxrwx 1 root root  15 Mai 19 18:22 13d368bf-6dbf-4751-8ba1-88bed06bef77 -> ../../mmcblk0p2
lrwxrwxrwx 1 root root  15 Mai 19 18:22 15CD-3B79 -> ../../mmcblk0p1

Now attach the external USB drive and run the command again. You'll see, the result is different and there's a new device there.

total 0
drwxr-xr-x 2 root root 100 Mai 19 18:22 .
drwxr-xr-x 6 root root 120 Jan  1  1970 ..
lrwxrwxrwx 1 root root  15 Mai 19 18:22 13d368bf-6dbf-4751-8ba1-88bed06bef77 -> ../../mmcblk0p2
lrwxrwxrwx 1 root root  15 Mai 19 18:22 15CD-3B79 -> ../../mmcblk0p1
lrwxrwxrwx 1 root root  10 Mai 19 18:22 eac53de3-9f06-4e46-999c-684da279298b -> ../../sda1

This tells us two things. The new devices is /dev/sda1 and it's uuid is eac53de3-9f06-4e46-999c-684da279298b. When you attach multiple dirves then the sda1 can change. So for mounting purposes later on, we'll just use it's UUID which won't change as long as the partitions aren't altered or the partition is being formatted - however, we're about to format the partition to a suitable filesystem.

Before we can use it, we'll have to format this drive. I prefer ext4 but some people might prefer btrfs for it's snapshot and integrity checks. In order to format it as ext4 just run this command:

sudo mkfs.ext4 /dev/sda1

Warning: Be sure to use the proper device label otherwise you might destroy data on a different device.

As said, formatting causes to change the UUID as well, so you need to issue again the aforementioned command and take note of the new UUID.

15. Mount the external USB drive

Next thing is that we have to mount it. Here you must decide where you want to mount it. I opted to mount the drive in the backup user's home directory. I could have mounted it as /home also if I wanted. However if I have multiple backups to do I like to make them onto individual drives. So one user = 1 drive and the drive is mounted in the user's home directory. On the Rasperry Pi you can directly attach 4 USB devices, so it's easy to expand to another user if needed. Before I mount it, I add according backup user - in this howto I call that user bu. In order to create that user, run the following command:

sudo adduser bu

You will be prompted again twice to provide a password for that user.

Once the user is added, you can mount the external drive easily there with the following command:

sudo mount /dev/sda1 /home/bu

However before we can use it, one last step needs to be taken. You need to change the ownership of the mounted folder now also to the bu user:

sudo chown bu:bu /home/bu

So, we have now mounted the external USB drive and set according permissions. If you run now the following command you'll see, that /dev/sda1 is mounted to /home/bu

df -h
Filesystem      Size  Used Avail Use% Mounted on
rootfs           15G  2.4G   12G  18% /
/dev/root        15G  2.4G   12G  18% /
devtmpfs        484M     0  484M   0% /dev
tmpfs            98M  236K   98M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           195M     0  195M   0% /run/shm
/dev/mmcblk0p1   56M   19M   37M  34% /boot
/dev/sda1       2.7T  260M  2.6T   1% /home/bu

Since I already have some test data on the external USB drive it shows that I have already used 260MB. On a fresh drive it should be zero.

16. Mount external USB drive at boot up

All seems find but after a reboot, the external USB drive isn't mounted anymore. Usually you would just add an entry to /etc/fstab but there's an issue with booting to quickly and USB detection being too slow. The solution is rather easy.

Edit: /boot/cmdline.txt

and you'll see that there is a line containing:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

Just add rootdelay=10 to it so that it looks now:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait rootdelay=10

Next edit /etc/fstab

and add this to the end of that file

UUID=eac53de3-9f06-4e46-999c-684da279298b       /home/bu        ext4    defaults        0       2

Of course use your own UUID instead of the one given in the example above.

So now we have ensured that the external USB drives mounts in /home/bu even after a reboot. If you attach more than one usb device, which I have never tested, and you notice that I doesn't properly add all of them, then maybe extend rootdealy to more than 10.

17. Configure Samba

Next we'll configure samba so that it will make all backups available on the network. Samba is a daemon that acts provides network shares that can also be accessed through Windows using the smb protocoll.

Simply edit /etc/samba/smb.conf and replace the context of the config file with this:

[global]

   workgroup = WORKGROUP
   server string = %h server
;   wins support = no
;   wins server = w.x.y.z
   dns proxy = no
;   name resolve order = lmhosts host wins bcast
   name resolve order = bcast lmhosts host wins

    socket options = TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE

;   interfaces = 127.0.0.0/8 eth0
;   bind interfaces

   hosts allow = 127.0.0.1, 10.0.0.0/24
   hosts deny = 0.0.0.0/0

   log file = /var/log/samba/log.%m
   max log size = 1000
#   syslog
   syslog = 0
   panic action = /usr/share/samba/panic-action %d

   security = user
   encrypt passwords = true
   map to guest = bad user
   guest account = bu

#   valid users = root

#======================= Share Definitions =======================

[Backup]
        comment = Backup Share
        path = /home/bu
        read
        guest
        guest ok = yes
        hosts allow = 127.0.0.1, 10.0.0.0/24
        force user = bu
        force group = bu
        hosts deny = 0.0.0.0/0

To ensure that nothing is leaked outside the lan I set in the global section to deny every ip address and only allow localhost as well as the lan. I use 10.0.0.x for my lan. Likely you use 192.168.0.0, so change this accordingly.

Also in the global section you see that the guest account is the bu user and in the actual share you can see that guests have access and that it's read only access.

Save and exit the file and restart samba:

sudo /etc/init.d/samba restart

With this, we're no done configuring the services.

18. Backup Control File on the Raspberry Pi

Create and edit the /home/bu/backups.sh and fill it with the following content:

#!/usr/bin/env bash

basePath="/home/bu"

action="${1}"

function checkMonth ()
{
        now=$(date +"%Y-%m")
        last=$(<checkMonth.txt)
        if [[ ${now} != ${last} ]]
        then
                # New Month
                mkdir -p "${basePath}/current/"
                rm -Rf "${basePath}/current/"*
                echo "${now}" > "checkMonth.txt"
        fi
}



function makeHardlink ()
{
        # Make hardlink copy
        now=$(date +"%Y-%m-%d_%H-%M")
        mkdir -p "${basePath}/old/${now}"
        cp -al "${basePath}/current"* "${basePath}/old/${now}"
}



function checkFree ()
{
        # Check if old files need to be deleted
        freeSpace=$( df -P | grep "${basePath}" | awk '{print $4}' )
        curUse=$( cd "${basePath}/current" | du -s | awk '{print $1}' )
        estUse=$(( curUse * 2 ))

        echo "${freeSpace} - ${curUse} - ${estUse}"

        while [[ ${freeSpace} -le ${estUse} ]]
        do
                echo "Not enough space... removing old backups..."
                IFS= read -r -d $'\0' line < <(find "${basePath}/old" -type d -maxdepth 1 -printf '%T@ %p\0' 2>/dev/null | sort -z -n)
                oldDir="${line#* }"
                rm -Rf "${oldDir}"
                freeSpace=$( df -P | grep "${basePath}" | awk '{print $4}' )
                echo "${freeSpace} - ${curUse} - ${estUse}"
        done
}



case ${action} in

        newMonth)
                        checkMonth
                        ;;
        hardLink)
                        makeHardlink
                        checkFree
                        ;;
esac

This script has two purposes. It should be run before and after each backup.

The checkMonth function will see if there is a new month since the last backup. As you know, harddisk can become corrupt or rather some parts of it may fail. If that happens, you can't access the data files in the corrupted sectors anymore. However, creating a full backup everytim requires a lot of diskspace. To save disk space, I hardlink backups, meaning I only write the file system "index" files a new that point to the same data. So if the data sector gets corrupted, the file can't be retrieved anymore for all the hardlinked file as they all point to the same data. In order to minimize that risk, I ensure that every month a complete new backup set is written. This will eat in your storage space. E.g. if you have 400 GB data, that means in month 1 it will use 400 GB + altered files. In month 2 it will use another 400 GB + altered files etc.

This also means that the first sync and the first sync in a new month will take a long time. All others are quick.

The makeHardlink function will actually create the hardlink copy of the last backup. A hardlink copy requires almost no space and on a backup, only new files are written afresh. Also in combination with the hardlink copy I run the