Sign In

Sign in with your username and password to access your account.
Part 2 of 2

Tutorial: Setup your own Raspberry Pi NAS

This article is a guide on how to set up a simple network-attached storage (NAS) computer based on a Raspberry Pi and external hard drives connected via USB. To follow along basic understanding of how to install and use a Linux OS is required, but to get a setup like this working no crazy technical knowledge is needed. If you want to know why some possibly odd choices were made, check out the accompanying blog entry. 😊

Important: This tutorial contains lots of shell commands to make things easier. Don’t blindly copy them as they assume my setup and don't paste multiple commands as blobs at once!

👓The whole picture

The goal is to build a NAS with full redundancy and data encryption using a Pi that boots from a USB disk. To achieve redundancy I use two identical HHDs as storage which are combined to a single block device as RAID using mdadm . Reads and writes are cached with bcache which will use a separate partition on the boot SSD to keep recently accessed data. Finally ecryptfs is used to encrypt all stored files and file names.

🚀Installing the OS

Download the 64bit image of Ubuntu Server for Raspberry Pi from here and burn it to an SD-Card. Boot up the Pi and install the software tools for the Pi with the following command:

sudo apt install libraspberrypi-bin

Now add program_usb_boot_mode=1 to the /boot/config.txt file in a new line. Reboot the Pi with sudo reboot , don’t just pull the power plug! To check whether the firmware is now able to boot from USB devices run vcgencmd otp_dump and look if you can spot the line 17::3020000a .

Now clone both partitions on the SD-Card onto your USB boot device. As we’ll be using the boot device as read-cache too, we need to make space for a third partition. The easiest way to do this is to use Gparted on a Linux desktop machine.

If you only have a Windows computer you can install Win32DiskImager to clone the SD-Card and follow the next few steps: You can check now if booting from USB works, by only connecting the USB drive to the Pi. (As written in my blog entry I ended up still needing the SD-Card later though.) Then boot the Pi from the SD-Card and connect the USB drive. Use lsblk to list all block devices. There should be an unmounted /dev/sdX with the same size as your USB drive, where X is a lowercase letter, probably “a”. This “block device” is the representation of the hard drive in software. Shrink the filesystem of the “writable” partition (not the “boot” partition) on the USB drive to the appropriate size with resize2fs and then shrink the partition using cfdisk . My drive is 256GB large and I will leave 100GB for Ubuntu and use the rest as cache.

sudo resize2fs /dev/sda 100G
sudo cfdisk /dev/sda

Just create a simple primary Linux partition filling the remaining free space on the disk using all default options in cfdisk or Gparted. Remember that you have to write out the changes to the disk before quitting, or nothing will be changed. You can use e2fsch to check and repair the integrity of the resized filesystem. Here you have to provide the name of the partition, which will be the name of the device with a single digit number as seen in lsblk .

If you want the handy raspi-config tool, you need to install it by downloading it as a package and install it manually. Go to the archive page and copy the link to the most recent version. As of writing, this is raspi-config_20210604_all.deb . Download it with wget to /temp and install its dependencies, then the package itself.

wget https://archive.raspberrypi.org/debian/pool/main/r/raspi-config/raspi-config_20210604_all.deb -P /tmp
sudo apt-get install libnewt0.52 whiptail parted triggerhappy lua5.1 alsa-utils -y
sudo apt-get install -fy
sudo dpkg -i /tmp/raspi-config_20210604_all.deb

Now you can run sudo raspi-config to get the interactive configuration tool.

📡Connecting to Wifi

I personally only set up wifi for some early experiments. I would recommend a wired connection for your NAS to your switch or router. First, get the name of your wifi network interface by running ls /sys/class/net . It is probably called wlan0 . Then edit the file /etc/netplan/50-cloud-init.yaml with root privileges and add a wifis section.

             dhcp4: true
             optional: true
     version: 2
             optional: true
                 "My Wifi SSID":
                     password: "My Wifi password"
             dhcp4: true

Replace “MyNetworkInterface”, “My Wifi SSID” and “My Wifi password” with your information and do a reboot.

🔗Setting up RAID

First both drives need to be formatted. Assuming they are called sdb and sdc , just run the commands below. Now run cfdisk for each drive and create a primary partition of type “Linux Raid” which fills all available space.

sudo parted /dev/sdb mklabel gpt
sudo parted /dev/sdc mklabel gpt
sudo cfdisk /dev/sdb
sudo cfdisk /dev/sdc

Both drives are now prepared to be combined into a single logical one using RAID. Install mdadm and run it to create a new RAID block device from the first (and only) partition on each of the two drives. Executing with --examine shows the health of your RAID. Immediately after creation mdadm will start syncing both drives block by block. Depending on the drive's size this can take a long time. You can check the process by looking at the contents of /proc/mdstat . It took my setup more than two days, but luckily this background process is paused and resumed automatically whenever you use the RAID. Therefore you can proceed with the next steps without having to wait for it to finish.

sudo apt-get install mdadm
sudo mdadm --verbose --create /dev/md0 --level=raid1 --raid-devices=2 /dev/sd[bc]1
sudo mdadm --examine /dev/sdb1 /dev/sdc1
cat /proc/mdstat

⏱Enabling caching

Caching will be handled by bcache . It will combine the RAID disk md0 and the third partition on the boot disk into a single cached (again logical) block device. The process is very simple: First create the cache disk, format it with a filesystem and make it mount on startup. The mountpoint will be a directory inside of the ubuntu user's home.

sudo make-bcache -B /dev/md127 -C /dev/sda3
cat /sys/block/bcache0/bcache/state
sudo mkfs.ext4 /dev/bcache0
mkdir ~/nas
mkdir ~/nas/nasdrive-mnt
sudo e2label /dev/bcache0 cached-nasdrive

Directly after creating the cached block device it should show up as /dev/bcache0 and /sys/block/bcache0/bcache/state should contain “clean”. If everything is good, prepare the mountpoint and label the drive. I just named it “cached-nasdrive”. We don’t need to label the physical drives or the RAID device as the system will never have to mount them automatically.

Add the following line at the end of /etc/fstab to mount the cached block device as a filesystem in our prepared directory on startup.

LABEL=cached-nasdrive   /home/ubuntu/nas/nasdrive-mnt   ext4   defaults        0       2

Now you can run mount -a to test if the entry works without issues. The folder nasdrive-mnt should now be a portal to the cached RAID. This can be checked using mountpoint , also you should see a folder called “lost+found” indicating that this is the base of an ext4 filesystem.

sudo mount -a
mountpoint ~/nas/nasdrive-mnt

🔐Encrypting your data

To encrypt the data stored on the NAS I used ecryptfs which handles directory level encryption on a user by user basis. As ecryptfs seems to be very inflexible about its directory structure an additional user is needed, whose home directory will be mounted on the “cached-nasdrive”. To allow for multiple network shares with different encryption keys making them completely separate from each other, several such users can be created repeating the steps below. If you don’t need such high security you can stick to a single encryption user and let SAMBA handle the access control.

The user is called “nasuser” and needs a secure password, as it will be used to safely store the encryption key. After installing the required tools log in as the newly created user and run the interactive setup program. Do as the program instructs you and print the encryption key to screen and create a secure copy! This will be needed if you ever have to recover your data on a different machine. You should see that a Private and two hidden folders have appeared in the home directory. Finally, remove the file auto-unmount to allow access through SAMBA.

sudo adduser nasuser
sudo apt-get install ecryptfs-utils
su nasuser
ecryptfs-unwrap-passphrase .ecryptfs/wrapped-passphrase
rm ~/.ecryptfs/auto-umount

After logging in and out the Private folder should now be a mountpoint. When creating a file inside of it, another one should appear in the hidden .Private directory with an illegible name. Now that this is all set up logout back to the ubuntu user to move all of the nasuser’s files to the hard drives.

Create a directory for the nasuser’s home folder and then copy all of its files there.

mkdir ~/nas/nasdrive-mnt/nasdrive-home
sudo cp -pvau /home/nasuser/ /home/ubuntu/nas/nasdrive-mnt/nasdrive-home

Now we only need to mount this new folder with all the files copied to it as a replacement for the current home directory. To make a portal from one directory to another one a bind mount can be used. The fstab entry looks like this:

/home/ubuntu/nas/nasdrive-mnt/nasdrive-home/nasuser /home/nasuser none defaults,bind 0 0

After running mount -a the home directory /home/nasuser should look unchanged but be a mountpoint.

📂Creating a network share

If you only want to connect from a Linux system as a client you probably can stop now as adding an SFTP connection as a network share is pretty straightforward. Else you can install SAMBA to be able to connect to your NAS from multiple devices on different platforms.

Add a SAMBA password for the nasuser by running sudo smbpasswd -a nasuser . Then edit /etc/samba/smb.conf and add the following block of text in the section for network shares.

     comment = Nasuser Folder
     path = /home/nasuser/Private
     valid users = nasuser
     read list = nasuser
     write list = nasuser
     force directory mode = 0755
     create mask = 0755
     force create mode = 0755
     directory mask = 0755
     inherit permissions = yes
     store dos attributes = no
     public = yes
     ea support = no
     inherit acls = yes
     browseable = yes
     writeable = yes
     printable = no

Finally, restart the SAMBA service using sudo systemctl restart smbd.service . You should be able to connect to your NAS via its local IP from your Windows or Linux machine, phone, or iPad.

Part 1
last edited 8th Sep 21