NUC home server

6 minute read ,

I recently set up a NUC as a general purpose always-on home server.

Operating System

I chose FreeBSD because I prefer ipfw over iptables.

The primary use case of this server is router & firewall, and FreeBSD excels at this role.

Hardware

The NUC is a dual-core Haswell Core i5 4250, with 8GB DDR3-1600 RAM and a 64GB m.2 Intel SSD.

Multiple NICs

Multiple network interfaces are a must for a firewall.

Intel NUCs only have one built-in Ethernet port, but the model I have has USB 3.0, so I use a j5create USB 3 Gigabit Ethernet adapter for the second interface.

Physical Network

Our house has CAT6 wiring throughout, with RJ-45 jacks in every room.

The lounge has a 1GbE switch, so that TV, PS4, AppleTV and WiFi AP are on wired network.

The office also has a 1GbE switch, so that the NAS, WiFi AP and NUC are also on the wired network, as well as my laptop when I use it in the office.

The garage has a 1GbE switch connected to all of the room RJ-45 jacks.

WiFi Network

The WiFi access points are two Ubiquiti UniFi AC-AP-PRO units, both connected to the wired network, which they use as their uplink.

This works very well, allowing 5Ghz devices to usually maximize utilization of the 200MB fibre link.

When a device gets far enough away from one AP, and is closer to another AP, handover occurs and the device is switched to the other AP.

They are also very stable, and have not required a reboot since setting up two months ago.

The admin user interface supports you doing management and configuration tasks to all APs in one go, which saves time.

If you have switches that support Power-over-Ethernet, you need one less cable to drive these things. If you don’t, they come with adapters, but you will need two Ethernet cables per AP.

Configuration

Reliable Fast Boot

By default, the NUC takes quite a while to boot up. To speed it up, I turned on the Fast Boot feature in the BIOS, which makes it boot up in around 5-15 seconds.

This feature delays USB initialization, which means you can’t use a USB keyboard during boot to go into BIOS again, unless you do some power button incantations.

For headless operation, you need to adjust some settings in the BIOS so it boots up without a keyboard or display attached.

FreeBSD also has a feature where it can delay startup of network services until it is able to successfully ping an IP address. You really want this if the server will be mounting SMB shares on a NAS. This is a simple /etc/rc.conf tweak:

# don't start network services until we have a network.
# USB ethernet takes a while to attach, would happen too
# late if we don't set this to YES, causing SMB mounts to fail.
netwait_enable="YES"
# <IP> should be an address that is accessible via USB ethernet.
netwait_ip="<IP>"

Even with netwait enabled, you probably want to add failok to your SMB mount options if you’re mounting some shares via /etc/fstab because if an fstab mount fails, FreeBSD goes into single user mode by default.

This is my /etc/fstab entry:

//admin@MEDIASTORE/Media        /mnt/media      smbfs   rw,failok,late,-N,-I<IP>

Since mounting an SMB share may require a password, I added the password to /etc/nsmb.conf. Make sure your version of this file is not world readable.

[MEDIASTORE:ADMIN]
password=<XXXX>

Network Interfaces

The ue0 USB ethernet is configured to be the LAN interface.

The em0 onboard ethernet is configured to be the WAN interface, and is connected directly to the ONT.

My ISP Spark does not do fibre by offering up DHCP leases over the WAN connection, it still uses PPPoE, and it requires that the interface used for PPPoE be tagged with VLAN tag 10:

# set it up with an arbitrary IP address
ifconfig_em0="inet 192.168.0.1"
# create a VLAN interface
vlans_em0="em0_10"
# ensure it has VLAN tag 10
create_args_em0_10="vlan 10"

PPPoE configuration

The built-in PPP daemon of FreeBSD is used, configured in /etc/ppp/ppp.conf.

Note that interface em0_10 is used, since it is the one configured with VLAN tag 10. The NAT implemented by PPP is used, and not natd.

default:
 set log Chat Command Connect Filter Phase tun Error Alert
 set mtu max 1492
 set mru max 1492

spark:
 set device PPPoE:em0_10
 set reconnect 3 0
 set authname <ISP-USERNAME>
 set authkey <ISP-PASSWORD>
 set dial
 set login
 set speed sync
 enable lqr
 enable echo
 accept lqr
 add! default HISADDR
 set timeout 0
 enable dns
 nat enable yes
 set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0

It is enabled on boot-up with some entries in /etc/rc.conf.

ppp_enable="YES"
ppp_nat="YES"
ppp_profile="spark"

Services

Gateway

The server is the gateway for the LAN, which is a simple /etc/rc.conf tweak:

gateway_enable="YES"
ipv6_gateway_enable="YES"

Firewall

A hand-rolled default-deny ipfw firewall is used, turned on in /etc/rc.conf with firewall_enable="YES" and firewall_script="/etc/firewall.sh".

The basic ideas of the rules created by /etc/firewall.sh are:

  • Allow all LAN traffic to the firewall/server
  • Allow traffic on already established connections back in
  • Allow outbound traffic from the LAN to anywhere
  • Drop everything else on the floor

DNS/DHCP server

Dnsmasq serves as both the caching DNS server, as well as the DHCP server.

It’s available as a port on FreeBSD, dns/dnsmasq, enabled with dnsmasq_enable="YES" in /etc/rc.conf, and configuration in /usr/local/etc/dnsmasq.conf.

  • All LAN hosts are listed in /etc/hosts, and Dnsmasq is configured to turn /etc/hosts entries into A records, and will suffix them with a configured suffix.
  • CNAMEs are defined in dnsmasq.conf.
  • MAC addresses that should always get the same IP from DHCP are defined in dnsmasq.conf.

It’s a bit tricky to get it to listen only on the specific interfaces you want for DNS, and that interferes with DHCP support, so I rely on ipfw to make sure only LAN clients can talk to Dnsmasq.

Example dnsmasq.conf:

# Use /etc/hosts as list of A records
expand-hosts
# Add suffix .home to names from /etc/hosts
domain=home
# CNAME some-alias.home -> some-hosts-entry.home
cname=some-alias.home,some-hosts-entry
# set up the DHCP IP range
dhcp-range=192.168.1.100,192.168.1.200,12h
# Always give access point IP 192.168.1.2
dhcp-host=80:2a:a8:c0:88:e7,192.168.1.2,12h

Plex Media Server

Plex is used to manage my extensive Linux ISO collection. The FreeBSD port multimedia/plexmediaserver is up to date, and new upstream versions are usually updated in FreeBSD quite quickly.

It’s enabled using plexmediaserver_enable="YES" in /etc/rc.conf.

Once started with service plexmediaserver start, you can use the administration interface at http://<SERVER>:32400/ to set up your libraries and start streaming your ISOs.

Backups

The configuration and important data on the server is backed up using tarsnap, which stores them encrypted in Amazon S3.

The sysutils/tarsnap port was installed, and the default setup instructions followed.

Backups were automated by adding an entry to /etc/crontab.

Make sure you stay on top of keeping your tarsnap account balance well in credit. tarsnap will not automatically charge you if you run out of credit, and they will delete your data if you run out of credit and don’t respond to the two warning emails they send. This is somewhat amusing, given that Stripe uses tarsnap to back up. The service is good enough though that I am willing to live with these eccentricities.

Other settings

Disabling sendmail from starting up.

# disable sendmail
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"

NTP time syncing & SSH

sshd_enable="YES"
ntpd_enable="YES"
ntpd_sync_on_start="YES"