I recently bought an Intel NUC (NUC5i3RYK to be precise). I have equipped it with 8 GB of RAM, but with no storage. My goal is to make the HTPC boot completely over the network using PXE. This should load Kodi (XBMC) and be able to access all shared files located on my file server.

Since I want the network boot and HTPC root filesystem separated from the rest of the network, so that it won’t interfere with my regular DHCP server, I have located them on an separate VLAN. It is also possible to put everything on the same VLAN if you would like to, but then you would need to configure the DHCP server you usually use to point to the TFTP server used for PXE boot.

Server-side

The server needs to provide DHCP address and an TFTP server. It also provides the root system for the Linux installation on which Kodi runs. The root filesystem is mounted over NFS. The server itself runs FreeBSD. I will use dnsmasq to provide both DHCP and TFTP. I believe this is easier than running separate daemons for both services.

dnsmasq

Install dns/dnsmasq from ports. Ensure that the system it is running on has a static IP address, and runs dnsmasq on boot, fixed by setting e.g:
ifconfig_xn0="inet 10.0.8.254 netmask 255.255.255.0"
dnsmasq_enable="YES"

in /etc/rc.conf

Now we need to configure dnsmasq to provide both DHCP and TFTP services. I use the following configuration file:

# Accept DNS queries only from hosts whose address is on a local
# subnet, ie a subnet for which an interface exists on the server.
# This option only has effect if there are no --interface
# --except-interface, --listen-address or --auth-server options.
local-service

# Uncomment this to enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to
# repeat this for each network on which you want to supply DHCP
# service.
dhcp-range=10.0.8.50,10.0.8.99,12h

# Override the default route supplied by dnsmasq and send no default
# route at all. Note that this only works for the options sent by
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
# for all other option numbers.
dhcp-option=3

# Set the boot filename for netboot/PXE. You will only need
# this is you want to boot machines over the network and you will need
# a TFTP server; either dnsmasq's built in TFTP server or an
# external one. (See below for how to enable the TFTP server.)
dhcp-boot=/pxelinux.0

# NFS mountpoint
dhcp-option=option:root-path,/htpc/

# Enable dnsmasq's built-in TFTP server
enable-tftp

# Set the root directory for files available via FTP.
tftp-root=/htpc/boot

As you can see, /htpc will be used as the root of our PXE-served Linux installation.

NFS server

I export the /htpc directory over NFS using the following /etc/exports configuration:
/htpc   -maproot=root   -network 10.0.8.0 -mask 255.255.255.0

and enable the NFS server by appending this to /etc/rc.conf

rpcbind_enable="YES"
nfs_server_enable="YES"
mountd_flags="-r"

We must allow clients to mount the filesystem with root rights (the -maproot option fixes this).

Preparing the NFS root directory with a Linux installation

The /htpc directory must be filled with some interesting contents to actually boot a system.

I want my HTPC to run Kodi, and I initially planned to use OpenELEC for simplicity. However, OpenELEC does not support the use of NFSv4 mounts, and since my file server is only configured to serve media over a kerberized NFSv4 mount, I had to abandon the idea of OpenELEC, and instead use my own setup. I based this on Arch Linux.

Following the guide for Diskless systems from the Arch wiki [1], we see that we must initialize the base system in our /htpc directory. Since this directory is located on a FreeBSD system, it is a bit tricky to do just by following the instructions as written on the wiki. However, since my desktop uses Arch Linux, I solved this by mounting the NFS share on my desktop computer, and proceeded according to the instructions on the wiki after this:

# mount -t nfs -o hard,nolock server:/htpc /htpc
# pacstrap -d /htpc base mkinitcpio-nfs-utils nfs-utils

This prepares an Arch Linux installation in the /htpc directory on the NFS server. The initramfs must be generated to support an NFS root. Ensure that /htpc/etc/mkinitcpio.conf has the following lines:

MODULES="nfs e1000 e1000e"
BINARIES="/usr/bin/mount.nfs"
HOOKS="base udev autodetect modconf block net filesystems keyboard fsck"

I used the module e1000e to match my network card, otherwise the NFS root mount will fail. Adapt this to your own network adapter. If you want to try to boot in VirtualBox before actually booting on the NUC, you need e1000. Then regenerate the initramfs by calling:

# arch-chroot /htpc mkinitcpio -p linux

I proceeded with setting the hostname, locale, timezone, etc. as usual in an Arch Linux installation. Check the Installation guide [2] on the wiki for this.

Next it is time to setup the bootloader. I will use PXELINUX. From my desktop system, I copied the PXELINUX files to the NFS mount.

# cp /usr/lib/syslinux/bios/pxelinux.0 /htpc/boot
# cp /usr/lib/syslinux/bios/ldlinux.c32 /htpc/boot
# mkdir /htpc/boot/pxelinux.cfg

I then proceed by creating the /htpc/boot/pxelinux.cfg/default configuration file:

default linux

label linux
kernel vmlinuz-linux net.ifnames=0
append initrd=initramfs-linux.img quiet ip=:::::eth0:dhcp nfsroot=10.0.8.254:/htpc

The base system is now ready, and should be able to boot over PXE! The kernel parameter net.ifnames=0 was added to avoid network device renaming on boot. This interfered with my NFS root and VLANs, you may not need it.

Further configuration of the Linux installation

You may skip this section if you have an ordinary system. It covers other stuff relevant for my own case, e.g. creating new interfaces for my other VLANs.

This contains some final steps required for my specific setup. Since I just mounted the root filesystem on a specific VLAN, I want to mount my ordinary file server from my default VLAN. This is done by creating a new network interface with the correct VLAN.

I use the following netctl configuration file for Arch Linux in /etc/netctl/regular0-vlan

Description='Regular VLAN on interface eth0'
Interface=regular0
Connection=vlan
# The variable name is plural, but needs precisely one interface
BindsToInterfaces=eth0
VLANID=1
IP=dhcp

and I then enabled the profile by using

# netctl enable regular0-vlan

To mount my NFS file server on boot I use the systemd automounter and include the following line in my fstab.

file.server.host:/media		/mnt/media			nfs4		users,noauto,x-systemd.automount,x-systemd.device-timeout=10,timeo=14,noatime,nfsvers=4,sec=krb5,soft		0 0

In addition, the usual NFS Client configuration from [3] is required.

Installation of Kodi and related stuff

We begin by installing the Intel graphics drivers.
# pacman -S xf86-video-intel mesa-libgl libva-intel-driver libva mesa xorg-xinit xorg-server udisks upower polkit

Now to the fun part, we want to install Kodi and have it to start automatically.

# pacman -S kodi unrar unzip libcec

Also install kodi-standalone-service from the AUR. Enable and start the service with

# systemctl enable kodi.service

To be able to shutdown the computer from within Kodi, add the user to the power and storage groups. If you want to use a HDMI-CEC adapter such as [4], you also need to add the kodi user to the groups uucp and lock.

# gpasswd -a kodi power
# gpasswd -a kodi storage
# gpasswd -a kodi uucp
# gpasswd -a kodi lock

Reboot your NUC, and Kodi will start just as expected!

References

[1] https://wiki.archlinux.org/index.php/Diskless_system

[2] https://wiki.archlinux.org/index.php/Installation_guide

[3] https://wiki.archlinux.org/index.php/NFS#Client

[4] http://www.pulse-eight.com/store/products/104-usb-hdmi-cec-adapter.aspx