Build a network-attached storage (NAS) with your Raspberry Pi and an external USB hard drive.
It's been few months since I've bought Raspberry Pi board and, quite frankly, I haven't been using it as much as I wanted - main reason being too little spare time on my hands.
Anyway, I was thinking recently of how I would really benefit from having some networked storage in my small home office and the thought had occurred of assembling one with my Raspberry Pi and an external 500 GB USB drive that I already have - basically, putting Raspberry Pi to good use :)
As with all DIY projects, one of the main hassles is the enclosure to put all of the hardware in. I wanted a quick solution - didn't have the time to make something fancy. After a while I remembered that I've saved my Amazon Kindle Keyboard cardboard package. The quality of the cardboard is excellent and the construction is quite sturdy. After some measuring and layout prototyping I decided that it is quite good for this purpose so I began to work on my new NAS :)
After reviewing Raspberry Pi (model B) schematics and laying out my requirements I decided to power USB hard drive directly from the power supply unit. Raspberry Pi (model B) has 140 mA poly-fuse on each of the two USB ports while the current requirement of the USB hard drive is certainly higher. This particular USB hard drive (Transcend StoreJet 25M) has Toshiba MK5065GSX HDD inside and according to specifications it consumes 300 mA during read/write operations (and almost full 1 A during start-up!). Anyway, it's safe to say that a single USB hard drive will consume max. 500 mA in general (as that is the max. allowable current on standard USB port). I also plan to add second hard drive eventually, so I'll be needing 1 A for USB hard drives alone. According to wiki, Raspberry Pi (model B) requires ~700 mA of current for active operation so, all in all, I'll be needing at least 1.7 A of current (2 A optimal). Unfortunately, I didn't have any spare 5 V DC power supply with stated current capabilities so I decided to purchase one. I found Mean Well RS-25-5 (5 V at 5 A) switching power supply at my local electronics shop. This is one really stable power supply. I adjusted it's output voltage to 5.05 V while it was unloaded. After I've loaded it with Raspberry Pi and USB hard drive the voltage stayed on exactly the same level - quite nice.
On picture 1, a schematic of all the necessary connections is displayed. Of course, in order to supply power from my new power supply, I had to cut one end of the USB-Micro cable and attach power conductors (Vcc and GND) directly to V+ and V- of the power supply unit (respectively). The same goes for USB hard drive. USB hard drive also requires connections to the Raspberry Pi board - but only the data lines (D+ and D-).
After a few days of sporadic "high-tech super-glue" cardboard modifications and quick electrical layout, the (almost) finished "device" can be seen on the following pictures. I say "almost" since I didn't install power switch SW1 - quite frankly, I didn't even remember to put it at the time I was assembling all this. I'm also thinking of adding soft turn-off mechanism (using Raspberry Pi's GPIO) instead of SW1 - and will probably do that, we'll see :)
After all the hardware assembly work was finished, I hooked up new Raspberry Pi NAS box to my LAN router, powered it up and began configuring the software.
As with all DIY projects, one of the main hassles is the enclosure to put all of the hardware in. I wanted a quick solution - didn't have the time to make something fancy. After a while I remembered that I've saved my Amazon Kindle Keyboard cardboard package. The quality of the cardboard is excellent and the construction is quite sturdy. After some measuring and layout prototyping I decided that it is quite good for this purpose so I began to work on my new NAS :)
The Hardware
After reviewing Raspberry Pi (model B) schematics and laying out my requirements I decided to power USB hard drive directly from the power supply unit. Raspberry Pi (model B) has 140 mA poly-fuse on each of the two USB ports while the current requirement of the USB hard drive is certainly higher. This particular USB hard drive (Transcend StoreJet 25M) has Toshiba MK5065GSX HDD inside and according to specifications it consumes 300 mA during read/write operations (and almost full 1 A during start-up!). Anyway, it's safe to say that a single USB hard drive will consume max. 500 mA in general (as that is the max. allowable current on standard USB port). I also plan to add second hard drive eventually, so I'll be needing 1 A for USB hard drives alone. According to wiki, Raspberry Pi (model B) requires ~700 mA of current for active operation so, all in all, I'll be needing at least 1.7 A of current (2 A optimal). Unfortunately, I didn't have any spare 5 V DC power supply with stated current capabilities so I decided to purchase one. I found Mean Well RS-25-5 (5 V at 5 A) switching power supply at my local electronics shop. This is one really stable power supply. I adjusted it's output voltage to 5.05 V while it was unloaded. After I've loaded it with Raspberry Pi and USB hard drive the voltage stayed on exactly the same level - quite nice.
On picture 1, a schematic of all the necessary connections is displayed. Of course, in order to supply power from my new power supply, I had to cut one end of the USB-Micro cable and attach power conductors (Vcc and GND) directly to V+ and V- of the power supply unit (respectively). The same goes for USB hard drive. USB hard drive also requires connections to the Raspberry Pi board - but only the data lines (D+ and D-).
Picture 1: Raspberry Pi NAS Schematic |
After a few days of sporadic "high-tech super-glue" cardboard modifications and quick electrical layout, the (almost) finished "device" can be seen on the following pictures. I say "almost" since I didn't install power switch SW1 - quite frankly, I didn't even remember to put it at the time I was assembling all this. I'm also thinking of adding soft turn-off mechanism (using Raspberry Pi's GPIO) instead of SW1 - and will probably do that, we'll see :)
Picture 2: Finished (almost) Raspberry Pi NAS |
Picture 3. Raspberry Pi NAS - rear view |
Picture 4: Closed box - holes are for ventilation |
After all the hardware assembly work was finished, I hooked up new Raspberry Pi NAS box to my LAN router, powered it up and began configuring the software.
The Software
I already had installed Raspbian "wheezy" on my SD card, so I continued with the configuration. I decided to set static IP address for Raspberry Pi (I chose 192.168.1.50). This can be done by editing
Since I don't like IP addresses (from aesthetic point of view) I added more aesthetically pleasing hostname to
First step in mounting the USB hard drive is finding it in
I now added this partition to
After much testing with both SSHFS and NFS remote mounts I decided to stay with SSHFS since the testing showed that it's faster than NFS mounted drive and it's more secure (being based on SSH). Another thing to note is that SSHFS is easier to setup - NFS requires installation and configuration of packages on both client and server while SSHFS requires installation and configuration of additional packages only on client (since SSH server is present by default on Raspbian - actually most, if not all, Linux distributions). Testing results are presented in "The Testing" chapter.
For the sake of completeness I'll describe how I configured both SSHFS and NFS. I'm using Crunchbang Linux (Debian based distro) on my working machine.
In order to mount remote folder to local
Enter Raspberry Pi's password and remote USB drive should be mounted at local
As can be seen above, when I mounted remote drive using
In order to mount remote drive via NFS, NFS packages will need to be installed both on client and server machine. My working machine (client) will only need following packages:
During the installation of
I performed read and write tests using
SSHFS is faster, both at reading and writing data by ~0.2 MB/s. I tried watching video (Video: MPEG-4, 672x512, 25 fps; Audio: 48 kHz, stereo, 128 kb/s) both via SSHFS and NFS and there really is no noticeable difference (I used VLC media player). Seeking (in movie) works fast, video plays smooth all the time (no interruptions whatsoever). However, when watching .mkv video (Video: H264 - MPEG-4, 1280x720, 25 fps; Audio: 48 kHz, stereo, 192 kb/s) interruptions (hiccups) appear every ~2 minutes on SSHFS and every 5-10 minutes on NFS. I have yet to discover why this is happening as, according to above measurements, there is certainly enough bandwidth to support constant stream in both cases.
NAS is a great thing but still, Raspberry Pi can do more - much more. One of the things that can be installed is torrent client. I'm thinking of i.e.
This has been a fun little project and I will probably do a follow up on torrent client configuration and more :)
/etc/network/interfaces
on Raspberry Pi and adding following configuration:
iface eth0 inet static address 192.168.1.50 netmask 255.255.255.0 gateway 192.168.1.1If the first line is already present (i.e.
iface eth0 inet dhcp
) then it should be replaced with the above configuration. After this, networking service should be restarted
pi@raspberrypi ~ $ sudo service networking restartSSH connection will be broken after this step. However, Raspberry Pi should be available on the new address (192.168.1.50).
Since I don't like IP addresses (from aesthetic point of view) I added more aesthetically pleasing hostname to
/etc/hosts
on my working machine
192.168.1.50 rpiYep, much better ;)
Mounting the USB Hard Drive
First step in mounting the USB hard drive is finding it in
/dev
. One way to find out which device is your target device is with fdisk
:pi@raspberrypi ~ $ sudo fdisk -l Disk /dev/mmcblk0: 7822 MB, 7822376960 bytes 4 heads, 16 sectors/track, 238720 cylinders, total 15278080 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x000108cb Device Boot Start End Blocks Id System /dev/mmcblk0p1 8192 122879 57344 c W95 FAT32 (LBA) /dev/mmcblk0p2 122880 3788799 1832960 83 Linux Disk /dev/sda: 500.1 GB, 500107862016 bytes 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x4c153c12 Device Boot Start End Blocks Id System /dev/sda1 63 976768064 488384001 c W95 FAT32 (LBA) pi@raspberrypi ~ $By looking at the disk sizes I could deduce which one is my USB drive - highlighted line
Disk /dev/sda: 500.1 GB, 500107862016 bytes
indicates that this is 500 GB hard drive. Since USB hard drives can be partitioned like any other, all partitions of this device are listed further down. This hard drive has only one partition /dev/sda1
. In order to mount it I first had to create a mounting point. I did that by creating empty folder in /mnt
:
pi@raspberrypi ~ $ sudo mkdir /mnt/drive1Now, I can mount
/dev/sda1
partition using mount
:pi@raspberrypi ~ $ sudo mount -o umask=0 /dev/sda1 /mnt/drive1At this point I can access USB hard drive at
/mnt/drive1
:
pi@raspberrypi ~ $ ls -l /mnt/drive1 total 576 drwxrwxrwx 4 root root 32768 Oct 16 2011 BACKUP drwxrwxrwx 7 root root 32768 Dec 9 2010 System Volume Information drwxrwxrwx 47 root root 32768 Nov 12 20:43 VideosGreat, all is working :)
I now added this partition to
/etc/fstab
which will mount it at boot time (edited /etc/fstab
on Raspberry Pi and added following line):
/dev/sda1 /mnt/drive1 auto users,noatime,umask=0 0 0I now created mounting point on my working machine:
me@localhost:~$ sudo mkdir /mnt/drive1This is where I'll mount remote Raspberry Pi's
/mnt/drive1
.SSHFS/NFS Installation
After much testing with both SSHFS and NFS remote mounts I decided to stay with SSHFS since the testing showed that it's faster than NFS mounted drive and it's more secure (being based on SSH). Another thing to note is that SSHFS is easier to setup - NFS requires installation and configuration of packages on both client and server while SSHFS requires installation and configuration of additional packages only on client (since SSH server is present by default on Raspbian - actually most, if not all, Linux distributions). Testing results are presented in "The Testing" chapter.
For the sake of completeness I'll describe how I configured both SSHFS and NFS. I'm using Crunchbang Linux (Debian based distro) on my working machine.
Method 1: SSHFS
In order to mount remote folder to local
/mnt/drive1
mount point via SSH, I installed sshfs
utility:
me@localhost:~$ sudo apt-get install fuse sshfsAfter the installation I immediately mounted remote drive:
me@localhost:~$ sudo sshfs -o allow_other pi@rpi:/mnt/drive1 /mnt/drive1 pi@rpi's password:
Please note that if
sshfs
mounting is not done as root
, user that performs the mount has to be a part of fuse
group. This can be done like:
me@localhost:~$ sudo usermod -a -G fuse username
Enter Raspberry Pi's password and remote USB drive should be mounted at local
/mnt/drive1
.
me@localhost:~$ ls -l /mnt/drive1 total 576 drwxrwxrwx 4 root root 32768 Oct 16 2011 BACKUP drwxrwxrwx 7 root root 32768 Dec 9 2010 System Volume Information drwxrwxrwx 47 root root 32768 Nov 12 20:43 VideosNow, I wanted this to be mounted at boot time so I added following to
/etc/fstab
on my machine:
sshfs#pi@rpi:/mnt/drive1 /mnt/drive1 fuse _netdev,users,allow_other,reconnect 0 0First field is remote file system (user, remote address, remote path) while the second field is local mount point. Third field is type of the file system (in this case
fuse
) and fourth field has a list of options. Each of them is important and should not be left out if remote drive is to be automatically mounted at boot time successfully - more info on these options can be found in mount
man pages.As can be seen above, when I mounted remote drive using
sshfs
, Raspberry Pi asked for a password - like when connecting using standard ssh
utlity. This will be a problem when system tries to mount remote drive at boot time. In order to avoid being asked for a password I created SSH authentication key for root
user (since fstab
will be executed by root
):
me@localhost:~$ sudo ssh-keygen -t rsa -C "me@localhost" [sudo] password for me: Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub.Didn't set any passphrase since, if set, it will ask for that passphrase when trying to establish SSH connection - the very thing I'm trying to avoid with Raspberry Pi's password. I then added it (contents of
/root/.ssh/id_rsa.pub
) to Raspberry Pi's /home/pi/.ssh/authorized_keys
file:
ssh-rsa some_very_long_set_of_characters me@localhostAfter the reboot, remote USB drive should be automatically mounted to local
/mnt/drive1
.Method 2: NFS
In order to mount remote drive via NFS, NFS packages will need to be installed both on client and server machine. My working machine (client) will only need following packages:
me@localhost:~$ sudo apt-get install portmap nfs-commonThis will basically enable me to mount remote drive using standard
mount
utility.
Raspberry Pi will need NFS server package as well:
pi@raspberrypi ~ $ sudo apt-get install portmap nfs-common nfs-kernel-serverAfter the installation of NFS packages on Raspberry Pi, installer will try to start
nfs-common
service but will fail since rpcbind
service is not running. It will also try to start nfs-kernel-server
but will fail since /etc/exports
is empty:
... Creating config file /etc/default/nfs-common with new version [....] Starting NFS common utilities: statd [warn] Not starting: portmapper is not running ... (warning). Setting up nfs-kernel-server (1:1.2.6-3) ... Creating config file /etc/exports with new version Creating config file /etc/defaults/nfs-kernel-server with new version [....] Starting NFS common utilities: statd [warn] Not starting: portmapper is not running ... (warning). [warn] Not starting NFS kernel daemon: no exports. ... (warning).Configurations in
/etc/exports
file control which remote host can access which local (Raspberry Pi in this case) directory. I want to give access to local /mnt/drive1
so I added following line to /etc/exports
(on Raspberry Pi of course):
/mnt/drive1 192.168.1.0/255.255.255.0(rw,sync,no_subtree_check)First column represents absolute path to local folder to be shared while second column specifies remote client. In this case
192.168.1.0/255.255.255.0
means that access to /mnt/drive1
folder is allowed for anyone on 192.168.1.0 network. Options in the brackets are mounting options i.e. if mounted file system will be only readable, writable or both. More info can be found in man pages for mount
and fstab
.
It's also not bad to add extra level of security for NFS. This can be done by adding few rules to
/etc/hosts.deny
and /etc/hosts.allow
. In /etc/hosts.deny
:
rpcbind: ALLand in
/etc/hosts.allow
:
rpcbind: 192.168.1.0/255.255.255.0Here's some more info on NFS security. Although
portmap
is mentioned in linked article, newer Debian systems have rpcbind
instead.
During the installation of
nfs-common
and nfs-kernel-server
utilities, installer created init scripts which will try to start these services on system boot. However, these services require rpcbind
service to be started first and, currently, on Raspbian "wheezy" rpcbind
is not started at boot time. This can be remedied with following command:
pi@raspberrypi ~ $ sudo update-rc.d rpcbind enableFinally, start
rpcbind
, nfs-common
and nfs-kernel-server
services:
pi@raspberrypi ~ $ sudo service rpcbind start [ ok ] Starting rpcbind daemon.... pi@raspberrypi ~ $ sudo service nfs-common start [ ok ] Starting NFS common utilities: statd idmapd. pi@raspberrypi ~ $ sudo service nfs-kernel-server start [ ok ] Exporting directories for NFS kernel daemon... [ ok ] Starting NFS kernel daemon: nfsd mountd.Mounting of
/mnt/drive1
on client machine should now be possible:
me@localhost:~$ sudo mount rpi:/mnt/drive1 /mnt/drive1At this point, Raspberry Pi's
/mnt/drive1
should be available at /mnt/drive1
on client machine.
me@localhost:~$ ls -l /mnt/drive1 total 576 drwxrwxrwx 4 root root 32768 Oct 16 2011 BACKUP drwxrwxrwx 7 root root 32768 Dec 9 2010 System Volume Information drwxrwxrwx 47 root root 32768 Nov 12 20:43 VideosYey, all is working fine :) Now, like on Raspberry Pi, I added mount point to
/etc/fstab
on my working machine:
rpi:/mnt/drive1 /mnt/drive1 nfs rw,hard,intr,async,nodev,noatime 0 0The first field is remote filesystem while the second field is local mount point. After the reboot, remote USB drive should be automatically mounted at local
/mnt/drive1
.
The Tests
I performed read and write tests using
dd
utility (as described here) both with SSHFS mount and with NFS mount. I took three different video files and copied them back and forth to/from /mnt/drive1
. I unmounted/mounted remote drive between each copy in order to avoid any caching interfering with measurements. I performed same measurements with standard cp
utility, transfer speeds were the same. I must point out that my working machine is connected to LAN router via Broadcom BCM4312 802.11b/g wireless card. Anyway, here are the results:
| |||||||||
Table 1. Throughput measurements |
NOTE: Transfer speed MB/s corresponds to 1000000 bytes/s. This is not be confused with MiB/s which corresponds to 1048576 bytes/s. More info on data rate units can be found here.
SSHFS is faster, both at reading and writing data by ~0.2 MB/s. I tried watching video (Video: MPEG-4, 672x512, 25 fps; Audio: 48 kHz, stereo, 128 kb/s) both via SSHFS and NFS and there really is no noticeable difference (I used VLC media player). Seeking (in movie) works fast, video plays smooth all the time (no interruptions whatsoever). However, when watching .mkv video (Video: H264 - MPEG-4, 1280x720, 25 fps; Audio: 48 kHz, stereo, 192 kb/s) interruptions (hiccups) appear every ~2 minutes on SSHFS and every 5-10 minutes on NFS. I have yet to discover why this is happening as, according to above measurements, there is certainly enough bandwidth to support constant stream in both cases.
And More...
NAS is a great thing but still, Raspberry Pi can do more - much more. One of the things that can be installed is torrent client. I'm thinking of i.e.
rtorrent
client coupled with some web GUI (like ruTorrent or rtgui). This way torrents can be downloaded directly to NAS and are accessible by anyone on the network.This has been a fun little project and I will probably do a follow up on torrent client configuration and more :)