Setting up an Ubuntu file server
I built my last file server in July 2010 and when it finally died in August 2017 I could barely remember how I had originally set it up. For posterity I thought an article detailing exactly how I configured my new file server would not only be great for future me to reference but maybe it will prevent someone else from stumbling through it like I did.
For my new file server I simply repurposed the remnants of my old gaming rig. It was a i5 2500K CPU with 16GB of RAM and a Radeon 6970 GPU which I chose to remove because I planned on using Ubuntu Server which didn't have a GUI. I took a spare 128GB SSD from another machine to be my OS drive and purchased two 4TB Western Digital Red (WD40EFRX) drives for my new RAID 1.
1. Create a bootable Ubuntu Server USB drive
The first step is to download the Ubuntu Server ISO. I recommend the Long Term Support (LTS) version because odds are your server is going to be very static and you're not going to need to update it to the latest and greatest Ubuntu as soon as it is released. You will want the more stable version that is supported for the longest period of time so you aren't likely to be forced into any major upgrades.
Be aware that the Ubuntu website will automatically download the ISO for the architecture of the machine you visit the website on which is going to be the 64-bit version for 99.99% of the people reading this. If you are going to install Ubuntu Server on a 32-bit machine you'll need to download the i386 ISO.
Once you have downloaded the ISO you can make a bootable USB drive by using the dd command. I did this on macOS Sierra using the following steps:
- Connect the USB drive you want to use. Keep in mind all the data on this drive is going to be erased.
- Run
disktuil list
to see a list of all of your connected drives. One of them should obviously be the USB drive because it should use some verbiage like "external". Let's assume the name of this drive is /dev/diskX. - Ensure the disk is unmounted by running
diskutil unmount /dev/diskX
. - Copy the contents of the ISO to your USB drive by running
sudo dd if=ubuntu-16.04.3-server-amd64.iso of=/dev/diskX bs=1m
. This will take several minutes.
2. Install Ubuntu Server
Plug your newly created Ubuntu Server USB drive into your file server and boot off of it. I booted into BIOS mode instead of UEFI because my hardware was fairly old (5 years) and I wanted to go with the old stuff that was robust versus the new hotness which could be buggy. Also the documentation for Ubuntu is pretty sparse and I was confident that my bad luck would mean I'd hit some random UEFI bug that no one has ever seen. I wanted to minimize my chances of stumbling across a phpBB forum post asking inquiring about my problem but having no solution.
I followed Ubuntu's handy install guide which was basically just push next until asked for a username and password. 99% of installs shouldn't need to change a thing but choose whatever suits your needs.
After the install has finished the server will restart and you should be looking at a command line asking you for the login credentials you created during installation. Enter them and you are ready to start configuring your server.
3. Update all the things
Even though you just finished installing your operating system I can guarantee you that something critical is out of date. Run the following commands:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get clean
and now your system should be completely up to date.
If you followed the Ubuntu Server install guide automatic updates should already be turned on but if not I highly recommend you look into enabling them.
4. Give your server a static IP address
You will want to give your server a static IP address so you can easily access it. There is nothing more frustrating than not being able to SSH into your server because the dynamic IP address changed.
To do this you will need to edit your /etc/network/interfaces
file.
You should see something like
auto eno1
iface eno1 inet dhcp
which indicates that your ethernet (en) onboard (o) in the first (1) position is set to use dynamic IP assignment (dhcp).
You want to change those two lines to be
auto eno1
iface en1 inet static
address 10.0.0.100
gateway 10.0.0.1
dns-nameserver 10.0.0.1
where "address" is the IP address you want your server to be, "gateway" is typically the IP address of your router and "dns-nameserver" is also the IP address of your router but you could use any name server you want like Google's (8.8.8.8) for instance.
Technically you can get your server to recognize these changes by running some commands but I always like to ensure this stuff works from a cold boot so I usually restart the machine with sudo shutdown -r now
.
When the machine finishes rebooting and you are logged back in you can run ifconfig
to ensure your computer has the correct IP address and run ping google.com
to ensure that it is resolving names properly.
To make things even easier you can now edit the /etc/hosts
file on whatever machine you plan to connect to your server from and add 10.0.0.100 CoolNameHere
so that you no longer have to memorize the IP address and can refer to it by whatever name you choose.
5. Configure ufw
Uncomplicated Firewall (ufw) is an amazing tool that lets you greatly improve the security of your server by clamping down on the ports that it communicates through.
Turn on ufw by running the command sudo ufw enable
and check that it is working with sudo ufw status verbose
. You should see that none of your ports are open.
Next you want to open up the port that you are going use to SSH into the server. I typically choose a port that is five digits to be confident that I will not be colliding with any other programs. Run sudo ufw allow XXXXX/tcp
to open the port for communication over TCP and then run sudo ufw status verbose
again to ensure the port was opened correctly. You should see something like
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
XXXXX/tcp ALLOW IN Anywhere
XXXXX/tcp (v6) ALLOW IN Anywhere (v6)
6. Configure SSH
99.99% of Linux distros have OpenSSH already installed but if your server doesn't you can run sudo apt install openssh-client
and sudo apt install openssh-server
.
Once OpenSSH Server is installed you will need to configure it by editing the /etc/ssh/sshd_config
file.
- Change
Port 22
toPort XXXXX
where XXXXX is same value you used when configuring ufw. - Ensure
PermitRootLogin no
is set. There is absolutely no reason to allow someone to log into your server as root. They can log in as another user and then request escalation. - Ensure
PubkeyAuthentication yes
is set. You only want users to be able to access your server via public key authentication, never passwords. - Ensure
PasswordAuthentication no
is set. Same reasons as above. - Ensure
UsePAM no
is set. Same reasons as above. - Add
AllowUsers user
and replace "user" with whatever user you want to be able to SSH into your machine. You always want to have a whitelist so any new user you add is not automatically granted permission to SSH in.
Now that OpenSSH is configured you need to set the public keys that are able to SSH into the server. Run the commands:
mkdir ~/.ssh/
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
which creates the necessary file and ensures it has the correct permissions, assuming the current user is the one that you added to the AllowUsers option in the sshd_config file.
Now you will need to add your public key to the authorized_keys
file. I upgraded to an Ed25519 key since DSA and RSA are deprecated so I just copied the output of cat ~/.ssh/id_ed25519.pub
on my local machine to the authorized keys file on my server.
Restart the server again with sudo shutdown -r now
and ensure you can SSH into your server from the machine you just authorized.
7. Install mdadm and set up your RAID
I used this article to refresh my memory on how to install and configure mdadm.
First you need to ensure mdadm is installed by running sudo apt-get install mdadm
.
Next you need to determine the logical names of the drives that will be used for the RAID. You can use sudo lshw -C disk
to get a list of all of the hard drives connected to your server.
Now you could just run sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sda /dev/sdb
and be done (assuming the logical names of your two drives are /dev/sda and /dev/sdb) but there is a downside to this. You are telling mdadm to use the entire disk for your RAID. This has two major drawbacks.
If you removed a hard drive from your RAID and transferred it to another computer it would only only be recognized by mdadm because it has no valid partition.
Any hard drives you add to the RAID in the future have to be the EXACT same size as your existing drives. If you can't find the exact model in the future then you'll most likely have to buy a bigger drive to ensure that it is large enough for your RAID. If you attempt to add anything that is smaller it will fail.
Basically partitioning your drives first gives you more flexibility in the future for when things inevitably go wrong.
So, assuming the two drives to be added to the RAID are /dev/sda and /dev/sdb, let's start by partitioning /dev/sda. Since the hard drives I was using were greater than 2TB I needed to use the parted command
for its support of GUID Partition Table. fdisk
only supports master boot record which means that it cannot work with drives over 2TB.
To partition /dev/sda with parted
you need to run the following commands:
sudo parted -a optimal /dev/sda
unit MiB
mklabel gpt
mkpart primary 2048s 3720GiB
align-check opt 1
set 1 raid on
quit
and then repeat them for /dev/sdb. Keep in my that 3720GiB is specific to my hard drives because they were 4TB in size. While you are inside parted you can use the print command to see what free space you have available.
You can run sudo fdisk -l
to list all of your drives and ensure that the partitions were created successfully. They should be identical between your two drives (/dev/sda1 and /dev/sdb1) which ensures they can be added to the same RAID.
You can now create the RAID by running sudo mdadm --create --verbose /dev/md0 --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1
.
To check on the status of the RAID you can run cat /proc/mdstat
or sudo mdadm --detail /dev/md0
. Since the RAID was just created it should be in the syncing state which will most likely take multiple hours to finish but you can still use the RAID at this time.
Now that the RAID has been successfully created we can format it with a file system so it can be mounted. Run the command sudo mkfs.ext4 -v /dev/md0
to create an ext4 file system which is the most common Ubuntu file system.
Next we should copy the ouput of sudo mdadm --detail --scan
and add it to our /etc/mdadm/mdadm.conf
file so that the RAID can automatically start on boot.
And finally if we want to the RAID to be mounted on boot we need to add it to our /etc/fstab
file. Get the UUID of /dev/md0 by running lsblk -o NAME,UUID
and then add UUID=XXX /mnt/md0 auto defaults 0 0
to your /etc/fstab
file where XXX is the UUID of the RAID and /mnt/md0 is your mount point.
If you run sudo shutdown -r now
again and log in to your server you should be able to cd /mnt/md0
and access your RAID.
8. Test RAID performance
To test the speed of your RAID you can run hdparm -Tt /dev/md0
. You can compare the results to the theoretical performance you should be getting from your drives to ensure that everything is working as expected.
You can also use the dd command to test the creation and reading of a large file to perform a practical performance test as well as see how your RAID handles syncing a large file.
dd if=/dev/zero of=/mnt/md0/test.out bs=1M count=10240
will create a 11 gigabyte file of all zeroes 1 megabyte at a time.
dd if=/mnt/md0/test.out of=/dev/null bs=1M
will read the entire file into /dev/null which is essentially a no-op but it will still access every byte of the file which demonstrates how fast you can read from your RAID.
7. Set up Samba
Now that our RAID is configured we want to expose it to our local network so that other users can read and write files to it. For this I chose to use Samba.
First you need to install Samba using sudo apt install samba
.
Next for every user you want to have access to Samba you will need to set a Samba specific password. This password can be the same as your Ubuntu password if you want but if the user you are giving access to has a lot of power then I would recommend you use two different passwords. To set the password for "user" run sudo smbpasswd -a user
and follow the prompts.
Now that "user" is configured to use Samba we must create a shared directory. To do this you'll need to edit /etc/samba/smb.conf
and add the following to the very bottom if you want to share a directory at /mnt/md0/Photos
.
[Photos]
path = /mnt/md0/Photos
browseable = yes
read only = yes
guest ok = yes
write list = user
This creates a publicly browseable share called "Photos" that guests can read from but only "user" can write to. You also must pay attention to the actual permissions of the directory you are sharing. In our case /mnt/md0/Photos
must be readable by anyone and writable by a group that contains "user".
Since we are using ufw we have one more step before our share can be accessed. We need to open the Samba specific ports by running sudo ufw allow samba
. After that you should run sudo service smbd restart
to restart Samba and ensure all of your changes take affect. Now you should be able to access your share from any computer on your local network.
If you are going to have Mac's accessing your share like I am you may want to add the following to your shares in /etc/samba/smb.conf
to prevent Apple metadata files from being created.
veto files = /._*/.DS_Store/
delete veto files = yes
I learned about this little trick from this article.
8. Time for a celebration
That's it. You should be good to go. Your server is automatically updating. You have a firewall in place and only allow public key authentication for SSH. Your RAID starts and mounts on boot and you can share over your network. What more do you want from your file server?