I had grand intentions.
This home server article was to be a detailed masterpiece, a complete documentation of my home server setup.
It hasn’t turned out that way, and many pieces are missing. Turns out, that writing a detailed article on setting up a server is much harder than just doing it! So what you see here is what I finally managed to publish, 5 months after actually building it. I hope you find it useful, and I don’t rule out the possibility that I may update parts of it in future.
Knowledge Requirements
The level I’m aiming at here is a novice sysadmin. If you’ve never heard of bash or used a terminal, you will struggle and I highly recommend starting with Ubuntu desktop and using the command line to get a feel for things.
You should also know how to use a text editor. I use vi, but feel free to substitute vi for nano, which is a much friendlier text editor for anyone not accustomed to vi’s modal interface.
Sometimes, I will give “magical one-liners”, which will perform several tasks in one step. Be careful with these! And don’t copy-paste them unless you are sure that they are suitable for your configuration. Even if a one-liner isn’t quite right though, I find them useful documentation as they are unambiguous. Just be sure you understand what you’re pasting.
Finally, before I get into it, I do not offer technical support for Ubuntu or this setup. If you get stuck, please feel free to comment, and either myself or another reader may help you, but any assistance should not be taken for granted, and will probably only be given if it might also useful to others. I am aiming this at technically savvy people who are prepared to do their own legwork. Hopefully, if you’re reading this, you’re not the sort of person that takes all this magic for granted. :-)
Choose your flavour
Even though you’ve probably decided on Ubuntu, there are several flavours to choose from, and the best choice for you boils down to a couple of things:
How “hands on” do you want to be?
If you’re happy doing a distribution upgrade every 6 months, and potentially a reinstall every couple of years, then using the latest stable release of Ubuntu (15.04 at the time of writing) makes the most sense. If you’re the kind of person that would rather “set and forget”, then I recommend using the latest LTS release.
How “pure” do you want the server to be?
If you’re the kind of person that doesn’t mind bloat, i.e. a full desktop install, then the Ubuntu desktop edition offers easier setup and some useful GUI tools, at the cost of increased power and memory usage. Some of these tools (network manager) can get in the way of shell-based configuration though, and a ssh session can be easier than having to plug a mouse and keyboard into a computer by the TV.
There are also more specialised distributions such as Kodibuntu (formerly XBMCbuntu), but for me, HTPC duties are secondary to NAS and server duties, so I prefer to have a clean base and treat Kodi as an add-on, rather than add NAS duties to Kodi.
Thus, I am going for the LTS release of Ubuntu Server because;
- I like my servers to be clean and free of clutter
- I value stability and don’t want to be forced to upgrade every 6 months
There is one caveat here and that’s proprietary drivers. The ASRock Z97E-ITX/AC motherboard I’m using has a Broadcom BCM4352 wireless adaptor, and the package provided in 14.04 failed to compile the kernel module. It was solved by installing the same package from 14.10, as detailed here.
Installation Notes
When you get to the package selection screen, I suggest ticking only Base Ubuntu Server, and OpenSSH server.
I’m not going to cover installing Ubuntu Server in detail, mainly because it is straightforward and covered well by the official documentation. However I did run into one problem; the installer installed grub (the boot loader) to the USB flash drive instead of the destination drive, which meant that without the flash drive plugged in I would get “error: no such partition”, followed by a rescue console on boot.
The fix for this, is simply to boot off the USB flash drive again, which should take you to your new OS install and not the installer, find the device name with [shell]mount | grep “on / type”[/shell], and run [shell]sudo grub-install /dev/your-disk-here[/shell] (grub-install /dev/sda for me).
Or you could use this magical one-liner:
[shell]
grub-install $(mount | awk ‘/on \/ type/ {print $1}’ | tr -d ‘[0-9]’)
[/shell]
From here on, I assume you have a simple Ubuntu Server install with a user account, and working internet access.
First step – sudo
First of all, and because this is a home server, I like to have sudo permissions without having to enter a password.
To do this, you need to create a file in /etc/sudoers.d, which is done as per the magical one-liner below (when logged in as that user):
[shell]
username=$(whoami); echo “$username ALL=(ALL) NOPASSWD: ALL” | sudo tee /etc/sudoers.d/$username
[/shell]
Installing the latest kernel
Usually, this isn’t necessary, however one of the goals of this setup was originally btrfs, and because btrfs is a relatively new filesystem, it is advisable to run the newest kernel available. The official wiki stresses this. If you prefer not to use btrfs you can skip this section.
Fortunately, Ubuntu has the back-ported kernels in its main repository, so installing a later kernel couldn’t be simpler:
[shell]
sudo apt-get install linux-image-generic-lts-vivid
[/shell]
This should give you Vivid Vervet’s kernel, which is linux 3.19, and fairly recent. Newer kernels may be available by the time you read this.
As a side note, originally I installed the linux-image-extra-3.16.0-28-generic package directly. This didn’t install the -extra package which has some somewhat important drivers in it. Such as usbhid. Which is required for usb keyboards. Thus, using the meta-package as above (which depends on the right kernel package), can save some hassle.
If your hardware requires any proprietary drivers, be sure to install the headers package as well, as it is required to compile any driver shims:
[shell]
sudo apt-get install linux-headers-generic-lts-vivid
[/shell]
Setting a static IP address
It’s always useful for a server to have a static IP address so that it can be reached reliably, especially when, as in most home networks, there is no local DNS server.
There are a couple of ways to go about it. The easiest, is to set it in your router, if it has the option to manually assign IP addresses. You might need the server’s MAC address which can be found by typing [shell]ifconfig eth0 | grep HWaddr[/shell].
If you do set it on your router you can skip to the next section, but I prefer to set it statically on the server itself. That way my server configuation doesn’t break when I upgrade my wifi router.
In [shell]/etc/network/interfaces[/shell], you should have something that looks like:
[shell]
# The primary network interface
auto eth0
iface eth0 inet dhcp[/shell]
We need to change this to something like:
[shell]auto eth0
iface eth0 inet static
address 192.168.1.10
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameservers 192.168.1.1
[/shell]
Of course, your network settings may be different, substitute for values that are right for your network.
After this, either reboot, or do [shell]ifdown eth0; ifup eth0[/shell], and make sure you can [shell]ping google.com[/shell].
Finally, make sure that your DHCP range doesn’t overlap. Most routers should be able to configure the range DHCP will allocate; make sure you assign static addresses outside that range.
WiFi
This is the first time I’ve configured WiFi by hand, and aside from one driver hassle, it’s far easier than I had ever expected.
My motherboard has a Broadcom BCM4352 chipset, which, annoyingly, requires a proprietary driver. As mentioned earlier, the required driver is broken in 14.04, as detailed here. So the fix was:
[shell]
wget ‘http://gb.archive.ubuntu.com/ubuntu/pool/restricted/b/bcmwl/bcmwl-kernel-source_6.30.223.248+bdcom-0ubuntu1_amd64.deb’ -O /tmp/bcmwl-kernel-source_6.30.223.248+bdcom-0ubuntu1_amd64.deb && dpkg -i /tmp/bcmwl-kernel-source_6.30.223.248+bdcom-0ubuntu1_amd64.deb
[/shell]
After that, setup is similar to the wired lan, except we have to add the wireless options:
In [shell]/etc/network/interfaces[/shell], add:
[shell]
auto wlan0
iface wlan0 inet static
address 192.168.1.11
netmask 255.255.255.0
wpa-ssid CoolNetworkSSID
wpa-psk W1r3le55P4ssw0rD
[/shell]
Obviously, you need to substitute the values for your own network.
One thing you may need to be mindful of is the default gateway. Linux can have multiple default routes, but only one gateway per network. Because my wired and wireless interfaces are on the same network, the gateway is the same, and the route for 192.168.1.1 is held by eth0. If you put your wireless on a separate network and route the wireless traffic, you would have separate gateways and the wifi could effectively act as a backup interface (for outbound connections at least).
But that’s probably going a bit far for this article. Just know that if your network is flat like mine and you want to use wlan0 as your primary interface, you will need to move both the ‘gateway’ and ‘dns-nameservers’ lines from eth0 to wlan0.
Also remember the commands to stop and start an interface:
[shell]
ifup eth0
ifdown eth0
[/shell]
If you need to restart the interface your ssh session is connected to, you can open up a tmux or screen session, and do it in a single command:
[shell]
ifdown eth0; ifup eth0
[/shell]
Email Setup
The ability to send email is a must for any server, as it is usually how we are notified that something is wrong. First install mailutils:
[shell]
apt-get install mailutils
[/shell]
Send a test email message to make sure mail routing is working (substitute your own email address):
[shell]
echo “testing 123” | mail -s ‘test message’ [email protected]
[/shell]
Finally, update /etc/aliases so you get email sent to root:
[shell]
vi /etc/aliases
echo “root: [email protected]” >> /etc/aliases
newaliases
[/shell]
You must run newaliases, as the actual file your MTA will read is /etc/aliases.db, a Berkely-DB hash-table. The newaliases command generates this DB from /etc/aliases.
RAID
Having some form of RAID is a good idea if you want to combine the capacity of multiple hard drives into one. Rarely do home servers need the performance of multiple spindles, and backups are the only way to ensure data security. Thus, RAID simply improves the user experience by showing one big volume, and gives you the chance to purchase a new disk without having to re-copy all your data if one fails. It is most definitely not a substitute for backups, and if you don’t need more capacity than one disk can provide you may want to skip this section.
Originally when building this server, I had planned to use btrfs raid, but my reading since has shown that it is still early days for btrfs raid 5, which is the raid level I wanted to use. You can use it today, but not without some risk – rebuilding only became functional in recent kernels and is not well-tested.
Thus this time around, I went with good old mdadm for the volume management, and a single btrfs partition on it, so I can gain familarity with the tools without jumping in at the deep end.
First, install mdadm and mailutils. We do this, so mdadm can send emails if the volume becomes degraded.
[shell]
apt-get install mdadm smartmontools parted
[/shell]
Next, make sure smart_smartd is set to yes by editing /etc/default/smartmontools, and start smartmon:
[shell]
vi /etc/default/smartmontools
service start smartmontools
[/shell]
Next, we need to prepare the disks for mdadm by creating a partition on them. Technically speaking, you don’t have to do this, as you can use any block device for mdadm. However, replacement devices must be equal to or larger than the capacity of the failed drive. Thus, it is a good idea to create a partition of a known size, slightly less than the maxumum capacity of your disks so you can allow for small differences in drive capacity between models or manufacturers.
With partitions though, alignment is a consideration, as for optimal performance we need to ensure that the raid stripe is on a sector boundary, which is difficult or impossible if the partition itself does not start on a sector boundary.
To create properly aligned partitions, we start parted with “-a optimal” with the first drive as parameter (replace sdX with your drive):
[shell]
parted -a optimal /dev/sdX
[/shell]
In the parted console, create a gpt partition table:
[shell]
(parted) mktable gpt
[/shell]
If you’re happy with being restricted to the same model of hard drive for replacements, create a partition that uses 100% of the disk:
[shell]
(parted) mkpart primary 0% 100%
[/shell]
Otherwise, you’ll want to create a partition that is somewhat smaller than the total (the example below is on a 2TB drive):
[shell]
(parted) unit s
(parted) mkpart primary 2048s 3907026943s
[/shell]
Note that it can be useful to create a 100% partition and then remove it, so you can see sensible values, particularly for the starting sector.
Finally, toggle raid, which just sets a flag to tell linux that the partition is part of a raid array. To be honest I don’t know what this is used for, but it can’t hurt right?!:
[shell]
(parted) toggle 1 raid
[/shell]
Repeat the above for each disk in your raid set.
Now, we create the raid array with the partitions we just created:
[shell]
mdadm –verbose –create /dev/md0 –level=5 –raid-devices=4 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1
[/shell]
Save your configuration to /etc/mdadm/mdadm.conf so that the array is created on startup:
[shell]
mdadm –detail –scan >> /etc/mdadm/mdadm.conf
[/shell]
Here I create a partition on the array, but you can skip this and create a filesystem directly on the /dev/md0 block device if you wish:
[shell]
parted -a optimal /dev/md0
(parted) mktable gpt
(parted) mkpart primary 0% 100%
[/shell]
And finally, create a btrfs filesystem:
[shell]
mkfs.btrfs /dev/md0p1
[/shell]
If you skipped creating a partition on the array, the command would be:
[shell]
mkfs.btrfs /dev/md0
[/shell]
Determine the blkid of your array with blkid, create a mount point, and enter a line into /etc/fstab so that it mounts on boot:
[shell]
mkdir /mnt/md0
echo “$(blkid -o export /dev/md0p1 | grep -E ‘^UUID=’) /mnt/md0 btrfs defaults 0 1” >> /etc/fstab
[/shell]
Network Services
Avahi daemon is a great first install, as it allows autodiscovery of devices on your network:
[shell]
sudo apt-get install avahi-daemon
[/shell]
For file sharing, samba is basically where it’s at these days. On home networks in particular, Microsoft’s SMB protocol has been the defacto standard for many years, so I generally don’t bother with NFS. If you want to use NFS though, do:
[shell]
sudo apt-get install nfs-kernel-server
[/shell]
and have a play with /etc/exports.
SMB support is provided by samba on practically anything that isn’t Windows:
[shell]
sudo apt-get install samba
[/shell]
This time around though, I was lazy. Samba share management is a hassle, and Ajenti does it through a pretty decent GUI:
[shell]
wget http://repo.ajenti.org/debian/key -O- | sudo apt-key add –
sudo echo “deb http://repo.ajenti.org/ng/debian main main ubuntu” >> /etc/apt/sources.list.d/ajenti.list
sudo apt-get update && sudo apt-get install ajenti
[/shell]
For more information on ajenti, checkout ajenti.org. It’s a solid GUI, that doesn’t take over your whole server like other control panels, and is optimised for Debian. I like it, even though I only use it to manage samba.
At some point in the future I may rework this section to detail share configuration (more likely it will be with Ansible or Puppet), but in the meantime please refer to my previous article on the topic.
Kodi
Kodi is to be the GUI of our home server. The idea is that the server is plugged into a TV, and presents the Kodi GUI. We don’t need a window manager, a login screen or anything other than Kodi on this display.
Fortunately, setting up Ubuntu in this way is rather simple.
First, we need a user to run kodi as. Kodi also needs to be in a few groups:
[shell]
adduser kodi –disabled-password –disabled-login
usermod -a -G audio,video,input,dialout,plugdev,tty kodi
[/shell]
Next, we need to make sure that “anybody”, can start X, otherwise our kodi user will not be able to. To do this edit /etc/X11/Xwrapper.config, and set [shell]allowed_users=anybody[/shell].
Note that you can not set “kodi” here, Xwrapper has a set list of options.
We also need an init/upstart script to launch Kodi (this script was found on the kodi wiki):
[shell]
# kodi-upstart
# starts Kodi on startup by using xinit.
# by default runs as kodi, to change edit below.
env USER=kodi
description “Kodi-barebones-upstart-script”
author “Matt Filetto”
start on (filesystem and stopped udevtrigger)
stop on runlevel [016]
# tell upstart to respawn the process if abnormal exit
respawn
script
exec su -c “xinit /usr/bin/kodi-standalone — -nocursor :0” $USER
end script
[/shell]
Wrap-up
This article isn’t quite what I’d hoped it would be, but I hope you have found it useful.
I’ve learned a few things from doing this, chiefly not to throw out everything I’ve learned in my job. In the past I’ve resisted using configuration management tools such as Puppet and Ansible to setup my personal servers, as, what’s the point for a single unique snowflake?! But this time I really regretted it.
Firstly, it provides good documentation for others that may want to do the same, makes rebuilds and upgrades super easy, and allows you to commit your configuration to version control. AL4 Home Server v3 will be a managed affair!
Awesome writeup. I might go this route eventually…one thing holding me back is WMC integration with tv tuners and WMC guide. Do you run live TV and schedule recordings on this server?
Thanks Maksim. By WMC do you mean Windows Media Centre? This is a Linux server with Kodi and doesn’t really bear much in common with a Windows setup.
I don’t do live TV actually, all the content I consume is internet-based these days. With the addition of a TV tuner you could certainly do it – MythTV as the backend with the Kodi PVR plugin would probably be the way to go.
edit: I see what you mean now! Yeah the Windows Guide is a great service. I haven’t used the open source equivalents, but the MythTV community would be a good place to start: https://www.mythtv.org/wiki/Electronic_Program_Guide