Published: in Videos
How to Install FreeBSD 15 on a Hetzner VPS (and Secure It with PF + SSH Keys)
Hetzner Cloud does not offer FreeBSD as a one-click operating system in the standard installer, but you can still install it cleanly using Hetzner’s ISO mounting feature. This guide walks through a straightforward FreeBSD 15 install (as current at the time of recording: 13 January 2026), then covers a sensible baseline hardening: system updates, a simple PF firewall, and SSH key-only access.
A video walkthrough accompanies this guide and will be linked here once it is available. The full written steps and commands are provided below.
What you will achieve
By the end, you will have:
-
FreeBSD 15 installed on a Hetzner Cloud VPS
-
Updates applied via
freebsd-updateandpkg -
PF enabled with a basic “default deny inbound” ruleset
-
SSH configured for key-based login, with password auth disabled
1) Create a Hetzner VPS (any OS is fine initially)
-
Log in to the Hetzner Cloud Console.
-
Create a new Project (optional, but useful for organising servers).
-
Create a new Server:
-
Choose a size (the demo uses a small instance such as CX23).
-
Choose a location (any is fine).
-
For Image / OS, pick something temporary (for example Debian).
This choice does not matter because you will replace it.
-
Once created, note the server’s public IP.
2) Mount the FreeBSD ISO and boot from it
-
Open your server in the Hetzner Cloud Console.
-
Go to ISO Images.
-
Search for FreeBSD.
-
Select the FreeBSD 15 ISO and mount it to the server.
-
Go to Power and perform a Reset / Power cycle.
-
Open the Console view. You should see the server boot into the FreeBSD installer.
3) Install FreeBSD 15 from the console
In the FreeBSD installer:
-
Select Install.
-
Keymap: choose English (United Kingdom) (or your preference).
-
Set a hostname (for example
youtube-demo).
Base system method
The installer may ask whether to install using traditional distribution sets or packages. In the video, traditional distribution sets were chosen because the packages option was marked as “tech preview” at the time.
-
Choose Distribution Sets and proceed with defaults.
Network download prompt
Depending on the ISO type, the installer may not have all sets available on the boot media and will prompt to download them.
-
Select the network interface (typically
vtnet0on Hetzner VPS). -
Use DHCP so it can fetch required sets.
Disk layout (ZFS)
-
Choose Auto (ZFS).
-
With a single disk, choose Stripe.
-
Set swap as preferred (the demo uses 8 GB swap on a 4 GB RAM system; adjust to your needs).
-
Encryption is optional. If you enable encryption on a remote VPS, remember you will need console access after reboot to unlock it.
Proceed with the installation, then:
-
Set a root password
-
Set timezone to Europe → United Kingdom
-
Enable ntpd (recommended so time is correct after boot)
-
Optionally enable “secure console” style settings if prompted (useful hardening defaults)
Create a non-root user during install if you want (recommended).
When finished:
-
Choose Reboot
-
Back in Hetzner, unmount the ISO (otherwise it may boot the installer again)
-
If needed, power cycle once more
At this point FreeBSD should boot from disk and display the server’s IP in the console.
4) First login and system updates
SSH to the server using either root or your created user (depending on what you configured).
Then apply base system updates:
freebsd-update fetch
freebsd-update install
Update packages:
pkg update
pkg upgrade
Quarterly vs Latest repositories
FreeBSD packages typically offer quarterly (more conservative/stable) and latest (newer). The demo stays on quarterly for stability.
5) Enable PF and apply a basic firewall ruleset
Before you start: the fastest way to lock yourself out of a remote server is to apply firewall rules without testing. Hetzner console access is your safety net, but you should still test PF rules before loading them.
Install an editor (optional)
pkg install neovim
Create /etc/pf.conf
Start with a simple, readable ruleset. This example:
-
Skips filtering on loopback
-
Blocks all inbound traffic on the public interface
-
Allows SSH in (preferably only from your own IP)
-
Allows outbound traffic
Edit the file:
nvim /etc/pf.conf
Example pf.conf:
ext_if = "vtnet0"
my_ssh_ip = "YOUR.PUBLIC.IP.ADDRESS" # replace with your IP
set skip on lo0
block in on $ext_if
pass in quick on $ext_if inet proto tcp from $my_ssh_ip to ($ext_if) port ssh
pass out on $ext_if from any to any
Notes:
-
Replace
YOUR.PUBLIC.IP.ADDRESSwith the public IP you will SSH from. -
If your IP changes frequently, you may temporarily use
from anyto confirm everything works, then tighten it afterwards. -
If you do not want inbound IPv6 at all, do not add an IPv6 SSH pass rule. Keep it explicit.
Test the rules before loading them
Always test:
pfctl -nf /etc/pf.conf
If the syntax check passes, load the rules:
pfctl -f /etc/pf.conf
Enable PF at boot and start it
Add PF enablement to /etc/rc.conf:
sysrc pf_enable="YES"
service pf start
Confirm active rules:
pfctl -s rules
If you make a mistake and lose access, use the Hetzner console to log in and fix /etc/pf.conf, then re-test and reload.
6) Set up SSH keys and disable password logins
Generate an SSH key (on your local machine)
If you do not already have a key:
ssh-keygen -t ed25519
Copy your key to the FreeBSD server
If you have ssh-copy-id available on your workstation, you can use it. If not, the reliable universal method is:
cat ~/.ssh/id_ed25519.pub | ssh youruser@your.server.ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Test that you can log in using your key in a new terminal before changing SSH settings.
Disable password authentication
Edit the SSH daemon config:
nvim /etc/ssh/sshd_config
Set or add:
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
(Leave PubkeyAuthentication yes as-is if already present.)
Restart SSH:
service sshd restart
Confirm you can still log in with your key from a fresh session. Once confirmed, password logins should fail and the server will only accept key-based authentication.
Summary
Installing FreeBSD on Hetzner Cloud is straightforward once you know the approach:
-
Create a VPS with any OS
-
Mount the FreeBSD ISO and reboot into it
-
Install with ZFS and network set downloads
-
Update the base system and packages
-
Enable PF with a minimal “deny inbound, allow SSH” ruleset
-
Enforce SSH keys and disable password authentication
This gives you a clean FreeBSD baseline suitable for building services on top, such as a self-hosted VPN, bastion host, or lightweight infrastructure tooling.
If you want, I can also produce a follow-up post in the same style for:
-
A hardened PF ruleset (stateful rules, logging, rate limiting, IPv6 stance)
-
Setting up WireGuard on FreeBSD 15 on Hetzner
-
Fail2ban alternatives on FreeBSD (or sshguard) and basic monitoring baseline