This guide will cover how to leverage a Raspberry Pi and a Linux software RAID 5 to perform automatic Time Machine backups for your Mac over the network. While creating a Time Machine backup with a Raspberry Pi has been covered before, I put my own spin on this as I had some old drives laying around from when I upgraded my Plex server and wanted a reference for setting up a Linux software RAID using mdadm.
The transition to working from home full time has forced a lot of us to re-evaluate our normal workflow. As my laptop now spends nearly 100% of its time plugged in and sitting on the desk, I decided to minimize the number of peripherals that need to be plugged into it. Specifically, I no longer need to carry around a back-up hard drive and I did not want it sitting on my desk 24/7.
This can be done using any model of Raspberry PI however I strongly recommend using a Raspberry Pi 4 to take advantage of its support for full gigabit ethernet and USB 3.0. Backups can take a prolonged period of time and we want to maximize our throughput.
Hardware needed:
- Raspberry Pi 4 (Any model)
- Raspberry Pi POE Hat
- At least 3 hard drives (All the same size, I used 5)
- USB3 External Hard Drive Bay (I used this one: https://www.amazon.com/dp/B071ZP2HFK/ref=cm_sw_em_r_mt_dp_714FM08EXEHBVJ0CNM3B?_encoding=UTF8&psc=1)
Raid Configuration:
Begin with updating your Pi and installing mdadm.
pi@raspberrypi:~ $ sudo apt update && apt upgrade -y pi@raspberrypi:~ $ sudo apt install mdadm -y
Add your drives into the drive bays and plug the enclosure into the Pi. SSH to it remotely or open a terminal locally. Once plugged in, list out the available drives using lsblk. Note that the drives will appear as /dev/sdx and differ from the SD card at /dev/mmcblk0.
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 1.8T 0 disk sdb 8:16 0 1.8T 0 disk sdc 8:32 0 1.8T 0 disk sdd 8:48 0 1.8T 0 disk sde 8:64 0 1.8T 0 disk mmcblk0 179:0 0 28.8G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 28.5G 0 part /
With the five available 2TB drives (reported as 1.8T by the OS), we will create the array in a RAID 5 configuration using mdadm.
pi@raspberrypi:~ $ sudo mdadm --create --verbose /dev/md0 --level=5 --raid-devices=5 /dev/sda /dev/sdb /dev/sdc /dev/sdd /dev/sde
The RAID array will start the build process and can be viewed with cat /proc/mdstat.
pi@raspberrypi:~ $ cat /proc/mdstat Personalities : [raid6] [raid5] [raid4] md0 : active raid5 sde1[5] sdc1[2] sda1[0] sdd1[3] sdb1[1] 7813525504 blocks super 1.2 level 5, 512k chunk, algorithm 2 [5/5] [UUUUU] [=======>.............] recovery = 26.3% (1924851/104038498) finish=7.3min speed=200808K/sec unused devices: <none>
One nice perk of mdadm is that we can continue to interact with the RAID while it is building. Time Machine requires Apple’s proprietary Hierarchical File System (HFS) so we will need to install the required utilities on the Raspberry Pi for interoperability.
pi@raspberrypi:~ $ sudo apt install hfsutils hfsprogs netatalk -y
With HFS+ support installed, format the drive to HFS+ with mkfs in Linux.
pi@raspberrypi:~ $ sudo mkfs.hfsplus /dev/md0 -v timeCapsule
If we run lsblk again, we should see our five drives configured in a RAID.
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 1.8T 0 disk └─sda1 8:1 0 1.8T 0 part └─md0 9:127 0 7.3T 0 raid5 sdb 8:16 0 1.8T 0 disk └─sdb1 8:17 0 1.8T 0 part └─md0 9:127 0 7.3T 0 raid5 sdc 8:32 0 1.8T 0 disk └─sdc1 8:33 0 1.8T 0 part └─md0 9:127 0 7.3T 0 raid5 sdd 8:48 0 1.8T 0 disk └─sdd1 8:49 0 1.8T 0 part └─md0 9:127 0 7.3T 0 raid5 sde 8:64 0 1.8T 0 disk └─sde1 8:65 0 1.8T 0 part └─md0 9:127 0 7.3T 0 raid5 mmcblk0 179:0 0 28.8G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 28.5G 0 part /
Now we need to create the directory to mount our new RAID disk. Create it using the following command:
pi@raspberrypi:~ $ sudo mkdir /srv/TimeCapsule
Before mounting we need the UUID of the drive. Take note of the entry that points to ../../md0 as we will need to add this to /etc/fstab:
pi@raspberrypi:~ $ ls -alh /dev/disk/by-uuid/ total 0 drwxr-xr-x 2 root root 100 Apr 13 01:08 . drwxr-xr-x 7 root root 140 Apr 13 01:08 .. lrwxrwxrwx 1 root root 15 Mar 4 23:04 7581-8A48 -> ../../mmcblk0p1 lrwxrwxrwx 1 root root 9 Apr 13 01:08 e89b1b71-39e3-3632-b4cb-3eed298133e6 -> ../../md0 lrwxrwxrwx 1 root root 15 Mar 4 23:04 fa37d505-e741-4d35-bcec-4580aef395e1 -> ../../mmcblk0p2
Open up /etc/fstab with a text editor and add a line to automatically mount the drive to /srv/TimeCapsule on boot or reboot:
proc /proc proc defaults 0 0 PARTUUID=83c4223d-01 /boot vfat defaults 0 2 PARTUUID=83c4223d-02 / ext4 defaults,noatime 0 1 UUID=e89b1b71-39e3-3632-b4cb-3eed298133e6 /srv/TimeCapsule hfsplus force,rw,user,noauto 0 0 # a swapfile is not a swap partition, no line here # use dphys-swapfile swap[on|off] for that
Mount the RAID disk at the directory:
pi@raspberrypi:~ $ sudo mount /srv/TimeCapsule/
If no output returns, the mount is successful. You can validate it by running lsblk to verify that md0 has a mount point set to /srv/TimeCapsule:
pi@raspberrypi:~ $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 1.8T 0 disk └─sda1 8:1 0 1.8T 0 part └─md127 9:127 0 7.3T 0 raid5 /srv/TimeCapsule sdb 8:16 0 1.8T 0 disk └─sdb1 8:17 0 1.8T 0 part └─md127 9:127 0 7.3T 0 raid5 /srv/TimeCapsule sdc 8:32 0 1.8T 0 disk └─sdc1 8:33 0 1.8T 0 part └─md127 9:127 0 7.3T 0 raid5 /srv/TimeCapsule sdd 8:48 0 1.8T 0 disk └─sdd1 8:49 0 1.8T 0 part └─md127 9:127 0 7.3T 0 raid5 /srv/TimeCapsule sde 8:64 0 1.8T 0 disk └─sde1 8:65 0 1.8T 0 part └─md127 9:127 0 7.3T 0 raid5 /srv/TimeCapsule mmcblk0 179:0 0 28.8G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 28.5G 0 part /
With the drive mounted, configure permissions so that we can write to it without requiring root privileges:
pi@raspberrypi:~ $ sudo chown pi:pi /srv/TimeCapsule
Time Machine Configuration:
Configure /etc/nsswitch.conf and add mdns mdns4 to the end of the hosts: line:
pi@raspberrypi:~ $ sudo vim /etc/nsswitch.conf # /etc/nsswitch.conf # # Example configuration of GNU Name Service Switch functionality. # If you have the `glibc-doc-reference' and `info' packages installed, try: # `info libc "Name Service Switch"' for information about this file. passwd: files group: files shadow: files gshadow: files hosts: files mdns4_minimal [NOTFOUND=return] dns mdns mdns4 networks: files protocols: db files services: db files ethers: db files rpc: db files netgroup: nis
Finally, configure Netatalk to mimic Apple’s Time Capsule in /etc/netatalk/afp.conf. Add the mimic model in the [Global] block and the path to our mounted Time Capsule volume in the [My Time Machine Volume] block. Be sure to remove the semi-colon characters in the [My Time Machine Volume] block as well.
pi@raspberrypi:~ $ sudo vim /etc/netatalk/afp.conf ; ; Netatalk 3.x configuration file ; [Global] ; Global server settings mimic model = TimeCapsule6,106 ; [Homes] ; basedir regex = /xxxx ; [My AFP Volume] ; path = /path/to/volume [My Time Machine Volume] path = /srv/TimeCapsule time machine = yes
Finally, start up the two configured services to broadcast the drive as a Time Capsule and then enable them to start automatically at boot.
pi@raspberrypi:~ $ sudo systemctl start avahi-daemon.service pi@raspberrypi:~ $ sudo systemctl start netatalk.service pi@raspberrypi:~ $ sudo systemctl enable avahi-daemon.service Synchronizing state of avahi-daemon.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable avahi-daemon pi@raspberrypi:~ $ sudo systemctl enable netatalk.service Synchronizing state of netatalk.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable netatalk
Note: Occasionally the HFS+ volume will be mounted in read-only mode if the Raspberry Pi restarts. The best explanation I have been able to find is that this is due to journaling with HFS+. I haven’t been able to find solid support for HFS+ journaling on Linux so the best way to fix this is to unmount and then remount the drive in the following way.
pi@raspberrypi:~ $ sudo systemctl stop avahi-daemon.service pi@raspberrypi:~ $ sudo systemctl stop netatalk.service pi@raspberrypi:~ $ sudo umount /srv/TimeCapsule pi@raspberrypi:~ $ sudo mount -t hfsplus -o force,rw /srv/TimeCapsule pi@raspberrypi:~ $ sudo systemctl start avahi-daemon.service pi@raspberrypi:~ $ sudo systemctl start netatalk.service
Pivot back to your Mac host and you should be able to directly connect to the Raspberry Pi using the same credentials via the GUI by navigating to Finder > Go > Connect to server…
Once connected, open up Time Machine Preferences, click “Select Disk” and choose your newly created Time Machine volume. For transparency, the screenshot shows my other time machine volume next to the newly created one.
That’s it! You should be up and running now and you can forget about every having to plug a backup drive into your computer again.
Final Thoughts:
This solution works pretty well for me and has been running stable for the last year. In the future, I may add some more granular permissions for each user that will be backing up to this rather than have a single account for everyone to use to connect to the Pi. Additionally, I am interested to hear if anyone has a better solution than un-mounting and re-mounting the volume and restarting the services when it becomes read-only. I’ve tried the cronjob solution without any luck.
References:
- I pulled heavily from Gregology initially but his fixes for the drive becoming read-only did not work for me. https://gregology.net/2018/09/raspberry-pi-time-machine/
- The Linux Raid Wiki has a wealth of info about managing your software Raid. https://raid.wiki.kernel.org/index.php/Linux_Raid