Skip to content

Install FreeBSD on a Raspberry Pi 4

  • Raspberry Pi 4
  • Power supply (usb-c 15W 3A 5.1V)
  • MicroSD-card (at least 16GB)
  • MicroSD-card reader
  • Micro-HDMI -> HDMI/DisplayPort cable
  • USB keyboard
  • Disk writing tool (dd or Raspberry Pi Imager)

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

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

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

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.

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
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