Raspberry Pi RAID File Server
A little recipe to build a networked RAID storage array that is shared via Apple File Sharing using a Raspberry Pi and some old USB hard disks.
Starting Point
Install a clean Raspberry Pi. This article is based on it being Raspbian Stretch Lite.
Be sure to update Raspbian to the latest version:
$ sudo apt-get update && apt-get dist-upgrade
Add some needed packages:
$ sudo apt-get install screen $ sudo apt-get install mdadm
screen
: I tend to SSH into the box and leave commands that need a long time run in the background while I disconnect (C-d
to detach and later screen -r
to resume)
mdadm
: the package used to manage RAID volumes
Prepare the First Disk
Find the USB drive with dmesg
:
$ dmesg [ 1389.493714] usb 1-1.3: new high-speed USB device number 5 using dwc_otg [ 1389.625266] usb 1-1.3: New USB device found, idVendor=059f, idProduct=0651 [ 1389.625297] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 1389.625310] usb 1-1.3: Product: LaCie Hard Drive USB [ 1389.625321] usb 1-1.3: Manufacturer: LaCie [ 1389.625330] usb 1-1.3: SerialNumber: 10000E0003C3AC29 [ 1389.632736] usb-storage 1-1.3:1.0: USB Mass Storage device detected [ 1389.653577] usb-storage 1-1.3:1.0: Quirks match for vid 059f pid 0651: 200 [ 1389.654822] scsi host0: usb-storage 1-1.3:1.0 [ 1390.685192] scsi 0:0:0:0: Direct-Access WDC WD1600BB-55GUC0 08.0 PQ: 0 ANSI: 2 [ 1390.687446] sd 0:0:0:0: [sda] 312581808 512-byte logical blocks: (160 GB/149 GiB) [ 1390.687476] sd 0:0:0:0: [sda] Assuming Write Enabled [ 1390.687492] sd 0:0:0:0: [sda] Assuming drive cache: write through [ 1390.773317] sd 0:0:0:0: Attached scsi generic sg0 type 0 [ 1390.806677] sda: sda1 sda2 [ 1390.810289] sd 0:0:0:0: [sda] Attached SCSI disk
Use lsblk
to see what is available:
$ lsblk -l NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 149,1G 0 disk sda1 8:1 0 200M 0 part sda2 8:2 0 148,7G 0 part mmcblk0 179:0 0 3,7G 0 disk mmcblk0p1 179:1 0 41,5M 0 part /boot mmcblk0p2 179:2 0 3,7G 0 part /
-l
: to print a white space list
Use dd
to wipe the current partition table:
$ sudo dd if=/dev/zero of=/dev/sda bs=512 count=1 1+0 Datensätze ein 1+0 Datensätze aus 512 Bytes kopiert, 0,0185235 s, 27,6 kB/s
Use fdisk
to create a new partition:
$ sudo fdisk /dev/sda Command (m for help): g Created a new GPT disklabel (GUID: 0C5D8867-F662-4156-B385-039E6F0DF2EA). Command (m for help): n Partition number (1-128, default 1): 1 First sector (2048-312581774, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-312581774, default 312581774): Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks.
Use lsblk
to check there is now one partition available:
$ lsblk -l NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 149,1G 0 disk sda1 8:1 0 149,1G 0 part mmcblk0 179:0 0 3,7G 0 disk mmcblk0p1 179:1 0 41,5M 0 part /boot mmcblk0p2 179:2 0 3,7G 0 part /
Format the drive with mkfs.ext4
:
$ sudo mkfs.ext4 -c -L "LaCie 160GB HDD" /dev/sda1
-c
: check for bad blocks
-L
: set the partition label
This will take a while because we are checking for bad blocks with mkfs.ext4
.
Prepare the Second Disk
Find the USB drive with dmesg
:
$ dmesg [ 2964.665263] usb 1-1.2: new high-speed USB device number 6 using dwc_otg [ 2964.797810] usb 1-1.2: New USB device found, idVendor=059b, idProduct=0370 [ 2964.797840] usb 1-1.2: New USB device strings: Mfr=10, Product=11, SerialNumber=5 [ 2964.797853] usb 1-1.2: Product: External HD [ 2964.797863] usb 1-1.2: Manufacturer: Iomega [ 2964.797872] usb 1-1.2: SerialNumber: 995EFFFFFFFF [ 2964.816603] usb-storage 1-1.2:1.0: USB Mass Storage device detected [ 2964.827924] scsi host1: usb-storage 1-1.2:1.0 [ 2965.857226] scsi 1:0:0:0: Direct-Access ST350082 0AS PQ: 0 ANSI: 2 CCS [ 2965.862824] sd 1:0:0:0: [sdb] 976773168 512-byte logical blocks: (500 GB/466 GiB) [ 2965.863902] sd 1:0:0:0: [sdb] Write Protect is off [ 2965.863933] sd 1:0:0:0: [sdb] Mode Sense: 34 00 00 00 [ 2965.864953] sd 1:0:0:0: [sdb] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA [ 2965.885140] sd 1:0:0:0: Attached scsi generic sg1 type 0 [ 2966.010811] sdb: sdb1 sdb2 [ 2966.034340] sd 1:0:0:0: [sdb] Attached SCSI disk
Use lsblk
to see what is available:
$ lsblk -l NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 149,1G 0 disk sda1 8:1 0 149,1G 0 part sdb 8:16 0 465,8G 0 disk sdb1 8:17 0 200M 0 part sdb2 8:18 0 465,5G 0 part mmcblk0 179:0 0 3,7G 0 disk mmcblk0p1 179:1 0 41,5M 0 part /boot mmcblk0p2 179:2 0 3,7G 0 part /
-l
: to print a white space list
Use dd
to wipe the current partition table:
$ sudo dd if=/dev/zero of=/dev/sdb bs=512 count=1 1+0 Datensätze ein 1+0 Datensätze aus 512 Bytes kopiert, 0,0421397 s, 12,2 kB/s
Use fdisk
to create a new partition:
$ sudo fdisk /dev/sdb Command (m for help): g Created a new GPT disklabel (GUID: 5B0986EA-8135-4C07-9A82-65F79831AA8A). Command (m for help): n Partition number (1-128, default 1): 1 First sector (2048-976773134, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-312581774, default 312581774): +150G Created a new partition 1 of type 'Linux filesystem' and of size 150 GiB. Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks.
Use lsblk
to check there is now one partition available:
$ lsblk -l NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 149,1G 0 disk sda1 8:1 0 149,1G 0 part sdb 8:16 0 465,8G 0 disk sdb1 8:17 0 150G 0 part mmcblk0 179:0 0 3,7G 0 disk mmcblk0p1 179:1 0 41,5M 0 part /boot mmcblk0p2 179:2 0 3,7G 0 part /
-l
: to print a white space list
Format the drive with mkfs.ext4
:
$ sudo mkfs.ext4 -c -L "LaCie 500GB HDD" /dev/sdb1 mke2fs 1.43.4 (31-Jan-2017) Ein Dateisystems mit 39321600 (4k) Blöcken und 9830400 Inodes wird erzeugt. UUID des Dateisystems: c1c86603-bcaa-4019-b570-3de66c7a4eeb Superblock-Sicherungskopien gespeichert in den Blöcken: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872 Es wird nach defekten Blöcken gesucht (Nur-Lesen-Modus):erledigt beim Anfordern von Speicher für die Gruppentabellen: erledigt Inode-Tabellen werden geschrieben: erledigt Das Journal (262144 Blöcke) wird angelegt: erledigt Die Superblöcke und die Informationen über die Dateisystemnutzung werden geschrieben: erledigt
-c
: check for bad blocks
-L
: set the partition label
Create the RAID Array
$ sudo mdadm --create --verbose /dev/md0 --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1 mdadm: /dev/sda1 appears to contain an ext2fs file system size=157286400K mtime=Thu Jan 1 01:00:00 1970 mdadm: Note: this array has metadata at the start and may not be suitable as a boot device. If you plan to store '/boot' on this device please ensure that your boot-loader understands md/v1.x metadata, or use --metadata=0.90 mdadm: /dev/sdb1 appears to contain an ext2fs file system size=156289860K mtime=Thu Jan 1 01:00:00 1970 mdadm: size set to 156158784K mdadm: automatically enabling write-intent bitmap on large array Continue creating array? y mdadm: Defaulting to version 1.2 metadata mdadm: array /dev/md0 started.
--verbose
: ensures that all mdadm information will be presented during the process
--level=1
: refers to the RAID level being created
Wait for the RAID array to finish assembling (this may take some time). You can check the progress periodically using the command reading /proc/mdstat
:
$ cat /proc/mdstat
You’d get this:
Personalities : [raid1] md0 : active raid1 sdb1[0] sda1[1] 156158784 blocks super 1.2 [2/2] [UU] [=====>...............] resync = 25.4% (39666240/156158784) finish=122.9min speed=15795K/sec bitmap: 2/2 pages [8KB], 65536KB chunk unused devices:
If you check, and it says “PENDING”
$ cat /proc/mdstat Personalities : [raid1] md0 : active (auto-read-only) raid1 sdb1[0] sda1[1] 156158784 blocks super 1.2 [2/2] [UU] resync=PENDING unused devices:
Then you can trigger the sync to continue with:
$ mdadm --readwrite /dev/md0
When it’s done, you’ll see:
$ cat /proc/mdstat Personalities : [raid1] md0 : active raid1 sdb1[0] sda1[1] 156158784 blocks super 1.2 [2/2] [UU] bitmap: 0/2 pages [0KB], 65536KB chunk unused devices:
Now add the array configuration to /etc/mdadm/mdadm.conf
. Edit the file and add:
DEVICE /dev/sda1 /dev/sdb1 ARRAY /dev/md0 devices=/dev/sda1,/dev/sdb1
The array should come up ready, but you can assemble the RAID disks together:
$ sudo mdadm --assemble /dev/md0 /dev/sda1 /dev/sdb1
Check to make sure that everything looks good with the new RAID device:
$ sudo mdadm --detail /dev/md0
Format the new RAID device:
$ sudo mkfs.ext4 -L "150 GB USB RAID" /dev/md0 mke2fs 1.43.4 (31-Jan-2017) Ein Dateisystems mit 39039696 (4k) Blöcken und 9764864 Inodes wird erzeugt. UUID des Dateisystems: 149a2788-7f1c-4904-ace4-cb37a3e20e7a Superblock-Sicherungskopien gespeichert in den Blöcken: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872 beim Anfordern von Speicher für die Gruppentabellen: erledigt Inode-Tabellen werden geschrieben: erledigt Das Journal (262144 Blöcke) wird angelegt: erledigt Die Superblöcke und die Informationen über die Dateisystemnutzung werden geschrieben: erledigt
Create a directory for the mount point where ever you like for your RAID device:
$ sudo mkdir /media/150_GB_USB_RAID
Find the UUID for your RAID array device:
$ lsblk --fs | grep md0 └─md0 ext4 150 GB USB RAID 149a2788-7f1c-4904-ace4-cb37a3e20e7a └─md0 ext4 150 GB USB RAID 149a2788-7f1c-4904-ace4-cb37a3e20e7a
Add an entry to the end of /etc/fstab
to auto-mount the RAID array device at the UUID and mount point.
UUID=d409ca76-9eee-40ea-a306-4838a7b813c7 /media/150_GB_USB_RAID ext4 defaults 0 2
Test your set up by mounting the RAID array device:
$ sudo mount -a
Now the storage array is up and ready.
Configure File Sharing over Apple Filing Protocol
Create a directory where shared files will be:
$ sudo mkdir /media/150_GB_USB_RAID/shared $ sudo chmod 777 /media/150_GB_USB_RAID/shared
Install netatalk
which is the package that provides Apple Filing Protocol.
$ sudo apt-get install netatalk
Edit the netatalk configuration file /etc/netatalk/afpd.conf
:
$ sudo vi /etc/netatalk/afpd.conf
On the last line remove the #
and remove uams_dhx.so,
to set the last line to:
- -tcp -noddp -uamlist uams_dhx2.so
-
apply these settings as the default
-tcp
listen on tcp
-noddp
do not listen on DDP/AppleTalk
-uamlist uams_dhx2.so
use Diffie-Hellman eXchange 2 as authentication method
Edit the netatalk configuration file /etc/netatalk/AppleVolumes.default
to define shares:
$ sudo vi /etc/netatalk/AppleVolumes.default
Remove the home directory being shared by default by adding a #
:
# ~/ "Home Directory"
Add a line to make the share available:
/media/150_GB_USB_RAID/shared "Mirrored File Share" allow:pi
Enable netatalk
at boot and (re)start it now:
$ sudo systemctl enable netatalk netatalk.service is not a native service, redirecting to systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable netatalk $ sudo systemctl restart netatalk
Done!
Possibly Good to Know
You can stop an array if neededww.:
$ mdadm --stop /dev/md0
Start an existing array:
mdadm --assemble /dev/md0 /dev/sda1 /dev/sdb1