Installing FreeBSD 15 on any VPS

2026-05-29 - With encrypted root on ZFS
Tags: FreeBSD QEMU

Introduction

Not many Virtual Private Server (VPS) providers consider FreeBSD a first-class citizen, and few encourage you to encrypt your hard drive from inside the VPS.

Though encrypting a VPS hard drive does not protect against everything and requires one to access the web KVM of the provider to type in a password on each reboot, I still find it reassuring.

You need a little know-how to be able to set up FreeBSD in a not so friendly environment. There are several procedures to achieve this floating around the Internet, but I found those either too complicated or out of date. This article presents my preferred way to install a FreeBSD operating system on a provider that does not officially support it, and it works even for other unsupported operating systems.

Install a Linux system to inspect the pre-provisioned VPS

Depending on your provider, you will want to prepare either a BIOS boot image (for example at OVH) or a UEFI boot image (for example on Azure or on Oracle Cloud). One way to find out which one is to install any Linux image supported by your provider and run:

dmesg | grep -i "efi:"

If you see lines like the following, then you need to prepare a UEFI boot image. Otherwise, prepare a BIOS boot image:

[    0.000000] efi: EFI v2.7 by EDK II
[    0.000000] efi: SMBIOS=0xbbea9000 ACPI=0xbbf9c000 ACPI 2.0=0xbbf9c014 MEMATTR=0xba639518 MOKvar=0xbbe97000

Bootstrap the FreeBSD installer on a local virtual machine

Create the RAW hard drive image for your virtual machine. Using the minimal necessary size will speed up the later image transfer. At the time of this writing, FreeBSD bootstraps fine on 1.6G of storage:

qemu-img create -f raw freebsd.raw 1600M

Download the installer image from an official mirror then start up the installer in the virtual machine.

I start a BIOS booted virtual machine with something like:

qemu-system-x86_64 \
    -drive if=none,id=disk,file=$PWD/freebsd.raw,format=raw,cache=writeback \
    -cdrom $HOME/Downloads/FreeBSD-15.0-RELEASE-amd64-bootonly.iso \
    -boot d -machine type=q35,accel=kvm \
    -cpu host -smp 2 -m 4096 \
    -nic user,model=virtio-net-pci,hostfwd=tcp::10022-:22 \
    -device virtio-blk-pci,drive=disk \
    -device virtio-serial-pci \
    -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 \
    -vga qxl -spice port=5902,addr=127.0.0.1,disable-ticketing=on \
    -chardev spicevmc,id=spicechannel0,name=vdagent

To boot in UEFI mode instead, add the following line somewhere in the middle. You might need to install another package and customize the path on your system, this one is for Gentoo:

    -bios /usr/share/edk2/OvmfX64/OVMF_CODE.fd \

If you are short on memory, tune down the -m 4096 flag that configures the amount allocated to the virtual machine.

This virtual machine starts up with a SPICE display device, which I like better than VNC, and can be accessed with a SPICE client like spicy. If you would rather use VNC instead, replace the lines mentioning SPICE with the following to start a VNC server on port 5900:

    -display vnc 127.0.0.1:0 \
    -vga none -device virtio-vga,edid=on,xres=2560,yres=1440

Install FreeBSD

Proceed to install FreeBSD as you normally would. I personally switched to pkgbase instead of the venerable distribution sets and am very happy with this choice. For simple host setups like this with only one drive, I use the auto ZFS partitioning mode. Make sure to choose the correct Partitioning Scheme and to encrypt your disks if you wish to. I also disable swap at this point.

To type in passwords, either for disk encryption or for the root and user accounts, the SPICE or VNC GUI can be unwieldy. When it is time for a password prompt, I like to use xdotool to simulate the keyboard inputs, bypassing the fact that copy/paste is not functional:

read -rs pass
sleep 2; xdotool type -- "$pass"
unset pass

After pressing Enter to execute this command, I have two seconds to switch to the SPICE or VNC window before the password is typed for me.

Once the installation is complete, shut down the virtual machine.

Prepare the network configuration

Restart the virtual machine on the newly installed system by setting the boot device to c and removing the ISO image flags. Make sure to keep the UEFI setting if you need it!

qemu-system-x86_64 \
    -drive if=none,id=disk,file=$PWD/freebsd.raw,format=raw,cache=writeback \
    -boot c -machine type=q35,accel=kvm \
    -cpu host -smp 2 -m 4096 \
    -nic user,model=virtio-net-pci,hostfwd=tcp::10022-:22 \
    -device virtio-blk-pci,drive=disk \
    -device virtio-serial-pci \
    -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 \
    -vga qxl -spice port=5902,addr=127.0.0.1,disable-ticketing=on \
    -chardev spicevmc,id=spicechannel0,name=vdagent

Log in as root, then edit your /etc/rc.conf. You likely used DHCP for the installation, but for most providers this needs to be customized for FreeBSD (in particular if you want IPv6). I found that there are no general rules here: the best indicator is to install a Linux system supported by your VPS provider and inspect the pre-provisioned configuration.

For example on an OVH VPS, I set everything statically in a /etc/start_if.vtnet0:

ifconfig vtnet0 inet 37.187.244.19/32
route -4 add 37.187.244.1/32 -interface vtnet0
route -4 add default 37.187.244.1
ifconfig vtnet0 inet6 2001:41d0:401:3100::fd5/64
route -6 add default 2001:41d0:401:3100::1

But on Oracle Cloud Infrastructure, I use something like:

ifconfig vtnet0 inet 10.0.0.62/24
route -4 add default 10.0.0.1
ifconfig vtnet0 inet6 2603:c022:c002:8500:e2a4:f02e:43b0:c1d8/64 accept_rtadv

You will have to figure out what you need based on the provider you chose.

Boot the VPS in rescue mode and transfer the disk image

Most VPS providers offer a rescue mode that will boot your server on a Linux image with diagnostic tooling. If yours does not offer that capability, maybe you can do something similar by creating a second Linux server and attaching the boot disk of the first one to it (that’s what I did to get my FreeBSD image to Oracle Cloud).

Whatever way you proceed, your first step is to identify what the /dev path of the target block device is with blkid and fdisk -l. I will use /dev/sdb as an example. Make sure your disk is not mounted anywhere (rescue modes love to do that).

Once ready, completely erase your disk with blkdiscard /dev/sdb. If blkdiscard is unsupported for some reason, you can skip it. Then copy over your raw image. I usually copy it in place with a command like the following (replace myth.adyxax.org with your actual server address):

dd if="$PWD/freebsd.raw" | ssh root@myth.adyxax.org dd of=/dev/sdb

First boot

Once the image has finished transferring, you should be able to disable rescue mode (or shut down the temporary installation instance and reattach the boot disk to your original instance if you went that route). Reboot your server to enjoy your new FreeBSD system!

If you chose full disk encryption, or if anything goes wrong and you need to debug the boot process, then the web KVM of your provider will be your best friend.

Resizing the root disk

I deliberately set up a very small virtual disk as to speed up transfer of the resulting image. After booting into the new system, we will want to make use of the full storage space allocated to the instance. When using FreeBSD with root on ZFS, I first inspect the storage layout with these two commands:

# gpart show -p
=>      40  41942960    da0  GPT  (20G)
        40      1024  da0p1  freebsd-boot  (512K)
      1064       984         - free -  (492K)
      2048  41940952  da0p2  freebsd-zfs  (20G)

# zpool status -P
  pool: zroot
 state: ONLINE
config:
	NAME              STATE     READ WRITE CKSUM
	zroot             ONLINE       0     0     0
	  /dev/da0p2.eli  ONLINE       0     0     0

I then do the resizing with something like:

gpart recover da0
gpart resize -i 2 da0
geli resize /dev/da0p2
zpool online -e zroot /dev/da0p2.eli

Conclusion

This method has served me well for years, and I am glad I finally took the time to write the FreeBSD version of these instructions for future reference.