I had played around with the NAS feature of my router in the past, but quickly reached its limits. Since then, I was looking for a NAS solution for my whole family. Best to build it myself. I already had a few Raspberry Pis at home and when the PI 4B came out, this was the perfect moment to get this project started.
Around the same time, a power amp at my school broke. Since I am involved in sound engineering there, it was no problem to get hold of it. So, I had a case in which all components would fit.
This project is divided into two parts:In part 1 we take care of the hardware, i.e. the cabling of the individual devices and especially also the installation in the power amp case.
In part 2 we will install the operating system and set up the NAS.
If you are only interested in the software part and setting up the NAS with Ubuntu Server, you can jump straight to the second part.
The complete project and associated code can be found on GitHub (https://github.com/JJandke/RaspberryPiNas).
Attention! Working on mains voltage is life threatening and should only be done by qualified personnel. Some steps shown here should only be done if you know exactly what you are doing. Furthermore, a multiple socket, as shown here, should never be used for permanent installations.
- Raspberry Pi 4
- 8 GB DDR3 SDRAM
- Gigabit Ethernet
- 4 TB RAID 1 Storage
Note: For a pure Raspberry Pi 4 NAS without amp case, we only need those articles in bold.
- Raspberry Pi 4B (I recommend the 8GB RAM version, as it is not much more expensive compared to other NAS solutions)
- Power supply (PSU) for the Pi (5V, 3A, 45W, UBS-C, surge- and overload protection)
- Micro SD card (32GB)
- Active cooling case for the Pi
- USB 3 Hub (This turned out later)
- Active USB-SATA adapter
- Hard drives (4TB WD red)
- 24V Power supply for the case fans (24V, 4.5A)
- 2 relay module (to switch the two case fans and the fan on the Raspberry Pi)
- Ethernet feedthrough (To connect an Ethernet cable to the case, as it would be with a real server)
- Ethernet patch cable (20cm)
- Switch (250V, 10A, for the Case)
- Fuse (4.5A)
- MC 7805 (Fixed voltage regulator)
- Capacitors (2200µF, 10 µF, 100nF – more details later)
- Diode (1N4001)
- Jumper cables
After opening the 19" case, and removing the actual PCB, I was also able to unscrew the front panel and get access to the fans. Of course, these had to be cleaned first. I decided to further disassemble the front panel and spray paint it completely black. In order for the paint to hold better, I had to sand it down a bit.
Then I had to think about the actual allocation of the devices in the case. This was only possible to a limited extent before, because I didn’t have any specifications of the power supplies for the USB-SATA adapters. I had originally wanted to take a black multi-socket, but the plugs there were arranged at an 45° angle, so that the power supplies would then have been too high and would no longer have fit into the housing. Therefore, I had to search for a multi-socket with straight plugs.
Now that I knew what should go where, I could start attaching the parts. The Ethernet feed through I could simply attach to the place of a previous speakOn port, for this I only had to drill two holes for the screws. For the relay, the 24 V power supply and the Raspberry Pi, I marked the holes and punched them so I could drill them with a 2.5 and 3mm drill bit. I was able to immediately screw the 24V power supply to the bottom of the case. But since the relay module was not insulated at the bottom side of the PCB, I had to mount it on spacers and attach a small plastic sheet.
I had long been wondering how I would mount the Raspberry Pi. In the end the best solution was to mark the four holes of the base plate with a scriber on the bottom of the amp and then screw the Raspberry Pi case to the power amp case with longer screws. Since the fans were clean again in the meantime, I could screw them into the case as well.
In order not to damage the hard drives during assembling the NAS, I took two old ones to mark the proportions. Then the hard drives were fixed with metal brackets. To allow air to get under the hard drives and reduce vibrations at the same time, I packed rubber spacers between both, the metal brackets and the case bottom.
I decided to use the screw terminals on the 24V power supply to be able to connect the multisocket there. So I had to remove the plug, and strip the three stranded wires. I crimped ferrules onto the stripped ends and then screwed them (L2, N2, PE2) to the AC input side of the terminal block on the 24V power supply.
- From the incoming mains cable, I was able to connect the neutral conductor (N1) directly to the power supply, using a wire end ferrule.
- The phase (L1), I first connected to a 4.5A fuse. In my case, I was able to insulate the solder joints of the fuse holder well with heat shrink tubing and electrical tape.
- Then L1 was looped to the switch (250V, 10 A). There I used insulated cable lugs to be able to plug and unplug the switch easily. Next, the phase was pulled back to the power supply. Since I have an illuminated switch, I also had to connect the neutral (N3) to the switch.
- Because only two cable ends fit on the terminal strip of the 24V PSU, this neutral conductor (N3) had to be connected with a terminal plug.
- I also screwed the protective conductor (PE2) of the multiple socket to the terminal strip of the power supply.
- In order to be able to connect the protective conductor of the mains cable and the power supply (PE3) and the incoming cable (PE1) with the housing, I have sanded down an unpainted area again and screwed both protective conductors using a toothed ring.
After an isolation test, I was able to plug it in for the first test. Fortunately, nothing blew up in my face, nothing exploded, and everything behaved as it should... except the switch… Wiring this power switch was a bit difficult, as it had an LED that was supposed to indicate if the switch was set to on or off... but it was not quite clear in which positions what happened. So it took me a few tries before I knew the correct wiring, as the manufacturer did not include instructions.
Now that the AC part is done, I'll take care of the DC part.
This seems complicated because there are many cables, but it is relatively simple.
- To reduce a few cables and to be able to connect the fans well, I soldered a board to which I can plug both fans on one side and the 24V is connected on the other side. GND goes directly to the power supply and +24V are switched via relay 1. As it turned out later, the fans vibrated very strongly at 24V. At 20V, however, they ran quietly. Therefore I soldered a 85 Ohm power resistor in front of each fan. From the fan of the Raspberry Pi you can also plug GND directly to a GPIO. I connected the +5V with a jumper cable to relay 2 and led it back again, so I didn't have to cut and solder a cable. This would make the fan more replaceable.
- To switch the relay, we need to connect +5V (VCC) and GND (GND) from the Raspberry Pi as power supply to the relay module. We also need GPIO 04 (IN1) and GPIO 17 (IN2) to switch the relays. The jumper has to be set between VCC and RVCC. Now the relay would theoretically already work, but the Raspi would not be galvanically separated from the relay module.
- To achieve this by using the optocouplers on the PCB, the jumper must be removed and a voltage of +5V must be connected to RVCC and GND.
- Since I don't have a 5V voltage source in the case, I built myself a voltage converter with a fixed voltage regulator with the following schematic:
- On the in pin of the MC7805 +24V are applied. Also an electrolytic capacitor is connected between +24V and GND. The middle pin (GND) is also connected to GND and the Out pin is connected to RVCC on the relay board. Between the out pin and GND an electrolytic capacitor with 10µF and a ceramic capacitor with 100nF are connected. To protect the MC7805 from a too high voltage at the out pin, a 1N4001 diode is connected between In and Out. The capacitors smooth the voltage. The GND of the circuit is connected to GND on the relay board.
- Because 19V drops at the fixed voltage regulator, it can get very hot. Therefore I took an old heat sink, which was previously installed in the power amp, and attached the MC7805 to it. I used a fixed voltage regulator instead of a DC/DC converter, because I had one at home. In addition, the 5V are only needed for the switching operations of the relay. Therefore the heat sink is theoretically not necessary. But since I might need the 5V output for other stuff and it does look good, I decided to use it.
- Now all that's left to do is plug in the power supplies, connect the hard drives to the Pi, and create a connection with the 20cm patch cable between the Pi and the Ethernet feedthrough.
At this point it is important to add that it turned out later that you need an additional active USB hub between the Raspberry Pi and the active SATA USB adapters. When setting up the NAS, I struggled almost continuously with one of the disks being kicked out. sudo dmesg
always returned errors that looked like this: over current change #54
. There were other errors, but they were software related. After weeks of trying and researching I found someone with the same problem. His hard drives were also thrown out, although he also used active SATA USB adapters. Indeed. With an active USB hub I didn't get these error messages anymore. Interesting to know is that the active USB hub drew only 0.2A(DC) in IDLE and almost 1A(DC) in use. From this I conclude that the active adapters could not supply enough current. Now that the Raspberry Pi has been expanded with more USB3 ports, I'm also thinking of moving the operating system to an SSD, as these are more durable than SD cards.
Of course, good cable management is important, so that cables do not unplug themselves and that it is easier to upgrade later.
To stop dust that would be sucked in by the fans, I sandwiched a strip of filter floss for servers between the chassis and the fans.
After flashing the Micro SD card (See Part 2) I was able to insert it into the Raspberry Pi and then attach the black painted front panel as well as the lid.
About switching the fans: Since the fans do not support PWM out of the box, it would be an idea to control the fans with MosFets instead of just a relay, to control their speed proportional to the temperature.
Now we continue in part 2, since we have already done everything that has to do with hardware.
Part 2 - SoftwareInstall operating system- To get the operating system onto the SD card, we use the Pi imager.
- There we select Choose OS -> Other general purpose OS -> Ubuntu -> Ubuntu Server 20.XX.x LTS (RPi 3/4/400).
- And then choose your SD card.
- Then press "Write" The process took me about 6 minutes.
- After the SD card is in the Pi and it is turned on, it should appear on your router's user interface after a few seconds.
- At my Fritz!Box you can find the IP under Home Tetworks -> Mesh -> Other connected or registered home network devices.
- There you should give the device a static IP, so that you don't have any problems later when mounting e.g. in fstab.
- To get access to the Raspberry Pi via SSH, we open a terminal on the PC and type:
ssh ubuntu@ubuntu
orssh ubuntu@"IP_of_your_pi"
. - the default password is
ubuntu
but the password should be urgently replaced with a strong password, otherwise an attacker will have access to all data stored on the NAS. - After that you will be logged out and have to log in again with your new password.
- Use
tab
in terminal for auto-complete. - Exit nano with
Ctrl+x
and confirm changes withy
. - Select a text section in nano:
Alt+A+M
and then move with thearrow
keys.Ctrl+arrow
key then selects the whole paragraph at once. - Cut selected text in nano:
Ctrl+K
sudo apt-get update
sudo at-get full-upgrade
If errors occur here, just rebooting will help.
Make SSH more secureNote: Since the NAS will only be accessible from the home network anyway, this is not absolutely necessary. This measure helps to make attacks on port 22 useless, but with a portscan you can also find out the actually used port. Therefore, a strong password is more important for every user. More help would be provided by fail2ban and access via certificate.
- For this we need to change the default SSH port and disable root login. This is done in the SSH configuration file under /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
- Here we have to remove the "#" in line
#Port 22
and change "22" to any other port (e.g. 2846). - Also, in the line
#PermitRootLogin prohibit-password,
the "#" should be removed and "prohibit-password" should be replaced by " no". - This should look like this:
Port 2846
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
[...]
# Authentication:
#LoginGraceTime 2m
PermitRootLogin no
- To make the changes take effect immediately, we restart ssh:
sudo /etc/init.d/ssh restart
Allow selected port in the firewallSince we changed the default port of SSH, sudo ufw allow OpenSSH
won't work anymore. Therefore, we need to use the following command to allow the newly selected port:
sudo ufw allow 1636
- Now the port must be specified when logging in via SSH:
ssh ubuntu@ubuntu -p 2846
Since I have installed several Ubuntu servers and want to recognize my NAS better in the home network afterwards, the hostname will be changed. Note: After that the RPi is no longer reachable via ssh under ssh ubuntu@ubuntu -p 2846
but under ssh ubuntu@rpi-nas -p 2846
.
- With
hostnamectl
we can display the current hostname:
$ hostnamectl
Static hostname: ubuntu
Icon name: computer
Machine ID: e5e5d4e8666c456488d91bc2735712d0
Boot ID: 1fdeecd84e8f48c499c520978bc60358
Operating System: Ubuntu 20.04.2 LTS
Kernel: Linux 5.4.0-1029-raspi
Architecture: arm64
- With the
set-hostname
option we can set a new hostname:
sudo hostnamectl set-hostname rpi-nas
- Then we have to add the line
127.0.0.1 rpi-nas
to the/etc/hosts
file:
sudo nano /etc/hosts
It should then look something like this:
127.0.0.1 rpi-nas
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
- The last thing to do is to change a value in the cloud.cfg file:
sudo nano /etc/cloud/cloud.cfg
- Search here for
preserve_hostname:
and change the value totrue
- To make sure everything worked, we run
hostnamectl
again.
$ hostnamectl
Static hostname: rpi-nas
Icon name: computer
Machine ID: e5e5d4e8666c456488d91bc2735712d0
Boot ID: 1fdeecd84e8f48c499c520978bc60358
Operating System: Ubuntu 20.04.2 LTS
Kernel: Linux 5.4.0-1029-raspi
Architecture: arm64
Add non-root userThe last thing we do is to add a default, non-root user, which we will work with from now on.
- To do this:
sudo adduser config
- Add the user to the sudo group:
sudo usermod -a -G sudo config
- Now we switch to the new user and run a command that requires root right to make sure everything worked:
sudo su - config
sudo apt-get update
Python scripts to cool the NASCooling the Raspberry Pi- First, you need to install some packages:
sudo apt-get install python3-pip
sudo pip3 install Rpi.GPIO
pip3 install gpiozero
pip3 install pigpio
sudo apt-get install rpi.gpio-common
sudo apt-get install python3-rpi.gpio
- Then the group
gpio
must be created, the current user (config) must be added and the group must get rights for the GPIOs:
sudo groupadd gpio # Add the group
sudo usermod -a -G gpio $USER # Add the current user to the new group
sudo grep gpio /etc/group # Assure that everything is working
sudo chown root:gpio /dev/gpiomem # Change the gpio owner to root
sudo chmod g+rw /dev/gpiomem # Add read and write permissions
- Alternatively, the current user may also own
gpiomem
:
sudo chown root:$USER /dev/gpiomem
- Now we create another folder where the python scripts will be placed, and also the python script itself. The code that needs to be inserted is found on GitHub:
mkdir code
cd code
mkdir python
cd python
nano cooling_pi.py # now paste the code from GitHub
sudo chmod u+x cooling_pi.py # Make the script executable
- To ensure that the Pi is reliably cooled after each reboot, we add the following line to the crontab. To log any errors that occur, we also create a log file:
cd log/
touch cron_user.log
crontab -e
@reboot python3 /home/config/code/python/cooling_pi.py > /home/config/log/cron_user.log 2>&1 # Insert this line.
Cooling the HDDs- To be able to read out the temperatures of the hard disks, hddtemp must be installed:
sudo apt-get install hddtemp
- The following line can be used to read out the temperature for a hard disk:
for i in /dev/sdX ; do sudo hddtemp sata:$i; done
- For the script we create a new folder for shell scripts in the directory./code. There we will create a script for each disk (code on GitHub) Since the readout requires root rights, but the python script is executed by a non-root user, the owner of the shell scripts must be changed to root, as well as the file rights must be adjusted.
cd code/
mkdir shell
cd shell/
nano sda_temp.sh # For HDD1
nano sdb_temp.sh # For HDD2
sudo chown root:root sda_temp.sh sdb_temp.sh # Change the owner
sudo chmod 755 sda_temp.sh sdb_temp.sh # Assign the relevant file permissions
sudo visudo # To avoid the need to enter a password, insert those two lines
config ALL=(ALL) NOPASSWD: /home/config/code/shell/sda_temp.sh
config ALL=(ALL) NOPASSWD: /home/config/code/shell/sdb_temp.sh
- Now we create the python script and add it to the crontab.
cd code/python/
nano cooling_hdd.py # now paste the code from GitHub
sudo chmod u+x cooling_hdd.py # Make the script executable
crontab -e
@reboot python3 /home/config/code/python/cooling_hdd.py > /home/config/log/cron_user.log 2>&1 # Insert this line.
Create Software RaidNow it finally comes to create the raid using mdadm.
- First, let's display the available disks to check that everything is working fine.
sudo lshw -short
H/W path Device Class Description
===============================================
system Raspberry Pi 4 Model B Rev 1.4
/0 bus Motherboard
/0/1 processor cpu
/0/2 processor cpu
/0/3 processor cpu
/0/4 processor cpu
/0/5 memory 7811MiB System memory # 8 GB RAM
/0/0 bridge Broadcom Inc. and subsidiaries
/0/0/0 bus VL805 USB 3.0 Host Controller
/0/0/0/0 usb1 bus xHCI Host Controller
/0/0/0/0/1 bus USB2.0 Hub
/0/0/0/1 usb2 bus xHCI Host Controller
/0/0/0/1/1 storage ASM105x
/0/0/0/1/2 storage ASM105x
/0/6 scsi0 storage
/0/6/0.0.0 /dev/sda disk 4TB ASM105x # HDD1
/0/6/0.0.0/1 /dev/sda1 volume 3726GiB EXT4 volume
/0/7 scsi1 storage
/0/7/0.0.0 /dev/sdb disk 4TB ASM105x # HDD2
/0/7/0.0.0/1 /dev/sdb1 volume 3726GiB EXT4 volume
/1 wlan0 network Wireless interface
/2 eth0 network Ethernet interface
- If the hard disks are not partitioned yet, we will do that first. Note that for disks larger than 2TB, GPT must be used instead of MBR as the partition table, since MBR can only handle partitions < 2TB and the disk will otherwise contain several small partitions instead of one large one.
- To create a partition using the entire hard disk, you can simply enter 0% 100%. Otherwise the start and end block must be specified.
sudo parted /dev/sda mklabel gpt # Create partition table
sudo parted -a optimal -- /dev/sda mkpart primary 0% 100%
sudo parted /dev/sda set 1 raid on # Mark partition as RAID
Of course must be repeated for the second drive (sdb).
- Now the RAID can be created. We create a RAID1, so the disks are mirrored.
sudo mdadm --create /dev/md0 --auto md --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1
- The question "Continue creating array?" must be answered with "y".
- Now we create an ext4 partition on the raid array and mount it.
sudo mkfs.ext4 /dev/md0
sudo mkdir /mnt/nas
sudo nano /etc/fstab
/dev/md0 /mnt/nas ext4 defaults 0 2 # Insert this line
sudo mount -a
- The last thing to do is to update mdadm.conf and initramfs. The second one takes a while.
sudo su -c "/usr/share/mdadm/mkconf > /etc/mdadm/mdadm.conf“
sudo update-initramfs -u -k all
- Whether everything went well can be checked with these two commands:
cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 sdb[1] sda[0]
3906886464 blocks super 1.2 [2/2] [UU]
[>....................] resync = 1.9% (75295680/3906886464) finish=3092.5min speed=20649K/sec
bitmap: 30/30 pages [120KB], 65536KB chunk
Here you can also see if a hard disk is failed or synchronized.
sudo mdadm --detail /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Wed Feb 3 09:26:57 2021
Raid Level : raid1
Array Size : 3906886464 (3725.90 GiB 4000.65 GB)
Used Dev Size : 3906886464 (3725.90 GiB 4000.65 GB)
Raid Devices : 2
Total Devices : 2
Persistence : Superblock is persistent
Intent Bitmap : Internal
Update Time : Wed Feb 3 10:31:45 2021
State : clean, resyncing
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
Consistency Policy : bitmap
Resync Status : 1% complete
Name : ubuntu:0 (local to host ubuntu)
UUID : ab3d8d90:b05e8253:5f8e750d:7ae67fea
Events : 1235
Number Major Minor RaidDevice State
0 8 0 0 active sync /dev/sda
1 8 16 1 active sync /dev/sdb
Block UASIn the beginning, I often had problems with my hard drives being kicked out. On the one hand, this was due to the lack of a USB hub, but on the other hand, it was also due to UAS. That is why we will block it. In addition, we deactivate the sleep mode of the hard drives, so that they do not switch off at some point and are then no longer accessible.
lsusb -t # check, if your adapter uses UAS:
/: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
|__ Port 2: Dev 2, If 0, Class=Mass Storage, Driver=uas, 5000M # <- UAS
sudo lsusb
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 002: ID 174c:55aa ASMedia Technology Inc. Name: ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge, ASM1153E SATA 6Gb/s bridge
sudo nano /boot/firmware/cmdline.txt
usb-storage.quirks=174c:55aa:u # Insert this line.
sudo update-initramfs -u # Update initramfs so that the changes take effect.
sudo hdparm -S0 /dev/sda #Disable sleep
Setup SambaCreate userssudo apt-get install samba samba-common # install samba
- I have created a total of 7 users on my end. The distribution as follows: User1, User2, User3, User4 for all family members. In addition, I have set up a public share (family). This is where files and photos are stored to which everyone has access. Then there is a share User2Work. This share is for the business data of user 2, which is also mounted only on the business laptop.
- There is also the user nas. This is generally used for writing, because otherwise conflicts with user rights could arise, for example, if User1 wants to change a file created by User2.
- With the first command a normal Ubuntu user named User1 is created. However, since this user does not need a home directory, nor does he need to log in to the NAS via ssh as we do, we disable this with the options
--no-create-home
and--disabled-login
. Also questions about residence, department, etc. can be skipped. The second command sets a (strong!)password for this user. Note that anyone who has this password can also have access to all files stored under this user.
sudo adduser --no-create-home --disabled-login --shell /bin/false user1
sudo smbpasswd -a user1
- These steps are now repeated for all 7 users.
- Of course, no folder is created for nas, since this user is only used for writing. Besides that, a separate folder is created for each of the other 6 users.
- In order for nas to be used for writing, this user must also be specified as the owner at the end.
cd /mnt/nas/
sudo mkdir shares
cd shares/
sudo mkdir {user1,user2,user2work,user3,user4,family}
sudo chown -R nas: /mnt/nas/shares/
Set up shares- To do this, we edit the
smb.conf
file. - For the normal users, the example of user1 can be used. Make sure that everywhere user1 (also in the path to the folder) is aligned with the real name.
- The example from the family can be used for all public shares.Just add it at the end of the file.
- In addition, the line
map to guest = bad user
must be changed tomap to guest = never
, so that Windows10 users can also use the share without errors. Otherwise "network errors" might occur.
sudo nano /etc/samba/smb.conf
# user1
[user1] # The name of the share.
comment = User1 # This comment appears e.g. in Explorer.
path = /mnt/nas/shares/user # This is the folder for all files of User1.
write list = user1
valid users = user1
force user = nas
read only = no
browsable = yes
# family
[family]
comment = Family
path = /mnt/nas/shares/family
write list = user1,user2,user3,user4 # Enter all users who should have access here.
valid users = family,user1,user2,user3,user4 # In addition, of course, family must be added here.
force user = nas
read only = no
browsable = yes
Note at this point: Whoever has the ubuntu or config passwords also has access to all files stored on the entire NAS.
Last step- The last thing to do is to restart Samba and allow it in the firewall
sudo service smbd restart
sudo allow smb on ufw
Now the NAS is completely set up and working.
It can now be mounted under Windows or Linux
//192.168.178.54/user1/documents /home/user1/Documents cifs credentials=/home/user1/.credentials/smbcredentials,users,uid=1000,gid=1000,forceuid,forcegid 0 0
and used normally like a hard disk.
Keep in mind, however, that a Raid1 storage is not a fully permanent backup solution and that regular backups must be made to different locations.
Comments