6 min read

Setting up a Raspberry Pi 4 router with FreeBSD

Install

Prelude

I have had a Raspberry Pi 4 that have just been sitting in a box, more or less untouched. I had this plan of creating a little cluster of these and use as some kind of little homelab. But that never happened and it was forgotten in the closet. But now it’s use will be as a little router powering my home network, running a few services and acting as a firewall.

End goal

Setup a Raspberry Pi 4 (4gb) as a router, running FreeBSD and some small various services like an adblocker for the network.

Prerequisites

  • Raspberry Pi 4
  • Power Adapter
  • microSD card
  • microHDMI -> HDMI cable
  • USB 3.0 Ethernet adapters

Instructions

$ infront of a command means you can do it as non-root.

# infront of a command means you have to do it with root privileges

All the config files can be found on codeberg

Preparing the microSD card

Start with downloading the image from the FreeBSD website, the version as of writing this is 15.0.

Extract the img file, find the name of our USB drive and write the image to it.

Shell
$ xz -d FreeBSD-15.0-RELEASE-arm64-aarch64-RPI.img.xz
$ ls -l /dev/disk/by-id/usb-*
# dd if=path/to/FreeBSD-15.0-RELEASE-arm64-aarch64-RPI.img of=/dev/disk/by-id/usb-Name_of_your_Flash_drive bs=4M conv=fsync oflag=direct status=progress

Mount the USB-drive.

To be able to get anything on my monitor when booting the Raspberry Pi, i had to add these settings to /boot/msdos/config.txt 1 on the usb drive.

/boot/msdos/config.txt
max_framebuffers=2
hdmi_safe=0
hdmi_force_hotplug=1
hdmi_group=1
hdmi_drive=2
hdmi_mode=16

Booting up

After we are all done with the microSD card. We can now attach all the cables, a keyboard and boot up the Raspberry Pi. When the booting sequence is finished, you will find yourself with a login screen. There are two default users with username/password: root/root and freebsd/freebsd.

Log in as root.

Changing keymap to another one if needed, available ones are located at /usr/share/vt/keymaps/

Shell
# sysrc keymap="se.kbd"

Change password for root and freebsd user.

Shell
# passwd
# passwd freebsd

Add a user, add them to the wheel group

Shell
# adduser

My clock on the Raspberry Pi was not correct and that made all kind of trouble trying to connect to servers using TLS, we fix this by setting the tzdata and enabling ntpd.

Shell
# tzsetup
# sysrc ntpd_enable=yes
# sysrc ntpd_sync_on_start="YES"
# service ntpd start

Now would be a good time to update our system.

Shell
# freebsd-update fetch
# freebsd-update install

Instead of being logged in as root, we add doas to be able to perform actions as root. And since our user was added to the wheel group, we can now perform actions as root.

Terminal window
# pkg install doas

Setting up SSH

We will setup SSH to log onto the server instead of having to connect keyboard and a monitor.

Shell
# sysrc sshd_enable="YES"
# service sshd start

And we need to add our ssh key to the server

Shell
scp ~/.ssh/id_ed25519.pub username@server:~/

Shell
$ mkdir -p ~/.ssh
$ cat ~/id_ed25519.pub >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys
$ chmod 700 ~/.ssh
$ rm ~/id_ed2519.pub

And we will make some changes to the sshd config file.

/etc/ssh/sshd_config
Port 20022 # Default port is 22, change it to something else.
LoginGraceTime 60 # Default time is 2m, a little more hardening by lowering it to 60 seconds
PermitRootLogin no # We never want root to able to login directly
PubkeyAuthentication yes # Use ssh keys for authentication
PasswordAuthentication no # Passwords are not allowed for authentication

Restart the sshd service

Shell
# service sshd reload

Now we can login to the server using ssh!

Shell
$ ssh username@server -p 20022

Making a router

With the basics of our FreeBSD server set up, it’s time to make it into a router! I have bought these D-Link USB 3.0 Ethernet adapters and will be attaching two of them to the USB 3.0 ports. This is not enough ports for a router normally, but at the moment i only have one desktop and one server so it should be sufficient enough. In the future, if there is a rack in the homelab i will add a dedicated router.

To be sure there won’t be any connection issues while doing the routing configuration, we should do this without using SSH.

Setting up the Firewall & DHCP

We start with adding the USB adapters and checking what network interfaces we have available. I have 3:

  • genet0: ethernet input
  • ue0: ethernet usb adapter output
  • ue1: ethernet usb adapter output
Shell
$ ifconfig

So now we will write some config to set up our little network.

/etc/rc.conf
# WAN
ifconfig_genet0="DHCP"
# USB Ethernet interfaces
ifconfig_ue0="up"
ifconfig_ue1="up"
# Bridge interface
cloned_interfaces="bridge0"
ifconfig_bridge0="inet 192.168.10.1 netmask 255.255.255.0 addm ue0 addm ue1 up"
# Enable routing
gateway_enable="YES"
# PF firewall
pf_enable="YES"
pf_rules="/etc/pf.conf"
# DHCP server on the bridge interface
dhcpd_enable="YES"
dhcpd_ifaces="bridge0"

/etc/pf.conf
#### INTERFACES ####
wan = "genet0"
lan = "bridge0"
#### NETWORKS ####
lan_net = "192.168.10.0/24"
set block-policy drop
set skip on lo
scrub in all
nat on $wan from $lan_net to any -> ($wan)
# Default deny inbound from WAN
block in all
# Allow outbound
pass out all keep state
#### ALLOW LAN -> ANYWHERE ####
pass in on $lan from $lan_net to any keep state
#### ALLOW LAN -> ROUTER (SSH + ICMP) ####
pass in on $lan proto tcp from any to $lan port { 20022 }
#### ALLOW ESTABLISHED / RELATED ####
pass in quick proto tcp from any to any flags S/SA keep state
#### ALLOW DHCP ####
pass in on $lan proto udp from port 68 to port 67
pass out on $lan proto udp from port 67 to port 68

/usr/local/etc/dhcpd.conf
default-lease-time 600;
max-lease-time 7200;
authoritative;
option domain-name-servers 9.9.9.9, 1.1.1.1;
subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.100 192.168.10.200;
option routers 192.168.10.1;
option subnet-mask 255.255.255.0;
}

/boot/loader.conf
if_bridge_load="YES"

/etc/sysctl.conf
net.link.bridge.pfil_bridge=1
net.link.bridge.pfil_member=0

Enabling it all

Shell
# kldload if_bridge
# sysctl net.link.bridge.pfil_bridge=1
# sysctl net.link.bridge.pfil_member=0
# sysctl net.inet.ip.forwarding 1
# service netif restart
# service routing restart
# service pf restart
# service dhcpd restart

And there we have it. It’s a basic configuration of a Raspberry Pi 4 as a router for our homelab. We should now be able to connect our different devices to the ethernet ports of the Raspberry Pi and get a working network connection.

1 FreeBSD Wiki Raspberry Pi 4