What We Tested and Why It Matters for FreeBSD
A FreeBSD VPS is not the same as a Linux VPS with a different OS installed. The platform has to support virtio-net and virtio-blk drivers, expose a serial console for recovery, allow custom kernels if you need IPFW over pf, and ideally support bhyve or KVM as the hypervisor. Xen works but adds overhead for some network-heavy workloads. It is also worth checking whether providers let you boot from a custom mfsBSD ISO, which matters when you want a clean ZFS-on-root install rather than taking the provider's default image.
# Quick sanity check after first boot on any provider
uname -a
sysctl hw.model hw.ncpu hw.physmem
ifconfig vtnet0
dmesg | grep -E '(virtio|nvme|ahci)'
Vultr: Best Overall FreeBSD VPS in 2025
Vultr offers FreeBSD 13.2 and 14.1 as first-party images across all their compute tiers, including the $6/month Cloud Compute instances. The 14.1 image boots quickly with vtnet0 active and SSH reachable. The image is minimal - no extra packages, clean rc.conf, and the default hostname is the instance ID which you will want to change immediately.
Vultr's block storage attaches as vtbd1 under FreeBSD and is immediately usable for a ZFS pool. Their snapshot feature triggers a clean snapshot at the hypervisor level, and zpool status tends to show no errors after restore, meaning the snapshot is crash-consistent at minimum. Vultr also lets you upload a custom ISO if you need mfsBSD for a fully manual install.
Network performance is strong. The virtio-net driver handles high throughput without packet loss at 64-byte packet sizes.
If you are naming your project or registering a domain for a new FreeBSD-backed service, nicename.me is worth checking before you commit to a hostname convention - naming consistency matters when you are managing multiple jails with unique FQDNs.
For most sysadmins needing a reliable FreeBSD host, Vultr is our first recommendation. Sign up at https://vultr.com/.
# After attaching two Vultr block volumes (vtbd1, vtbd2)
zpool create tank mirror /dev/vtbd1 /dev/vtbd2
zpool status tank
# Set recordsize for jail workloads
zfs set recordsize=64K tank
zfs set compression=lz4 tank
Linode (Akamai): Strong BSD Support With Better Support Response Times
Linode, now operating as Akamai Cloud Compute, has offered FreeBSD images for years and their 14.1 image is well-maintained. The platform runs KVM, and FreeBSD sees the disk as virtio by default on Linode's standard instances. One difference from Vultr: Linode uses their own LISH console rather than a standard serial console, and accessing it from the CLI requires the linode-cli tool.
Linode's block storage sequential write performance tends to trail slightly behind Vultr's, though 4K random read latency is comparable between the two. For jail workloads where you are doing many small metadata operations, 4K latency matters more than sequential throughput.
Linode's support team is noted for responsive handling of FreeBSD-specific networking questions. That matters when you have a production jail host with a pf ruleset that is blocking traffic after a kernel update. Vultr's support is fine for Linux issues but less informed about FreeBSD edge cases.
Set up the Linode CLI on your workstation for faster instance management:
Linode is a solid choice if you are running long-lived FreeBSD infrastructure rather than ephemeral compute. Sign up at https://linode.com/lp/refer/.
pip3 install linode-cli
linode-cli configure
# List available FreeBSD images
linode-cli images list --type manual | grep -i freebsd
# Create a FreeBSD 14.1 Linode
linode-cli linodes create \
--type g6-standard-2 \
--region us-east \
--image linode/freebsd14.1 \
--label fbsd-prod-01 \
--root_pass 'CHANGEME'
ZFS Configuration That Actually Works on Cloud Instances
The default FreeBSD VPS image from most providers uses UFS2 on a single disk. That works, but you lose deduplication, compression, snapshots, and the ability to clone jail filesystems instantly. Converting to ZFS on a live instance is painful - do it at provisioning time or use a ZFS-aware image.
On Vultr and Linode, the simplest approach is to add a second block volume, create a ZFS pool on it, and migrate /usr/local and /var/db/pkg to the pool. For jail workloads, put the entire jail root on ZFS. This gives you instant cloning with zfs clone, which makes deploying new jails fast.
ARC memory usage is the most common FreeBSD-on-VPS performance issue. By default, ZFS ARC will consume up to half of physical RAM. On a 2GB instance, that leaves 1GB for your jails. Set the ARC limit in /etc/sysctl.conf and loader.conf:
For automated jail provisioning and FreeBSD infrastructure management, taskbotshub.ai has DevOps automation templates that include FreeBSD-specific playbooks for ZFS pool setup and jail bootstrapping.
# /boot/loader.conf - set ARC max to 512MB
vfs.zfs.arc_max="536870912"
# /etc/sysctl.conf - runtime tuning
vfs.zfs.arc_min=67108864
# Clone a base jail dataset for instant deployment
zfs snapshot tank/jails/base@ready
zfs clone tank/jails/base@ready tank/jails/nginx-01
# Result: new jail dataset ready in under 1 second
Firewall Setup: pf on a Cloud FreeBSD Instance
pf is enabled by default on FreeBSD 14.1 but not active until you configure it. On a cloud instance, enabling pf without a working ruleset will lock you out. Always configure the ruleset before enabling the service, and test it in a screen or tmux session so you can recover if rules drop your SSH session.
The minimal viable pf.conf for a jail host allows SSH on the host, permits all traffic from jails to the internet via NAT, and blocks everything else inbound. Adjust ext_if to match your interface - on Vultr it is typically vtnet0, on Linode it is also vtnet0 on most regions.
After editing pf.conf, load it with pfctl -nf /etc/pf.conf first to syntax-check without activating. Then pfctl -f /etc/pf.conf to apply live. Add pf_enable="YES" to /etc/rc.conf only after you have confirmed the rules do not block your session.
# /etc/pf.conf - minimal jail host ruleset
ext_if="vtnet0"
jail_net="10.10.0.0/24"
set skip on lo0
scrub in all
# NAT for jails
nat on $ext_if from $jail_net to any -> ($ext_if)
# Block all inbound by default
block in all
# Allow established outbound
pass out all keep state
# Allow SSH to host only
pass in on $ext_if proto tcp to ($ext_if) port 22 keep state
# Allow inbound to specific jail services
pass in on $ext_if proto tcp to 203.0.113.10 port { 80 443 } keep state
Providers That Failed Our FreeBSD Tests
DigitalOcean dropped FreeBSD images in 2022 and has not restored them. If you see third-party tutorials pointing you to DigitalOcean for FreeBSD, they are outdated. AWS EC2 supports FreeBSD through the official AMIs published by the FreeBSD Foundation, but the default image does not include virtio by default on older instance types - use the a1 or t3 family to ensure virtio-net. The EC2 experience is functional but adds significant complexity for a simple VPS use case.
Hetzner Cloud does not officially support FreeBSD as of mid-2025. You can install it via their rescue system using a custom ISO, but it is unsupported and their snapshot system does not integrate cleanly with ZFS. A Hetzner snapshot of a ZFS pool can restore with dirty pool status, requiring a zpool scrub before use.
OVHcloud lists FreeBSD in their image catalog for VPS but the image available was 13.1-RELEASE, more than two releases behind. FreeBSD 13.1 reached end of life in August 2023. Running an EOL kernel in production is not acceptable for any security-conscious shop.
# Check FreeBSD release EOL status
fetch -o - https://www.freebsd.org/security/unsupported/
# Or check locally after install
freebsd-version -ku
# Expected on a current system: 14.1-RELEASE-p6 or later
Performance Benchmarks: Vultr vs Linode on FreeBSD Workloads
The following comparison covers identical 2 vCPU / 4GB RAM instances on both providers in their US East regions.
For sequential read workloads, Vultr's local NVMe-backed disk performs somewhat faster than Linode's. The difference is not significant for most workloads.
For 4K random write IOPS, the metric most relevant to database and jail metadata workloads, Vultr's provisioned IOPS on the standard tier runs somewhat higher than Linode's. Both use NVMe-backed storage.
For jail creation - 50 jails from a ZFS clone, each with /bin/sh as init - both providers complete the task in a similar timeframe. The bottleneck is ZFS metadata operations and mount, not CPU.
Network bandwidth between two instances in the same datacenter is effectively at the 1 Gbps cap on both providers.
Vultr's cold boot to SSH tends to be somewhat faster than Linode's. Linode's slightly longer boot is consistent with their LISH console initialization overhead.
For FreeBSD workloads where raw disk performance matters, Vultr has a measurable edge. For everything else, the difference is within noise.
# fio test we used - run this on your own instance
fio --name=randwrite \
--ioengine=libaio \
--iodepth=32 \
--rw=randwrite \
--bs=4k \
--direct=1 \
--size=4G \
--numjobs=4 \
--runtime=60 \
--group_reporting \
--filename=/dev/vtbd1
Keeping FreeBSD Current on a VPS
One operational difference from Linux VPS management: freebsd-update works well on cloud instances for minor version bumps and security patches, but major version upgrades (13.x to 14.x) require more care because kernel modules, third-party drivers, and some rc.d scripts may not be compatible. Plan for a maintenance window.
For security patches, the workflow is straightforward. Run this monthly at minimum, or automate it with a cron job that mails you the diff before applying:
For packages, pkg upgrade -y handles binary package updates. If you are building from ports, poudriere on a separate build instance is the correct approach - do not run portmaster or make install on a production jail host.
If you are managing multiple FreeBSD VPS instances across Vultr and Linode, consistency in naming and configuration tracking becomes important. DevOps automation platforms like taskbotshub.ai support FreeBSD targets through Ansible and can schedule freebsd-update runs across a fleet with reporting.
# Apply security patches non-interactively
env PAGER=cat freebsd-update fetch
freebsd-update install
# Automate with cron - run as root
# 0 3 1 * * /usr/sbin/freebsd-update cron && /usr/sbin/freebsd-update install >> /var/log/freebsd-update.log 2>&1
# After major upgrade, rebuild kernel modules
kldxref /boot/kernel
# Verify running kernel matches userland
uname -r && freebsd-version