<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><title>IT Notes - bhyve</title><link>https://it-notes.dragas.net/categories/bhyve/</link><description>Articles in category bhyve</description><language>en</language><lastBuildDate>Fri, 19 Sep 2025 10:50:00 +0200</lastBuildDate><atom:link href="https://it-notes.dragas.net/categories/bhyve/feed.xml" rel="self" type="application/rss+xml"></atom:link><item><title>FreeBSD vs. SmartOS: Who's Faster for Jails, Zones, and bhyve VMs?</title><link>https://it-notes.dragas.net/2025/09/19/freebsd-vs-smartos-whos-faster-for-jails-zones-bhyve/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/server_rack.webp" alt="A server rack with some servers and cables"&gt;&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;br /&gt;
These benchmarks were performed on my specific hardware and tuned for the workloads I expect to run.&lt;br /&gt;
They should not be taken as absolute or universally applicable results.&lt;br /&gt;
Different CPUs, storage, networking setups, or workload profiles could produce very different outcomes.&lt;br /&gt;
What I’m sharing here is a faithful snapshot of &lt;em&gt;my&lt;/em&gt; test environment and use case - a guidepost, not a final verdict.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Years ago, I installed a PCEngines APU at a client's site. It dutifully ran Proxmox with a few small VMs inside. It wasn't a speed demon, but it got the job done. Tasked with running in a closed, uncooled, and unsupervised server closet, it soldiered on for about seven years.&lt;/p&gt;
&lt;p&gt;Then, while I was at BSDCan, I got the call. A series of power outages and surges had finally taken their toll, and the APU was dead. It was probably just the power supply, but given its age, we decided it was time for a replacement. I set up a remote bypass to keep them running, but I knew I'd need to install something more powerful soon.&lt;/p&gt;
&lt;p&gt;I ordered a modern MiniPC-based on the low-power Intel Processor N150 platform, but with 16GB of RAM and more than enough performance to serve as a decent workstation. I have a similar one in my office running openSUSE Tumbleweed, and it works beautifully.&lt;/p&gt;
&lt;p&gt;This time, however, I decided to replace Proxmox with a different virtualization system. This decision wasn't made in a vacuum. In the past, I've put bhyve head-to-head with Proxmox, and my findings were clear: &lt;strong&gt;bhyve on FreeBSD is an extremely efficient hypervisor, &lt;a href="https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/"&gt;often outperforming KVM on Proxmox in my tests&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This positive experience is what made FreeBSD with bhyve a top contender. The other path was a KVM-style approach (which would require fewer changes to the VMs), where my options would be NetBSD or an &lt;a href="https://www.illumos.org/"&gt;illumos-based&lt;/a&gt; OS like &lt;a href="https://www.tritondatacenter.com/smartos"&gt;SmartOS&lt;/a&gt;. Since I had the new hardware on hand, I decided to run some tests to see how these different technologies stacked up against each other, and against the bare metal itself.&lt;/p&gt;
&lt;h3&gt;The Lineup: What I Put on the Test Bench&lt;/h3&gt;
&lt;p&gt;My goal was to test every reasonable option on this Intel N150 hardware. The final lineup covered the entire spectrum:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Baseline:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FreeBSD 14.3-RELEASE Bare Metal:&lt;/strong&gt; The ground truth for performance on this hardware.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OS-Level Virtualization (Containers):&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SmartOS Native Zone:&lt;/strong&gt; The baseline native container on SmartOS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SmartOS LX Zone:&lt;/strong&gt; Running &lt;strong&gt;Ubuntu 24.04&lt;/strong&gt; and &lt;strong&gt;Alpine Linux&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FreeBSD Native Jail:&lt;/strong&gt; The baseline native container on FreeBSD.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FreeBSD Jail with Linux:&lt;/strong&gt; A jail running a &lt;strong&gt;Ubuntu 22.04&lt;/strong&gt; userland.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full Hardware Virtualization (HVM):&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SmartOS bhyve Zone:&lt;/strong&gt; A FreeBSD guest inside the bhyve hypervisor on a SmartOS host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SmartOS KVM Zone:&lt;/strong&gt; A FreeBSD guest inside the KVM hypervisor on a SmartOS host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FreeBSD bhyve VM:&lt;/strong&gt; A FreeBSD guest inside the bhyve hypervisor on a FreeBSD host.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Benchmark: My &lt;code&gt;sysbench&lt;/code&gt; Commands&lt;/h3&gt;
&lt;p&gt;To keep the comparison fair and simple, I used two core &lt;code&gt;sysbench&lt;/code&gt; commands. To ensure consistency, I even compiled &lt;code&gt;sysbench&lt;/code&gt; from scratch on the SmartOS native zone to match the versions and compile options on the other systems as closely as possible.&lt;/p&gt;
&lt;p&gt;The commands I used in each environment were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For CPU performance:&lt;/strong&gt; &lt;code&gt;sysbench --test=cpu --cpu-max-prime=20000 run&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For memory performance:&lt;/strong&gt; &lt;code&gt;sysbench --test=memory run&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;First Look: CPU and Memory on the Intel N150&lt;/h3&gt;
&lt;p&gt;My initial tests on the Intel N150 hardware immediately revealed some interesting trends. The &lt;code&gt;sysbench&lt;/code&gt; CPU results from any native FreeBSD environment (bare metal or jail) were on a completely different scale from the Linux and SmartOS guests, making a direct comparison meaningless.&lt;/p&gt;
&lt;p&gt;However, by excluding the incompatible FreeBSD-native results, we get a very clear picture of the overhead between the various container technologies.&lt;/p&gt;
&lt;h4&gt;Valid CPU Performance Comparison (Single Thread, Intel N150)&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Host OS&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Container Tech&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Guest OS&lt;/th&gt;
&lt;th style="text-align: left;"&gt;CPU Performance (Events/sec)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FreeBSD&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jail (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ubuntu 22.04&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;1108.18&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;SmartOS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;LX Zone (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ubuntu 24.04&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1107.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;SmartOS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Native Zone (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;SmartOS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1107.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;SmartOS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;LX Zone (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Alpine Linux&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1022.81&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The takeaway here was clear: for CPU work, the overhead from these containers is basically a rounding error. For CPU-bound tasks, neither SmartOS Zones nor FreeBSD Jails will be a bottleneck.&lt;/p&gt;
&lt;p&gt;The memory results, which were consistent across all platforms, were far more revealing.&lt;/p&gt;
&lt;h4&gt;Overall Memory Performance Comparison (Intel Processor N150)&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Host OS&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Virtualization Tech&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Guest OS&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Memory Performance (Transfer Rate)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;SmartOS&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;LX Zone (OS-level)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Ubuntu 24.04&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;4970.54 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;SmartOS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Native Zone (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;SmartOS (Native)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4549.97 MiB/sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FreeBSD&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jail (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ubuntu 22.04&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4348.32 MiB/sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Bare Metal&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD (Native)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;4005.08 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FreeBSD&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Native Jail (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;FreeBSD (Native)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3990.13 MiB/sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;SmartOS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;LX Zone (OS-level)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Alpine Linux&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3803.72 MiB/sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;bhyve VM (Full HVM)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;3636.01 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;SmartOS&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;bhyve Zone (Full HVM)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;3020.15 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;SmartOS&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;KVM Zone (Full HVM)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;205.18 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These initial numbers led to a few conclusions: a virtual layer could be a performance boost, the userland matters, and bhyve clearly outclassed the legacy KVM on SmartOS. However, one result was nagging at me: the performance gap between FreeBSD bare metal (&lt;code&gt;4005.08 MiB/sec&lt;/code&gt;) and a native bhyve VM (&lt;code&gt;3636.01 MiB/sec&lt;/code&gt;) was about 9%. This was a larger drop than I expected. It prompted a new question: was this overhead inherent to bhyve, or was it a quirk of the new N150 hardware?&lt;/p&gt;
&lt;h3&gt;Going deeper: Testing on an Intel i7-7500U&lt;/h3&gt;
&lt;p&gt;To see if more mature, better-supported hardware would tell a different story, I replicated the FreeBSD tests on an older Qotom Mini-PC powered by an Intel i7-7500U. The results were illuminating and dramatically changed the narrative.&lt;/p&gt;
&lt;h4&gt;CPU Performance Comparison (Intel i7-7500U)&lt;/h4&gt;
&lt;p&gt;Once again, the CPU tests produced strange results. The native FreeBSD environments all reported incredibly high numbers in the millions of events/sec, while the Ubuntu Linuxulator jail's result was on a completely different, incompatible scale. Frankly, given the massive discrepancy between FreeBSD-native and Linux-based environments, I'm unsure that the &lt;code&gt;sysbench&lt;/code&gt; CPU figures can be considered totally reliable in absolute terms.&lt;/p&gt;
&lt;p&gt;However, what &lt;em&gt;is&lt;/em&gt; useful is comparing the native FreeBSD results against each other. This tells us about relative overhead.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Platform&lt;/th&gt;
&lt;th style="text-align: left;"&gt;CPU Performance (Events/sec)&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Overhead vs. Bare Metal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FreeBSD Bare Metal&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6,377,778&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FreeBSD Native Jail&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6,379,271&lt;/td&gt;
&lt;td style="text-align: left;"&gt;~0.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD bhyve VM&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;6,346,852&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;-0.48%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Even if we're skeptical of the absolute numbers, the relative comparison is crystal clear: the CPU overhead of bhyve is &lt;strong&gt;less than half a percent&lt;/strong&gt;. This is the key takeaway.&lt;/p&gt;
&lt;h4&gt;Memory Performance Comparison (Intel i7-7500U)&lt;/h4&gt;
&lt;p&gt;The memory benchmarks, in contrast, were consistent and highly informative.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Platform&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Memory Performance (Transfer Rate)&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Overhead vs. Bare Metal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ubuntu 22.04 Jail&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4856.23 MiB/sec&lt;/td&gt;
&lt;td style="text-align: left;"&gt;+7.55%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FreeBSD Native Jail&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4517.73 MiB/sec&lt;/td&gt;
&lt;td style="text-align: left;"&gt;+0.05%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD Bare Metal&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;4515.24 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Baseline&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;FreeBSD bhyve VM&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;4491.60 MiB/sec&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;-0.52%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is where the real story is. The memory performance of a bhyve VM was a mere &lt;strong&gt;0.52%&lt;/strong&gt; slower than bare metal. This is the kind of near-native performance one hopes for from a top-tier hypervisor and stands in stark contrast to the 9% drop seen on the newer N150.&lt;/p&gt;
&lt;h3&gt;Breaking Down the Results: What I Learned From Both Tests&lt;/h3&gt;
&lt;p&gt;This comprehensive two-platform analysis paints a much clearer picture.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Hardware &lt;em&gt;Really&lt;/em&gt; Matters&lt;/strong&gt;
Performance is not an absolute. The difference between the two platforms was stark: on the mature i7-7500U, bhyve’s overhead was less than 1%, while on the newer, budget N150, it was a more significant 9%. This suggests the performance dip is likely due to missing optimizations for that specific CPU architecture, rather than a fundamental flaw in bhyve itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. bhyve's True Potential is Near-Native Speed&lt;/strong&gt;
The i7 tests prove that &lt;strong&gt;bhyve is an exceptionally efficient hypervisor&lt;/strong&gt; on well-supported hardware. The relative CPU overhead was a negligible -0.48%, and more importantly, the reliable memory benchmarks showed a performance drop of just 0.52% compared to bare metal. This is the gold standard for virtualization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. FreeBSD Jails are Feather-Light&lt;/strong&gt;
On both platforms, native FreeBSD jails demonstrated almost zero performance overhead. On the i7, both CPU and memory performance were virtually identical to bare metal (a 0.05% difference). The N150 CPU tests further showed that FreeBSD's container implementation is so efficient that running a Linux userland inside a jail delivered the best CPU scores of the entire lineup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. SmartOS Zones Are Also Extremely Efficient&lt;/strong&gt;
Just like Jails, SmartOS's native Zones proved to be remarkably lightweight. The N150 CPU tests confirm this, showing that native and LX zones have virtually identical, top-tier performance. On the memory front, the native Zone delivered performance over 13% &lt;em&gt;faster&lt;/em&gt; than the FreeBSD bare-metal baseline, pointing to the high efficiency of the illumos kernel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. The Linux Userland Excels at Throughput&lt;/strong&gt;
A clear pattern emerged on both testbeds: the Ubuntu userland consistently delivered excellent benchmark results. On the CPU front, Ubuntu on both FreeBSD and SmartOS delivered the highest, and nearly identical, performance scores on the N150. For memory, the story was even more dramatic: the Ubuntu LX Zone on SmartOS was the top performer, beating bare-metal FreeBSD by nearly 25%, while the Ubuntu jail on the i7 also surpassed its host by over 7%.&lt;/p&gt;
&lt;h3&gt;Final Thoughts: The Verdict for My Client's New Server&lt;/h3&gt;
&lt;p&gt;So, what's the bottom line for my client's new MiniPC? This benchmarking journey has made the path forward much clearer.&lt;/p&gt;
&lt;p&gt;At the beginning of this process, my main question was whether to stick with a KVM-based setup or make the switch to bhyve. The performance data answers that decisively. The legacy KVM on SmartOS showed a crippling performance penalty, making it a non-starter. Given that, the extra effort to migrate the existing VMs to a bhyve-compatible format is absolutely worth it. The performance gain is just too significant to ignore.&lt;/p&gt;
&lt;p&gt;The final question, then, is &lt;em&gt;which&lt;/em&gt; host OS to use for bhyve: SmartOS or FreeBSD? This is a much tougher call, as both platforms demonstrated incredible strengths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SmartOS&lt;/strong&gt;, powered by the illumos kernel, was a true surprise. It delivered astonishing performance on the target N150 hardware. Its key advantage is the raw speed of its containerization for both CPU and memory tasks. The Ubuntu LX Zone not only ran flawlessly but delivered top-tier CPU scores and outperformed the bare-metal FreeBSD baseline in memory by a massive 25% margin. This points to a highly efficient kernel and offers the tantalizing prospect of running ultra-fast Linux containers alongside performant bhyve VMs on the same host.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;strong&gt;FreeBSD&lt;/strong&gt; proved its mastery of bhyve virtualization. The tests on the i7 hardware showed its implementation to be the gold standard, offering virtually zero performance overhead for full hardware virtualization. Its native Jails are equally efficient, and its Linux compatibility layer is so effective that an Ubuntu jail delivered the &lt;em&gt;fastest CPU performance&lt;/em&gt; of all containers tested on FreeBSD. For workloads that &lt;em&gt;must&lt;/em&gt; live in a full VM, FreeBSD offers the most performant and native bhyve experience, with the reasonable expectation that its support for newer hardware like the N150 will only improve over time.&lt;/p&gt;
&lt;p&gt;Ultimately, the choice comes down to the primary workload. It's a decision between the raw container speed and Linux flexibility of SmartOS versus the pure, uncompromising HVM performance of FreeBSD.&lt;/p&gt;
&lt;p&gt;But one thing is certain: thanks to this deep dive, the path forward is much clearer, and it's paved by bhyve.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Fri, 19 Sep 2025 10:50:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/09/19/freebsd-vs-smartos-whos-faster-for-jails-zones-bhyve/</guid><category>freebsd</category><category>smartos</category><category>illumos</category><category>linux</category><category>jail</category><category>bhyve</category><category>zones</category><category>data</category><category>hosting</category><category>server</category><category>sysadmin</category><category>virtualization</category><category>ownyourdata</category></item><item><title>Introducing the illumos Cafe: Another Cozy Corner for OS Diversity</title><link>https://it-notes.dragas.net/2025/08/18/introducing-the-illumos-cafe/</link><description>&lt;p&gt;&lt;img src="https://illumos.cafe/illumos_cafe.webp" alt="illumos Cafe logo - a coffee cup with an illumos logo"&gt;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;Introducing the illumos Cafe: Another Cozy Corner for OS Diversity&lt;/strong&gt;&lt;/h3&gt;
&lt;h4&gt;From the BSD Cafe to illumos Cafe&lt;/h4&gt;
&lt;p&gt;The idea for this new project was born from the success of the BSD Cafe, an initiative I introduced to the world in July 2023, which received an incredibly positive response. Far more than I ever anticipated. The BSD community already had its well-established hubs: in the Fediverse, places like &lt;a href="https://bsd.network"&gt;bsd.network&lt;/a&gt;, &lt;a href="https://exquisite.social"&gt;exquisite.social&lt;/a&gt;, and others were already thriving, not to mention all the forums, channels, and Reddit communities.&lt;/p&gt;
&lt;p&gt;But in my vision, something was still missing: a hub of services with a positive spirit, built exclusively with open-source tools, where people could come to share, learn, and experience technology with a positive mindset. The BSD Cafe is therefore not just an instance, but a true Cafe - &lt;a href="https://events.eurobsdcon.org/2025/talk/PJJLFV/"&gt;I’ll be speaking more about the BSD Cafe in detail at the next EuroBSDCon&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Why Another Cafe?&lt;/h4&gt;
&lt;p&gt;In a world increasingly dominated by centralized services under the control (or lack thereof) of the usual big players, it has become essential to create free, independent communities, devoid of the algorithmic and commercial controls that influence our overall experience. From day one, the BSD Cafe has embodied this spirit.&lt;/p&gt;
&lt;p&gt;Linux is a good kernel, and there are excellent distributions based on it (some using the GNU userland, others only partially, like Alpine Linux), but it cannot and should not become a monoculture. The alternatives are extremely capable, and for many use cases - in my opinion and experience - they are even more suitable. &lt;a href="https://it-notes.dragas.net/2024/10/03/i-solve-problems-eurobsdcon/"&gt;BSD systems have served me exceptionally well for over 20 years&lt;/a&gt;, providing stability and security. At the same time, many other operating systems are renowned for their robustness, reliability, and the quality of their design and implementation.&lt;/p&gt;
&lt;h4&gt;Why illumos?&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://illumos.org"&gt;illumos&lt;/a&gt; is one of them. As the open-source descendant of OpenSolaris, it is an operating system known for its enterprise-grade stability and innovative technologies like ZFS, DTrace, and "zones". It was born from the solid foundations of Solaris and has evolved over time while remaining true to many of its core principles. I have always seen illumos and its distributions as kindred spirits to the BSDs, despite their differences. The philosophy is one of evolution without revolution, of guaranteeing long-term continuity and reliability rather than chasing the latest hype. This is precisely why, for some time now (and thanks in part to the &lt;a href="https://www.tumfatig.net/tags/illumos/"&gt;inspiring posts by Joel Carnat&lt;/a&gt;, which further sparked my curiosity), I have been running &lt;a href="https://omnios.org"&gt;OmniOS&lt;/a&gt; and &lt;a href="https://smartos.org"&gt;SmartOS&lt;/a&gt; alongside my BSD-based setups for certain workloads.&lt;/p&gt;
&lt;p&gt;However, there is very little information online about services running on them. So, a few months ago, I began to consider a new project: &lt;a href="http://illumos.cafe"&gt;the illumos Cafe&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;The illumos Cafe Project&lt;/h4&gt;
&lt;p&gt;The illumos Cafe is a project similar to the &lt;a href="https://bsd.cafe"&gt;BSD Cafe&lt;/a&gt; (though perhaps less complex, at least initially). It shares the same spirit of positivity and inclusivity and aims to provide services running on illumos-based operating systems to demonstrate that there are no reasons not to use them. Just like with the BSD Cafe, diversifying the operating systems we use - even while using the same platforms - is fundamental to improving the reliability and resilience of the Internet. The Internet was born as a decentralized network, but for most people, it has sadly become just a tool to access the services of big players.&lt;/p&gt;
&lt;h4&gt;Community and Philosophy&lt;/h4&gt;
&lt;p&gt;But we want to connect. We want relationships with people, between people. We don't want algorithms. We don't want our data to be monetized by "us and our 65535 partners". We want a network that serves us, an OS that serves us - not an OS that just serves as a vehicle to store our data in "someone else's house". The illumos Cafe, therefore, aims to be a home for anyone interested in developing, using, or who is simply curious about illumos-based operating systems.&lt;/p&gt;
&lt;h4&gt;Technical Setup&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://wiki.bsd.cafe/bsdcafe-technical-details"&gt;As with the BSD Cafe&lt;/a&gt;, the entire setup will be documented. For now, it is very simple: there is a VM (running on FreeBSD and bhyve, on hardware I manage) where I have installed SmartOS. The physical host also runs the reverse proxy (in a jail). Inside the SmartOS VM, there are a series of zones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zone 1: nginx&lt;/strong&gt; (Web Server) - Currently serving &lt;a href="https://illumos.cafe"&gt;the project's homepage&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zone 2: Mastodon&lt;/strong&gt; (Social) - Hosting the Mastodon instance and its dependencies at &lt;a href="https://mastodon.illumos.cafe"&gt;https://mastodon.illumos.cafe&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zone 3: PostgreSQL&lt;/strong&gt; (Database) - The Mastodon database, on a dedicated zone.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zone 4: Redis&lt;/strong&gt; (Cache) - The Mastodon cache, on a dedicated zone.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zone 5: snac&lt;/strong&gt; (LX Zone) - Currently in an LX zone (Alpine) as I ran into some issues getting it to work in a native zone. It will be moved to a native zone as soon as I resolve them. It's serving the snac instance at &lt;a href="https://snac.illumos.cafe"&gt;https://snac.illumos.cafe&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Media files are stored on an external physical server (running FreeBSD, the same one as the BSD Cafe, but in a dedicated jail) with &lt;a href="https://github.com/seaweedfs/seaweedfs"&gt;SeaweedFS&lt;/a&gt;. I was able to compile and run SeaweedFS on illumos without any problems, but at the moment, I don't have a host with enough storage space for the media.&lt;/p&gt;
&lt;h4&gt;Available Services&lt;/h4&gt;
&lt;p&gt;More services will arrive over time. For now, two gateways to the Fediverse are already available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mastodon&lt;/strong&gt; - &lt;a href="https://mastodon.illumos.cafe"&gt;https://mastodon.illumos.cafe&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;snac&lt;/strong&gt; - &lt;a href="https://snac.illumos.cafe"&gt;https://snac.illumos.cafe&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both instances share the same rules as the BSD Cafe. Positivity. Supporters, not haters. I want them to be places of enjoyment, not venting. Of friendship, not hate.&lt;/p&gt;
&lt;h4&gt;Registrations and Logo&lt;/h4&gt;
&lt;p&gt;Registrations for the Mastodon instance are now open, and the available themes are the default ones plus &lt;a href="https://github.com/nileane/TangerineUI-for-Mastodon"&gt;the colorful TangerineUI&lt;/a&gt; - whose orange hue echoes the illumos logo.&lt;/p&gt;
&lt;p&gt;The project's logo was not generated by an AI. I made it myself by hastily sticking the illumos SVG onto a coffee cup. Basic, perhaps. But authentic.&lt;/p&gt;
&lt;h4&gt;Looking Ahead&lt;/h4&gt;
&lt;p&gt;The BSD Cafe will, of course, remain my primary home. But I want to bring illumos into the Fediverse and provide a home for anyone who wishes to share their interest in this excellent OS.&lt;/p&gt;
&lt;p&gt;I will document the entire process, just &lt;a href="https://it-notes.dragas.net/2022/11/23/installing-mastodon-on-a-freebsd-jail/"&gt;as I did with Mastodon on FreeBSD&lt;/a&gt;, as it is a bit more intricate. Because in my dreams, I see Fediverse statistics showing instances spread fairly evenly across the major open-source operating systems. Because relying on a single OS, even if it's open-source, and ceasing to support the others is also a single point of failure.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Mon, 18 Aug 2025 09:04:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/08/18/introducing-the-illumos-cafe/</guid><category>illumos</category><category>community</category><category>bhyve</category><category>fediverse</category><category>data</category><category>server</category><category>ownyourdata</category><category>social</category><category>web</category><category>zfs</category></item><item><title>Make Your Own Backup System – Part 2: Forging the FreeBSD Backup Stronghold</title><link>https://it-notes.dragas.net/2025/07/29/make-your-own-backup-system-part-2-forging-the-freebsd-backup-stronghold/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/hard_disk.webp" alt="A hard disk - ready to host our backups"&gt;&lt;/p&gt;&lt;p&gt;With the &lt;a href="https://it-notes.dragas.net/2025/07/18/make-your-own-backup-system-part-1-strategy-before-scripts/"&gt;primary backup strategies and methodologies introduced&lt;/a&gt;, we've reached the point where we can get specific: the Backup Server configuration.&lt;/p&gt;
&lt;p&gt;When choosing the type of backup server to use, I tend to favor specific setups: either I trust a professional backup service provider (like Colin Percival's &lt;a href="https://www.tarsnap.com/"&gt;Tarsnap&lt;/a&gt;), or I want full control over the disks where the backups will be hosted. In both cases, for the past twenty years, my operating system of choice for backup servers has been FreeBSD. With a few rare exceptions for clients with special requests, it covers all my needs. When I require Linux-based solutions, such as the &lt;a href="https://www.proxmox.com/en/products/proxmox-backup-server/overview"&gt;Proxmox Backup Server&lt;/a&gt;, I create a VM and manage it within.&lt;/p&gt;
&lt;p&gt;I typically use both IPv4 and IPv6. For IPv4, I "play" with NAT and port forwarding. For IPv6, I tend to assign a public IPv6 address to each jail or VM, which is then filtered by the physical server's firewall. Unfortunately, every provider, server, and setup has a different approach to IPv6, making it impossible to cover them all in this article. When a provider allows for routed setups, I use this approach: &lt;a href="https://it-notes.dragas.net/2023/09/23/make-your-own-vpn-freebsd-wireguard-ipv6-and-ad-blocking-included/"&gt;Make your own VPN: FreeBSD, WireGuard, IPv6, and ad-blocking included&lt;/a&gt; - assigning a /72 to the bridge for the jails and VMs.&lt;/p&gt;
&lt;p&gt;In my opinion, FreeBSD is a perfect all-rounder for backups, thanks to its ability to completely partition services. You can separate backup services (or specific servers/clients) into different jails or even VMs. Furthermore, using ZFS greatly enhances both flexibility and the range of tools you can use.&lt;/p&gt;
&lt;p&gt;The main distinction is usually between local backup servers (physically accessible, though not always attended, and in locations deemed secure) and remote ones, such as leased external servers. I personally use a combination of both. If the services I need to back up are external, in a datacenter, and need to be quickly restorable, I prefer to always have a copy on another server in a different datacenter with good outbound connectivity. This guarantees good bandwidth for restores, which isn't always available from a local connection to the outside world. However, an internal, nearby, and accessible backup server (even a Raspberry Pi or a mini PC) ensures physical access to the data. Whenever possible, I maintain both an external and an internal copy - and they are autonomous, meaning the internal copy is &lt;em&gt;not&lt;/em&gt; a replica of the external one, but an additional, independent backup. This ensures that if a problem occurs with the external backup, it won't automatically propagate to the internal one. In any case, the backup must always be in a different datacenter from the one containing the production data. When &lt;a href="https://www.reuters.com/article/idUSKBN2B20NT/"&gt;the fire at the OVH datacenter in Strasbourg&lt;/a&gt; caused the entire complex to shut down, many people found themselves in trouble because their backups were in the same, now unreachable, location. I had a copy with another provider, in a different datacenter and country, as well as a local copy.&lt;/p&gt;
&lt;p&gt;Despite it being "just" a backup server, I almost always use some form of disk redundancy. If I have two disks, I set up a mirror. With three or more, I use RaidZ1 or RaidZ2. This is because, in my view, backups are nearly as important as production data. The inability to recover data from a backup means it's lost forever. And it happens often, very often, that someone contacts me to recover a file (or a database, etc.) days or weeks after its accidental loss or deletion. Usually, pulling out a file from a two-month-old backup generates a mix of disbelief, admiration, but above all, a sense of security in the person requesting it. And that is what our work should instill in the people we collaborate with.&lt;/p&gt;
&lt;p&gt;The backup server should be hardened. If possible, it should be protected and unreachable from the outside. My best backup servers are those accessible only via VPN, capable of pulling the data on their own. If they are on a LAN, it's even better if they are completely disconnected from the Internet.&lt;/p&gt;
&lt;p&gt;For this very reason, &lt;strong&gt;backups must always be encrypted&lt;/strong&gt;. Having a backup means having full access to the data, and the backup server is the prime target for being breached or stolen if the goal is to get your hands on that data. I've seen healthcare facilities' backup servers being targeted (in a rather trivial way, to be honest) by journalists looking for health details of important figures. It is therefore critical that the backup server be as secure as possible.&lt;/p&gt;
&lt;p&gt;Based on the type of access, I use two types of encryption:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;If the server is local&lt;/strong&gt; (especially if the ZFS pool is on external disks), I usually install FreeBSD on UFS in read-only mode, as &lt;a href="https://it-notes.dragas.net/2024/05/31/freebsd-tips-and-tricks-native-ro-rootfs/"&gt;I've described in a previous article&lt;/a&gt;, and encrypt the backup disks with &lt;a href="https://man.freebsd.org/cgi/man.cgi?geli(8)"&gt;GELI&lt;/a&gt;. This ensures that in the event of a "dirty" shutdown (more likely in unattended environments), I can reconnect to the host and then reactivate the ZFS pool. This approach makes it nearly impossible to retrieve even the pool's metadata if the disks are stolen, as GELI performs a full-device encryption. For example, an employee of a company I work with stole one of the secondary backup disks (which was located at a different, unmonitored company site) to steal information. He got nothing but a criminal complaint. With this approach, it's also not necessary to further encrypt the datasets, which avoids some issues (which I'll discuss later, in a future post).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If the server is remote&lt;/strong&gt;, in a datacenter, I usually use ZFS native encryption, encrypting the main backup dataset (and &lt;a href="https://bastillebsd.org/"&gt;BastilleBSD&lt;/a&gt;'s, if applicable). Consequently, all child datasets containing backups will also be encrypted. In this case as well, a password will be required after a reboot to unlock those datasets, ensuring that the data cannot be extracted if control of the disks is lost.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is an example of how to use GELI to encrypt an entire partition and then create a ZFS pool on it (in the example, the disk is &lt;code&gt;da1&lt;/code&gt; - do not follow these commands blindly, or you will erase all content on the &lt;code&gt;da1&lt;/code&gt; device!):&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# WARNING: This destroys the existing partition table on disk da1
gpart destroy -F da1

# Create a new GPT partition table
gpart create -s gpt da1

# Add a freebsd-zfs partition that spans the entire disk
# The -a 1m flag ensures proper alignment
gpart add -t freebsd-zfs -a 1m da1

# Initialize GELI encryption on the new partition (da1p1)
# We use AES-XTS with 256-bit keys and a 4k sector size
# The -b flag means &amp;quot;boot,&amp;quot; prompting for the passphrase at boot time
geli init -b -l 256 -s 4096 da1p1
# You will be prompted for a passphrase: choose a strong one and save it!

# Attach the encrypted partition. A new device /dev/da1p1.eli will be created.
# You will be prompted for the passphrase you just set
geli attach da1p1

# (Optional) Check the status of the encrypted device
geli status da1p1

# Create the ZFS pool &amp;quot;bckpool&amp;quot; on the encrypted device
# We enable zstd compression (an excellent compromise) and disable atime
zpool create -O compression=zstd -O atime=off bckpool da1p1.eli
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this setup, the reference pool for everything related to backups will be &lt;code&gt;bckpool&lt;/code&gt; - and you'll need to keep this in mind for the next steps. Additionally, after every server reboot, you'll need to "unlock" the disk and import the pool:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Enter the passphrase when prompted
geli attach da1p1

# Import the ZFS pool, which is now visible
zpool import bckpool
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With this method, it's not necessary to encrypt the ZFS datasets, as the underlying disk (or, more precisely, the partition containing the ZFS pool) is already encrypted.&lt;/p&gt;
&lt;p&gt;If, instead, you choose to encrypt the ZFS dataset (for example, if you install FreeBSD on the same disks that will hold the data and don't want to use a multi-partition approach), you should create a base encrypted dataset. Inside it, you can create the various backup datasets, VMs, and the BastilleBSD mountpoint. Due to property inheritance, they will all be encrypted as well.&lt;/p&gt;
&lt;p&gt;To create an encrypted dataset, a command like this will suffice:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Creates a new dataset with encryption enabled.
# keylocation=prompt will ask for a passphrase every time it's mounted.
# keyformat=passphrase specifies the key type.
zfs create -o encryption=on -o keylocation=prompt -o keyformat=passphrase zfspool/dataset
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, after every reboot, you will need to load the key and mount the dataset:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;zfs load-key zfspool/dataset
zfs mount zfspool/dataset
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Keep in mind the setup you choose, as many of the subsequent choices and commands will depend on it.&lt;/p&gt;
&lt;h2&gt;Base System Setup&lt;/h2&gt;
&lt;p&gt;I'll install BastilleBSD - a useful tool for separating services into jails. It will be helpful for isolating our backup services:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;pkg install -y bastille
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you used ZFS for the root filesystem, you can proceed directly with the setup. Otherwise (i.e., ZFS on other disks), you'll need to edit the &lt;code&gt;/usr/local/etc/bastille/bastille.conf&lt;/code&gt; file and specify the correct dataset on which to install the jails. Then run:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille setup
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once the automatic setup is complete, check the &lt;code&gt;/etc/pf.conf&lt;/code&gt; file - it will be automatically configured to only accept SSH connections. Ensure the network interface is set correctly. When you activate &lt;code&gt;pf&lt;/code&gt;, you will be kicked out of the server, but you can then reconnect.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;service pf start
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's bootstrap a FreeBSD release for the jails - this will be useful later.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille bootstrap 14.3-RELEASE update
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we create a local bridge. Jails and VMs can be attached to it, making them fully autonomous. Using VNET jails, for example, will allow the creation of VPNs or &lt;code&gt;tun&lt;/code&gt; interfaces inside them, simplifying potential future setups (and increasing security by using a dedicated network stack).&lt;/p&gt;
&lt;p&gt;Modify the &lt;code&gt;/etc/rc.conf&lt;/code&gt; file and add:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Add lo1 and bridge0 to the list of cloned interfaces
cloned_interfaces=&amp;quot;lo1 bridge0&amp;quot;
# Assign an IP address and netmask to the bridge
ifconfig_bridge0=&amp;quot;inet 192.168.0.1 netmask 255.255.255.0&amp;quot;
# Enable gateway functionality for routing
gateway_enable=&amp;quot;yes&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's also modify &lt;code&gt;/etc/pf.conf&lt;/code&gt; to allow the &lt;code&gt;192.168.0.0/24&lt;/code&gt; subnet to access the Internet via NAT. We will skip packet filtering on &lt;code&gt;bridge0&lt;/code&gt; and enable NAT. This isn't the most secure setup, but it's sufficient to get started:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;#...
# Skip PF processing on the internal bridge interface
set skip on bridge0
#...
# NAT traffic from our internal network to the outside world
nat on $ext_if from 192.168.0.0/24 to any -&amp;gt; ($ext_if:0)
#...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To ensure the new settings are correct, it's a good idea to test with a reboot.&lt;/p&gt;
&lt;p&gt;Since I often configure &lt;a href="https://github.com/freebsd/vm-bhyve"&gt;vm-bhyve&lt;/a&gt; in my setups, I prefer to install it right away, creating the dataset that will contain the VMs and installation templates. Remember that &lt;code&gt;zroot&lt;/code&gt; is only valid if you installed the entire system on ZFS; otherwise, you'll need to change it to your own dataset:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Install required packages
pkg install vm-bhyve grub2-bhyve bhyve-firmware
# Create a dataset to store VMs
zfs create zroot/VMs
# Enable the vm service at boot
sysrc vm_enable=&amp;quot;YES&amp;quot;
# Set the directory for VMs, using the ZFS dataset
sysrc vm_dir=&amp;quot;zfs:zroot/VMs&amp;quot;
# Initialize vm-bhyve
vm init
# Copy the example templates
cp /usr/local/share/examples/vm-bhyve/* /zroot/VMs/.templates/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, I usually enable the console via &lt;code&gt;tmux&lt;/code&gt;. This means that when a VM is launched, it won't open a VNC port by default, but a &lt;code&gt;tmux&lt;/code&gt; session connected to the VM's serial port. Let's install and configure &lt;code&gt;tmux&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;pkg install -y tmux
vm set console=tmux
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's also attach the switch we created (&lt;code&gt;bridge0&lt;/code&gt;) to &lt;code&gt;vm-bhyve&lt;/code&gt; so we can use it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;vm switch create -t manual -b bridge0 public
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, &lt;code&gt;vm-bhyve&lt;/code&gt; is ready.&lt;/p&gt;
&lt;p&gt;The basic infrastructure is complete. We now have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ZFS&lt;/strong&gt; to ensure data integrity, which will also handle redundancy, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BastilleBSD&lt;/strong&gt; to manage jails, useful for backing up Linux, NetBSD, OpenBSD, and non-ZFS FreeBSD machines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vm-bhyve&lt;/strong&gt; to install specific systems (like Proxmox Backup Server).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Backup Strategies&lt;/h2&gt;
&lt;p&gt;I use various backup tools, too many to list in this article. So I'll make a broad distinction, describing how to use this server to achieve our goal: securing data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;FreeBSD servers with ZFS&lt;/strong&gt; (hosts, VMs, jails, hypervisors, and their respective VMs), I use an extremely useful, efficient, and reliable tool: &lt;a href="https://github.com/psy0rz/zfs_autobackup"&gt;zfs-autobackup&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Linux servers (without ZFS), NetBSD, OpenBSD&lt;/strong&gt;, etc. (any non-ZFS OS), I usually use &lt;a href="https://www.borgbackup.org/"&gt;BorgBackup&lt;/a&gt;. There are other fantastic tools like &lt;a href="https://restic.net/"&gt;restic&lt;/a&gt;, &lt;a href="https://kopia.io/"&gt;Kopia&lt;/a&gt;, etc., but BorgBackup has never let me down and has served me well even on low-power devices and after incredibly complex disasters.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Proxmox servers&lt;/strong&gt; (a solution I've used with satisfaction in production since 2013, although I'm recently migrating to FreeBSD/bhyve where possible), I use two possible alternatives (often both at the same time): if the storage is ZFS, I use the &lt;code&gt;zfs-autobackup&lt;/code&gt; approach. In either case, the most practical solution is the Proxmox Backup Server. And the Proxmox Backup Server is one of the reasons I proposed installing &lt;code&gt;vm-bhyve&lt;/code&gt;: running it in a VM and storing the data on the FreeBSD host gives you the best of both worlds. Some time ago, I tried running it in a FreeBSD jail (via Linuxulator), but it didn't work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Backups using zfs-autobackup&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;zfs-autobackup&lt;/code&gt; is an extremely useful and effective tool. It allows for "pull" type backups, as well as having an intermediary host that connects to both the source and destination, which is useful if you don't want direct contact between the source and destination. I won't describe the latter setup, but the documentation is clear, and I have several of them in production, ensuring that the production server and its backup server cannot communicate with each other.&lt;/p&gt;
&lt;p&gt;I usually create a dataset for each server and instruct &lt;code&gt;zfs-autobackup&lt;/code&gt; to keep that server's backups in that dataset. The snapshots taken and transferred will all be from the same instant, so as not to create a time skew (some tools of this kind snapshot a dataset, then transfer it, which can result in minutes of difference between two different datasets from the same server).&lt;/p&gt;
&lt;p&gt;I've described in detail how I perform this type of backup in a &lt;a href="https://it-notes.dragas.net/2022/05/30/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-2/"&gt;previous post&lt;/a&gt;, so I suggest reading that post for reference.&lt;/p&gt;
&lt;p&gt;Let's install zfs-autobackup on the FreeBSD server:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;pkg install py311-zfs-autobackup mbuffer
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Backups for other servers using BorgBackup&lt;/h3&gt;
&lt;p&gt;When I don't have ZFS available or need to perform a file-based backup (all or partial), I use a different technique. &lt;code&gt;BorgBackup&lt;/code&gt; backups are primarily "push" based, meaning the client will connect to the backup server. This is not optimal or the most secure approach, as the backup server should, in theory, be hardened. Even when protecting everything via VPN, the risk remains that a compromised server could connect to its backup server and alter or delete the backups. I have seen this happen in ransomware cases (especially in the Microsoft world), and so I try to be careful to minimize this type of problem, mainly through snapshots of the backup server (an operation that will be described later).&lt;/p&gt;
&lt;p&gt;To ensure the highest possible security, I create a FreeBSD jail on the backup server for each server I need to back up. The advantage of this approach is the complete separation of all servers from each other. By using a regular user inside a jail, a compromised server that connects to its backup server would only be able to reach its own backups, as it would be confined to a user account and, even if it managed to escalate privileges, still be inside a jail.&lt;/p&gt;
&lt;p&gt;Let's say, for example, we want to back up a server called "ServerA" (great imagination, I know). We create a dedicated jail on the backup server:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Create a new VNET jail named &amp;quot;servera&amp;quot; attached to our bridge
bastille create -B servera 14.3-RELEASE 192.168.0.101/24 bridge0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;BastilleBSD will automatically set the host's gateway for the jail. In our case, this is incorrect, so we need to modify it and set the jail's gateway to &lt;code&gt;192.168.0.1&lt;/code&gt; in the &lt;code&gt;/usr/local/bastille/jails/servera/root/etc/rc.conf&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# ...
defaultrouter=&amp;quot;192.168.0.1&amp;quot;
# ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Restart the jail and connect to it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille restart servera
bastille console servera
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, inside the jail, we install &lt;code&gt;borgbackup&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;pkg install py311-borgbackup
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;BorgBackup doesn't run a daemon; it's launched by the remote server (which sends its data to the backup server), so it's important that the installed version is compatible with the one on the remote host.&lt;/p&gt;
&lt;p&gt;Since we'll be using SSH, let's enable it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;service sshd enable
service sshd start
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And create a non-privileged user for this purpose:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# The 'adduser' utility provides an interactive way to create a user.
root@servera:~ # adduser
Username: servera
Full name: Server A
Uid (Leave empty for default): 
Login group [servera]: 
Login group is servera. Invite servera into other groups? []: 
Login class [default]: 
Shell (sh csh tcsh nologin) [sh]: 
Home directory [/home/servera]: 
Home directory permissions (Leave empty for default): 
Use password-based authentication? [yes]: 
Use an empty password? (yes/no) [no]: 
Use a random password? (yes/no) [no]: yes
Lock out the account after creation? [no]: 
Username    : servera
Password    : &amp;lt;random&amp;gt;
Full Name   : Server A
Uid         : 1001
Class       : 
Groups      : servera 
Home        : /home/servera
Home Mode   : 
Shell       : /bin/sh
Locked      : no
OK? (yes/no) [yes]: yes
adduser: INFO: Successfully added (servera) to the user database.
adduser: INFO: Password for (servera) is: JIkdq8Ex
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The user is created and can receive SSH connections. After setting everything up, I suggest disabling password-based login in the jail's SSH configuration, using only public key authentication.&lt;/p&gt;
&lt;p&gt;As mentioned, the biggest risk of a "push" backup is that a compromised client could access the backup server and delete or encrypt the backup history, rendering it useless.&lt;/p&gt;
&lt;p&gt;To drastically mitigate this risk, we can configure SSH to force the client to operate in a special Borg mode called &lt;strong&gt;append-only&lt;/strong&gt;. In this mode, the SSH key used by the client will only have permission to create new archives, not to read or delete old ones. However, this approach could complicate some client-side operations (like &lt;code&gt;mount&lt;/code&gt;, &lt;code&gt;prune&lt;/code&gt;, etc.), forcing them to be done on the server. For this reason, I won't describe it in this setup, "limiting" myself to taking snapshots of the repositories. It can be a very good practice, so I recommend considering it.&lt;/p&gt;
&lt;p&gt;Let's initialize the BorgBackup repository. In this example, for simplicity, I won't set up repository encryption. If the jails are on an encrypted dataset or GELI-encrypted disks, there will still be data encryption on the disks, but there will be no protection against someone who could physically access the server while the disks are mounted. As usual, security is like an onion: every layer helps. Personally, I suggest enabling and using it ALWAYS.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Switch to the new user
su -l servera
# Initialize a new Borg repo named &amp;quot;servera&amp;quot; with no encryption (for this example)
borg init -e none servera
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The jail is ready, but it's unreachable from the outside. There are two ways to make it accessible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Install a VPN system inside the jail itself.&lt;/strong&gt; Using tools like Zerotier or Tailscale (which don't need to expose ports) will immediately create the conditions to connect to the jail, which will remain inaccessible from the outside. As the jail is a VNET jail, we're free to choose any of the supported VPN technologies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expose a port on the backup server&lt;/strong&gt;, i.e., on the host, to allow external connections. Many advise against this path as they consider it less secure. It is, but sometimes we don't have the luxury of installing whatever we want on the server we're backing up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To expose the port, go back to the host and modify the &lt;code&gt;/etc/pf.conf&lt;/code&gt; file, creating the &lt;code&gt;rdr&lt;/code&gt; and &lt;code&gt;pass&lt;/code&gt; rules to let packets in:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# ...
# Redirect incoming traffic on port 1122 to the jail's SSH port (22)
rdr on $ext_if inet proto tcp from any to any port = 1122 -&amp;gt; 192.168.0.101 port 22
# ...
# Allow incoming traffic on port 1122
pass in inet proto tcp from any to any port 1122 flags S/SA keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Reload the &lt;code&gt;pf&lt;/code&gt; configuration:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;service pf reload
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The jail will now be reachable on the server's public IP, on port 1122. Obviously, this port number is for illustrative purposes, and I used &lt;code&gt;from any&lt;/code&gt;, but for better security, you should replace &lt;code&gt;any&lt;/code&gt; with the IP address of the server that will be connecting to perform the backup.&lt;/p&gt;
&lt;p&gt;By repeating this process for each server and creating a separate jail for each, you can have isolated jails in separate datasets with their backups, potentially setting space limits using ZFS quotas.&lt;/p&gt;
&lt;p&gt;It's important to remember that backing up a live filesystem (i.e., without a snapshot or dumps) has a very high probability of being impossible to restore completely. Databases hate this approach because files will change while being copied and tend to get corrupted. Of course, it depends on the nature of the data (a backup of a static website will have no issues, but a WordPress database probably will), but it's crucial to think about a technique to snapshot the filesystem before proceeding. For example, I have already written about how to create snapshots on FreeBSD with UFS in a previous article: &lt;a href="https://it-notes.dragas.net/2024/06/04/freebsd-tips-and-tricks-creating-snapshots-with-ufs/"&gt;FreeBSD tips and tricks: creating snapshots with UFS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will cover other operating systems in a future, dedicated post.&lt;/p&gt;
&lt;h3&gt;Proxmox Backup Server in a Dedicated VM&lt;/h3&gt;
&lt;p&gt;Starting with version 4.0 (which is still in beta at the time of this writing), Proxmox Backup Server (PBS) supports storing its data in an S3 bucket. This is excellent news as it decouples the server from the data. There are great open-source S3 implementations, like &lt;a href="https://min.io/"&gt;Minio&lt;/a&gt; or &lt;a href="https://github.com/seaweedfs/seaweedfs"&gt;SeaweedFS&lt;/a&gt;, which allow for clustering, replication, etc. In this "simple" case, we will install Proxmox Backup Server in a small VM, while for the data, we'll install Minio in a native FreeBSD jail. The advantage is undeniable: the VM will only serve as an "intermediary", but the data will rest directly on the FreeBSD host's dataset, natively. It will also be possible to specify other external endpoints, other repositories, etc.&lt;/p&gt;
&lt;p&gt;As a philosophy, I tend not to use external providers unless for specific needs, so installing Minio in a jail is a perfect solution to manage this situation.&lt;/p&gt;
&lt;p&gt;Let's install PBS by downloading the ISO from their website (https://enterprise.proxmox.com/iso/) - at this moment, the version that supports this setup is 4.0 Beta.&lt;/p&gt;
&lt;p&gt;The directory to download to is the &lt;code&gt;vm-bhyve&lt;/code&gt; ISOs directory. It's not strictly necessary, but it's useful for not "losing" it somewhere. So, go to the directory and download it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;cd /zroot/VMs/.iso
fetch https://enterprise.proxmox.com/iso/proxmox-backup-server_4.0-BETA-1.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let's create a VM with &lt;code&gt;vm-bhyve&lt;/code&gt;. We can start from the Debian template, but we'll make some modifications to optimize performance. In this example, I'm giving it 30 GB of disk space, 2 GB of RAM, and 2 cores.&lt;/p&gt;
&lt;p&gt;If you want to store all backups inside the VM, you'll need to size the virtual disk correctly (or create and attach another one). In this case, I will focus on the "clean" VM that will store its data on a dedicated jail with Minio.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;vm create -t debian -s 30G -m 2G -c 2 pbs
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once the empty VM is created, let's modify its options:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;vm configure pbs
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We will modify the VM to be UEFI and to use the NVME disk driver - bhyve &lt;a href="https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/"&gt;performs significantly better on NVME than virtio, as previously tested&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;loader=&amp;quot;uefi&amp;quot;
cpu=&amp;quot;2&amp;quot;
memory=&amp;quot;2G&amp;quot;
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;nvme&amp;quot;
disk0_name=&amp;quot;disk0.img&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fortunately, the Proxmox team has provided for the installation of the Backup Server on devices without a graphical interface, so the boot menu will allow installation via serial console. Let's launch the installation and connect to the virtual serial console:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;cd /zroot/VMs/.iso
vm install pbs proxmox-backup-server_4.0-BETA-1.iso
vm console pbs
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Select the installation via &lt;strong&gt;Terminal UI (serial console)&lt;/strong&gt; and proceed normally as if it were a physical host, assigning an IPv4 address from the &lt;code&gt;192.168.0.x&lt;/code&gt; range (in this example, I'll use &lt;code&gt;192.168.0.3&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This way, the Proxmox Backup Server will run in a VM, with the ability to take snapshots before updates, etc., without any worries.&lt;/p&gt;
&lt;p&gt;Once the installation is complete, PBS will reboot and listen on port 8007 of its IP. Again, as with the jails, we have two options: install a VPN system within the VM itself (thus exposing it automatically only on that VPN - generally a more secure operation) or expose port 8007 on the server's public IP.&lt;/p&gt;
&lt;p&gt;In the latter case, add the relevant lines to the &lt;code&gt;/etc/pf.conf&lt;/code&gt; file on the FreeBSD backup server:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# ...
# Redirect incoming traffic on port 8007 to the PBS VM's web interface
rdr on $ext_if inet proto tcp from any to any port = 8007 -&amp;gt; 192.168.0.3 port 8007
# ...
# Allow that traffic to pass
pass in inet proto tcp from any to any port 8007 flags S/SA keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Reload the &lt;code&gt;pf&lt;/code&gt; configuration:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;service pf reload
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The PBS VM configuration is complete. If you chose to use the PBS's internal disk as a repository, no further operations are necessary (other than the normal repository creation, etc., within PBS).&lt;/p&gt;
&lt;p&gt;In this case, however, we will use a different approach.&lt;/p&gt;
&lt;h4&gt;Creating a Minio Jail as a Data Repository for PBS&lt;/h4&gt;
&lt;p&gt;This approach, in my opinion, has a number of important advantages. The first is that Minio will run in a dedicated jail on the host, at full performance, and will store the data directly on the physical ZFS datapool, thus removing any other layer in between. This jail could potentially be moved to other hosts (by connecting PBS and the jail via VPN or public IP), made redundant thanks to all of Minio's features, etc. Another solution I am successfully testing (in other setups) is SeaweedFS.&lt;/p&gt;
&lt;p&gt;Let's create a dedicated jail with Minio and put it on the bridge, so that PBS can access it on the LAN.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille create -B minio 14.3-RELEASE 192.168.0.11/24 bridge0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If not configured directly, BastilleBSD will use the host's gateway for the jail, which is incorrect in this case. So let's go modify it and restart the jail. Enter the jail with:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille console minio
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And modify the &lt;code&gt;/etc/rc.conf&lt;/code&gt; file to have the correct gateway (following the example addresses):&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# ...
ifconfig_vnet0=&amp;quot; inet 192.168.0.11/24 &amp;quot;
defaultrouter=&amp;quot;192.168.0.1&amp;quot;
# ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Exit the jail and restart it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille restart minio
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Enter the jail and install Minio:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;bastille console minio
pkg install -y minio
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Minio is already able to start, but PBS, even on the LAN, wants an encrypted connection. Fortunately, there's a handy tool that can generate the certificates for us:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Download the certgen tool
fetch https://github.com/minio/certgen/releases/latest/download/certgen-freebsd-amd64

# Make it executable and run it for our jail's IP
chmod a+rx certgen-freebsd-amd64
./certgen-freebsd-amd64  -host &amp;quot;192.168.0.11&amp;quot;

# Create the necessary directories and set permissions
mkdir -p /usr/local/etc/minio/certs
cp private.key public.crt /usr/local/etc/minio/certs/
chown -R minio:minio /usr/local/etc/minio/certs/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's view the certificate's fingerprint. Since it's self-signed, we'll need it for PBS later. For security reasons, PBS will ask for the fingerprint of non-directly verifiable certificates. Run the following command and take note of the result:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;openssl x509 -in /usr/local/etc/minio/certs/public.crt -noout -fingerprint -sha256
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, enable and configure Minio in &lt;code&gt;/etc/rc.conf&lt;/code&gt;. 
&lt;strong&gt;WARNING&lt;/strong&gt;: The username and password (access key and secret) used in this example are insecure and for testing purposes only. It is strongly recommended to use different values:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Enable Minio service
minio_enable=&amp;quot;YES&amp;quot;
# Set the address for the Minio console
minio_console_address=&amp;quot;:8751&amp;quot;
# Set the root user and password as environment variables
minio_env=&amp;quot;MINIO_ROOT_USER=testaccess MINIO_ROOT_PASSWORD=testsecret&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start Minio:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;service minio start
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything went correctly, Minio is now running (with its certificates) and ready to receive connections.&lt;/p&gt;
&lt;p&gt;It's now time to create the bucket(s) that PBS will use. There are several ways to do this, but to test that everything is working and to configure PBS, I suggest connecting via an SSH tunnel.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;# Create an SSH tunnel from your local machine to the backup server
# Port 8007 is forwarded to the PBS web UI
# Port 8751 is forwarded to the Minio console
ssh user@backupServerIP -L8007:192.168.0.3:8007 -L8751:192.168.0.11:8751
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This way, we'll create a tunnel between the FreeBSD backup server and our workstation, mapping &lt;code&gt;127.0.0.1:8007&lt;/code&gt; to &lt;code&gt;192.168.0.3:8007&lt;/code&gt; (the PBS web interface) and &lt;code&gt;127.0.0.1:8751&lt;/code&gt; to &lt;code&gt;192.168.0.11:8751&lt;/code&gt; (the Minio console port).&lt;/p&gt;
&lt;p&gt;Now, connect to &lt;code&gt;https://127.0.0.1:8751&lt;/code&gt;, enter the credentials specified in &lt;code&gt;/etc/rc.conf&lt;/code&gt;, and create a bucket.&lt;/p&gt;
&lt;p&gt;Once the bucket is created, you can configure PBS to use it. Connect to PBS via &lt;code&gt;https://127.0.0.1:8007&lt;/code&gt; and go to &lt;strong&gt;S3 Endpoints&lt;/strong&gt;. Set a name, use &lt;code&gt;192.168.0.11&lt;/code&gt; as the IP and &lt;code&gt;9000&lt;/code&gt; as the port, enter the access and secret keys, and the certificate fingerprint we generated earlier. &lt;strong&gt;Enable "Path Style"&lt;/strong&gt; or it will not work.&lt;/p&gt;
&lt;p&gt;Then go to &lt;strong&gt;Datastores&lt;/strong&gt; and add it, as you would for any other S3 datastore, by specifying the created bucket and a local directory where the system will keep its cache.&lt;/p&gt;
&lt;p&gt;If everything was set up correctly, PBS will create its structure in the bucket, and from that moment on, you can use it. Always keep in mind that this is still a "technology preview", so there may be issues, but from my tests, it is sufficiently reliable.&lt;/p&gt;
&lt;h3&gt;Taking Local Snapshots of Backups&lt;/h3&gt;
&lt;p&gt;One of the most common techniques used in ransomware attacks is to also delete or encrypt backups. They often use automated methods, relying on the fact that many (too many!) consider a "backup" to be a simple copy of files to a network share. However, it's not impossible that, in specific cases, they might compromise the machine and connect to the backup server. This is nearly impossible with a "pull" type backup (like the one managed by &lt;code&gt;zfs-autobackup&lt;/code&gt;) but is still possible with the "push" approach, which involves using BorgBackup or similar tools.&lt;/p&gt;
&lt;p&gt;This happened to one of my clients once - in that case, the problem originated internally, from an employee who wanted to cover up his mistake, inadvertently creating a disaster - but that will be material for another post.&lt;/p&gt;
&lt;p&gt;Fortunately, the client had a system that solved the problem: thanks to ZFS, we can have local snapshots on the backup server, which are invisible and inaccessible to the production server. Since we have already installed &lt;code&gt;zfs-autobackup&lt;/code&gt;, it's easy to use it for this purpose as well. I've already talked about this in a &lt;a href="https://it-notes.dragas.net/2024/08/21/automating-zfs-snapshots-for-peace-of-mind/"&gt;previous article&lt;/a&gt; and won't rewrite the steps here. Just consult that article, keeping in mind that in this case, it's not advisable to snapshot all the datasets on the backup server (the space would grow exponentially), but only those at risk. In the cases analyzed in this post, this applies only to the &lt;code&gt;push&lt;/code&gt; part, as PBS will also be accessible only from the Proxmox servers and not from the VMs they contain. If, in this case too, you don't trust those who manage the Proxmox servers, just set up snapshots for the Minio jail as well.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This long post aims to analyze, in a general way, how I believe one can manage reasonably secure backups of their data. Obviously, there are many variables, additional precautions, possible optimizations, hardening, etc., that must be studied on a case-by-case basis. There are old rules, new rules, old and new philosophies. Recently, many people who have embraced the cloud have often stopped thinking about backups, only to realize it when something happens and the data has, indeed, vanished... into the clouds.&lt;/p&gt;
&lt;p&gt;In this post, I have generically covered the setup of the backup server, and this demonstrates how FreeBSD, thanks to its features, can be considered an ideal platform for this type of task.&lt;/p&gt;
&lt;p&gt;In the next articles in this series, I will examine the client side, i.e., how to structure them for a sufficiently reliable backup, and how to monitor everything - because I've seen this too: people resting easy because the backup was supposedly running every night, but in fact, the backup had been failing every night for more than 4 years.&lt;/p&gt;
&lt;p&gt;Stay Tuned and stay...backupped!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 29 Jul 2025 08:00:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/07/29/make-your-own-backup-system-part-2-forging-the-freebsd-backup-stronghold/</guid><category>backup</category><category>freebsd</category><category>jail</category><category>bhyve</category><category>borg</category><category>data</category><category>server</category><category>vps</category><category>filesystems</category><category>proxmox</category><category>snapshots</category><category>sysadmin</category><category>virtualization</category><category>ownyourdata</category><category>zfs</category><category>series</category><category>tutorial</category></item><item><title>Migrating Windows VMs from Proxmox BIOS/KVM to FreeBSD UEFI/bhyve</title><link>https://it-notes.dragas.net/2024/11/15/migrating-windows-vms-from-bios-kvm-to-uefi-bhyve/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/datacenter.webp" alt="Migrating Windows VMs from Proxmox BIOS/KVM to FreeBSD UEFI/bhyve"&gt;&lt;/p&gt;&lt;p&gt;A client of mine has several Windows Server VMs, which I had not migrated to FreeBSD/bhyve until a few weeks ago. These VMs were originally installed with the traditional BIOS boot mode, not UEFI, on Proxmox. Fortunately, their virtual disks are on ZFS, which allowed me to test and achieve the final result in just a few steps.&lt;/p&gt;
&lt;p&gt;This is because Windows VMs (server or otherwise) often installed on KVM (Proxmox, etc.), especially older ones, are non-UEFI, using the traditional BIOS boot mode. bhyve doesn’t support this setup, but Windows allows changing the boot mode, and I could perform the migration directly on the target FreeBSD server.&lt;/p&gt;
&lt;h2&gt;Setting Up the Network&lt;/h2&gt;
&lt;p&gt;Before starting, as usual in my setups, I manually created the bridge and configured a few pf rules for outbound NAT, which these servers need. Let’s begin with the modifications to &lt;code&gt;/etc/rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;cloned_interfaces=&amp;quot;bridge0&amp;quot;
ifconfig_bridge0=&amp;quot;inet 192.168.33.1 netmask 255.255.255.0&amp;quot;
gateway_enable=&amp;quot;YES&amp;quot;
pf_enable=&amp;quot;YES&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, for the &lt;code&gt;pf.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;ext_if=&amp;quot;igb0&amp;quot;

set block-policy return
set skip on bridge0
set skip on lo0

# Allow the VMs to connect to the outside world
nat on $ext_if from {192.168.33.0/24} to any -&amp;gt; ($ext_if)

block in all
antispoof for $ext_if inet
pass in inet proto icmp
pass out quick keep state
pass in inet proto tcp from any to any port ssh flags S/SA keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To ensure everything is working as expected, I recommend rebooting the server. It’s not strictly necessary since you could reload network configurations and start pf without a reboot, but I prefer a few extra reboots in these cases. Why? Because system administrators are often afraid to reboot production servers, unsure if they will come back up smoothly. A configuration error could prevent a successful reboot, and this would be a significant issue if the server is already in production. I’ve faced this situation myself—many times! To mitigate this, I make frequent reboots, especially after changing network configurations, ensuring everything starts correctly on reboot.&lt;/p&gt;
&lt;h2&gt;Installing and Configuring vm-bhyve&lt;/h2&gt;
&lt;p&gt;Next, I installed &lt;code&gt;vm-bhyve&lt;/code&gt; on the target FreeBSD host and configured it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;pkg install vm-bhyve-devel bhyve-firmware
zfs create zroot/VMs
sysrc vm_enable=&amp;quot;YES&amp;quot;
sysrc vm_dir=&amp;quot;zfs:zroot/VMs&amp;quot;
vm init
cp /usr/local/share/examples/vm-bhyve/* /zroot/VMs/.templates/
vm switch create -t manual -b bridge0 public
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usually, I enable the serial console on tmux, but in this case, I’ll skip that since Windows VMs need a graphical console. If the FreeBSD server is not on your local network, I suggest connecting via SSH with port forwarding for the necessary VNC ports (e.g., &lt;code&gt;-L5900:127.0.0.1:5900&lt;/code&gt;) to connect to bhyve via SSH tunnel. Never expose the VNC port directly!&lt;/p&gt;
&lt;h2&gt;Creating the VM Template&lt;/h2&gt;
&lt;p&gt;Now, I created an “empty” VM using the “Windows” template with &lt;code&gt;vm-bhyve&lt;/code&gt; and adjusted the configuration afterward:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;vm create -t windows -s 1G -m 16G -c 4 vm115
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I created a virtual disk of 1 GB because it will be replaced by the dataset sent from the current production server, so it’s a fictitious size. At that point, I deleted the &lt;code&gt;disk0&lt;/code&gt; image file:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;rm /zroot/VMs/vm115/disk0.img
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Modifying the VM Configuration&lt;/h2&gt;
&lt;p&gt;Next, I modified the VM configuration as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changed the disk configuration to use a zvol, simplifying the send-receive operation from the original Proxmox host.&lt;/li&gt;
&lt;li&gt;In some cases, older Windows installations may not support the &lt;code&gt;nvme&lt;/code&gt; driver. If this happens, use &lt;code&gt;ahci-hd&lt;/code&gt; instead, as after the conversion Windows may fail to boot and display a BSOD.&lt;/li&gt;
&lt;li&gt;Changed the network adapter driver to &lt;code&gt;virtio-net&lt;/code&gt; (since it was already installed on the Proxmox VM).&lt;/li&gt;
&lt;li&gt;Set the network adapter MAC address to match the original VM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After running &lt;code&gt;vm configure vm115&lt;/code&gt;, the configuration should look something like this:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;loader=&amp;quot;uefi&amp;quot;
graphics=&amp;quot;yes&amp;quot;
xhci_mouse=&amp;quot;yes&amp;quot;
cpu=&amp;quot;4&amp;quot;
memory=&amp;quot;16G&amp;quot;

ahci_device_limit=&amp;quot;8&amp;quot;

network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;

disk0_type=&amp;quot;nvme&amp;quot;
disk0_name=&amp;quot;disk0&amp;quot;
disk0_dev=&amp;quot;sparse-zvol&amp;quot;

utctime=&amp;quot;no&amp;quot;
uuid=&amp;quot;myUUID&amp;quot;
network0_mac=&amp;quot;theProxmoxVirtualMachineMacAddress&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Copying the Virtual Disk&lt;/h2&gt;
&lt;p&gt;I took a snapshot of the virtual disks of the VMs on the original server and copied them to the target server:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;zfs snapshot vmpool/vm-115-disk-0@toSend01
zfs send -Rcv vmpool/vm-115-disk-0@toSend01 | mbuffer -m 128M | ssh user@FreebsdHostIP &amp;quot;zfs receive -F zroot/VMs/vm115/disk0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The VM’s disk will be transferred to the target host.&lt;/p&gt;
&lt;h2&gt;Converting BIOS to UEFI&lt;/h2&gt;
&lt;p&gt;At this point, bhyve expects a UEFI VM, but the VM we just copied is BIOS-based. In other words, it won’t boot as is.&lt;/p&gt;
&lt;p&gt;Luckily, Microsoft provides a tool to convert partitions and change the server from BIOS to UEFI. Of course, I would only use such a tool on a snapshot, and while I could do it directly on the source server, I prefer minimizing downtime and avoiding touching the original server. I want to perform the conversion directly on the FreeBSD host, which also makes disaster recovery easier, allowing me to manage everything on FreeBSD without first restoring the VM on a Proxmox server.&lt;/p&gt;
&lt;p&gt;The first step is to download a Windows installation ISO (in my case, Windows Server). I downloaded the ISO from here: &lt;a href="https://www.microsoft.com/en-us/evalcenter/download-windows-server-2022"&gt;Windows Server Evaluation Center&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once ready, launch the ISO as if you were installing Windows on the VM:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;vm install vm115 SERVER_EVAL_x64FRE_en-us.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Running the Windows Repair Tool&lt;/h2&gt;
&lt;p&gt;Now the VM will boot. Connect via VNC (if using VNC tunneling, connect to &lt;code&gt;127.0.0.1:5900&lt;/code&gt;) to proceed. The ISO will prompt you to press a key to boot from the CDROM—go ahead and do that.&lt;/p&gt;
&lt;p&gt;Proceed as if you were repairing your installation ("Repair your computer"), then select Troubleshoot -&amp;gt; Command Prompt.&lt;/p&gt;
&lt;p&gt;Once at the prompt, run a validation check first (to avoid making changes if the disk has any unusual configurations):&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;mbr2gpt /validate /disk:0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the validation is successful, proceed with the actual conversion:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;mbr2gpt /convert /disk:0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Windows will convert the partition and indicate success at the end.&lt;/p&gt;
&lt;h2&gt;Booting the VM&lt;/h2&gt;
&lt;p&gt;Close the command prompt and shut down the VM. Everything should be ready now—easy peasy.&lt;/p&gt;
&lt;p&gt;Boot the VM with:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;vm start vm115
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Connecting via VNC to the VM will bring up the Windows boot screen. In case of BSOD, change the &lt;code&gt;nvme&lt;/code&gt;driver to &lt;code&gt;ahci-hd&lt;/code&gt;and it should be working. If the snapshot was taken while the VM was powered on, it may perform a disk check. If everything went as planned, you should see the Windows login screen.&lt;/p&gt;
&lt;p&gt;Additionally, Windows will likely require reactivation of the VM, as it will detect hardware changes.&lt;/p&gt;
&lt;h2&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;At this point, you need to decide whether to continue with this VM or resynchronize it with the original (e.g., if the contents have changed). In the first case, no further action is needed. In the second case, the proper procedure would be to power off the original VM, create a new snapshot, roll back the snapshot on the FreeBSD host, transfer it incrementally—&lt;a href="https://it-notes.dragas.net/2024/10/21/from-proxmox-to-freebsd-story-of-a-migration/"&gt;a process I’ve described in a previous post&lt;/a&gt;—and then redo the conversion.&lt;/p&gt;
&lt;p&gt;To configure the VM to boot automatically when the FreeBSD host boots, add the necessary settings to &lt;code&gt;/etc/rc.conf&lt;/code&gt;, &lt;a href="https://it-notes.dragas.net/2024/10/21/from-proxmox-to-freebsd-story-of-a-migration/#configuring-automatic-vm-startup"&gt;as described in a previous article&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Fri, 15 Nov 2024 10:57:00 +0100</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/11/15/migrating-windows-vms-from-bios-kvm-to-uefi-bhyve/</guid><category>freebsd</category><category>proxmox</category><category>ownyourdata</category><category>bhyve</category><category>virtualization</category><category>server</category><category>filesystems</category><category>windows</category><category>snapshots</category><category>zfs</category></item><item><title>From Proxmox to FreeBSD - Story of a Migration</title><link>https://it-notes.dragas.net/2024/10/21/from-proxmox-to-freebsd-story-of-a-migration/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/server_rack.webp" alt="From Proxmox to FreeBSD - Story of a Migration"&gt;&lt;/p&gt;&lt;p&gt;I have been managing a client's server for several years. I inherited a setup (actually, partly done by me at the time, but following the directions of their internal administrator) based on Proxmox. Originally, the VM disks were &lt;code&gt;qcow2&lt;/code&gt; files, but over time and with Proxmox updates, I managed to create a ZFS pool and move them onto it. For backups, I continued to use Proxmox Backup Server (even though virtualized on bhyve) - a solution we've been using for several years.&lt;/p&gt;
&lt;p&gt;The existing VMs/containers were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An LXC container based on Debian&lt;/strong&gt;, with Apache as a reverse proxy. The choice of Apache was mainly tied to specific configurations from the company that produces the underlying software. It has always done an excellent job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A VM running OPNsense&lt;/strong&gt; — the choice was related to direct use by the client, as it allows easy creation/modification of users for the internal VPN. Some users can access via VPN (OpenVPN) and perform specific operations, such as SSH connections. It has always worked well and is up to date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two VMs based on Rocky Linux 9&lt;/strong&gt; — both with components of the management software in Java, with the reverse proxy directing requests based on the requested site.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two VMs based on Rocky Linux 8&lt;/strong&gt; — these also have parts of the management software and the databases. These machines are used both by providing specific URLs and by the other two as databases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The load is not particularly high, and the machines have good performance. Suddenly, however, I received a notification: one of the NVMe drives died abruptly, and the server rebooted. ZFS did its job, and everything remained sufficiently secure, but since it's a leased server and already several years old, I spoke with the client and proposed getting more recent hardware and redoing the setup &lt;a href="https://it-notes.dragas.net/2022/01/24/why-were-migrating-many-of-our-servers-from-linux-to-freebsd/"&gt;based&lt;/a&gt; on a &lt;a href="https://it-notes.dragas.net/2024/10/03/i-solve-problems-eurobsdcon/"&gt;FreeBSD&lt;/a&gt; host.&lt;/p&gt;
&lt;p&gt;Unfortunately, I cannot change the setup of the VMs. In my opinion, there are no contraindications since the databases are PostgreSQL and the management applications are Java applications with Tomcat. However, the software house only certifies that type of setup, and considering they are the ones performing updates and fixes, it's appropriate to maintain the setup they suggest. It's a technically sound choice in my opinion, so I can't say anything negative.&lt;/p&gt;
&lt;h2&gt;Acquiring New Hardware&lt;/h2&gt;
&lt;p&gt;The first step was, of course, to get the new server. It took a few days because I requested ECC RAM (for a small price variation), and the time extended. As soon as the physical server was ready, I got to work.&lt;/p&gt;
&lt;p&gt;I installed &lt;strong&gt;FreeBSD 14.1-RELEASE&lt;/strong&gt;, root on ZFS, creating a mirror setup between the NVMe drives. The I/O is not particularly heavy in this setup, but I don't want to waste potential: even if I can reduce the length of an operation by a few seconds, I see no reason not to do it.&lt;/p&gt;
&lt;p&gt;As the first step, I decided to manually create the bridge to which I will connect both the VMs and the reverse proxy, which will be installed inside a FreeBSD jail.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vm-bhyve&lt;/code&gt;, the tool I use to manage VMs, allows creating bridges, but I prefer to manage it manually and maintain more complete control over everything. I will also enable &lt;code&gt;pf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I decided to use &lt;code&gt;zstd&lt;/code&gt; as the compression algorithm and disable &lt;code&gt;atime&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs set compression=zstd zroot
zfs set atime=off zroot
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I then modified the &lt;code&gt;/etc/rc.conf&lt;/code&gt; file as follows:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;cloned_interfaces=&amp;quot;bridge0 lo1&amp;quot;
ifconfig_lo1_name=&amp;quot;bastille0&amp;quot;
ifconfig_bridge0=&amp;quot;inet 192.168.33.1 netmask 255.255.255.0&amp;quot;
gateway_enable=&amp;quot;YES&amp;quot;
pf_enable=&amp;quot;YES&amp;quot;
bastille_enable=&amp;quot;YES&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I then updated FreeBSD by running the usual command:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;freebsd-update fetch install
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Configuring the Firewall&lt;/h2&gt;
&lt;p&gt;I configured the firewall with a basic setup:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-pf"&gt;ext_if=&amp;quot;igb0&amp;quot;

set block-policy return
set skip on bridge0

table &amp;lt;jails&amp;gt; persist
nat on $ext_if from {192.168.33.0/24} to any -&amp;gt; ($ext_if)
nat on $ext_if from &amp;lt;jails&amp;gt; to any -&amp;gt; ($ext_if:0)

# nginx-proxy - to the jail
rdr on $ext_if inet proto tcp from any to PUBLIC_IP port = 80 -&amp;gt; 192.168.33.254 port 80
rdr on $ext_if inet proto tcp from any to PUBLIC_IP port = 443 -&amp;gt; 192.168.33.254 port 443

# opnsense
rdr on $ext_if inet proto tcp from any to PUBLIC_IP port = 1194 -&amp;gt; 192.168.33.253 port 1194
rdr on $ext_if inet proto udp from any to PUBLIC_IP port = 1194 -&amp;gt; 192.168.33.253 port 1194

rdr-anchor &amp;quot;rdr/*&amp;quot;

block in all
antispoof for $ext_if inet
pass in inet proto icmp
pass out quick keep state
pass in inet proto tcp from any to any port {http,https} flags S/SA keep state
pass in inet proto {tcp,udp} from any to any port 1194 flags S/SA keep state
# This will be closed at the end of the setup and will be allowed only via VPN
pass in inet proto tcp from any to any port ssh flags S/SA keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once finished, I rebooted everything to load the new kernel. No problems.&lt;/p&gt;
&lt;h2&gt;Installing Necessary Tools&lt;/h2&gt;
&lt;p&gt;I then installed some useful packages:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;pkg install tmux py311-zfs-autobackup mbuffer rsync vm-bhyve-devel edk2-bhyve grub2-bhyve bastille
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I created the datasets for the jails and VMs:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs create zroot/bastille
zfs create zroot/VMs
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I then started configuring everything. First, &lt;strong&gt;BastilleBSD&lt;/strong&gt;: I modified &lt;code&gt;/usr/local/etc/bastille/bastille.conf&lt;/code&gt; by adding:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;## ZFS options
bastille_zfs_enable=&amp;quot;YES&amp;quot;
bastille_zfs_zpool=&amp;quot;zroot/bastille&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then I enabled and configured &lt;code&gt;vm-bhyve&lt;/code&gt;, enabling the serial console on tmux:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;sysrc vm_enable=&amp;quot;YES&amp;quot;
sysrc vm_dir=&amp;quot;zfs:zroot/VMs&amp;quot;
vm init
cp /usr/local/share/examples/vm-bhyve/* /zroot/VMs/.templates/
vm switch create -t manual -b bridge0 public
vm set console=tmux
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now I bootstrapped FreeBSD 14.1-RELEASE on BastilleBSD:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;bastille bootstrap 14.1-RELEASE update
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Setting Up the Reverse Proxy Jail&lt;/h2&gt;
&lt;p&gt;I then started by creating the jail for the reverse proxy:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;bastille create -B apache 14.1-RELEASE 192.168.33.254/24 bridge0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once created, I had to modify the default gateway of the jail because by default it is set to that of the host. It was enough to set &lt;code&gt;192.168.33.1&lt;/code&gt; in &lt;code&gt;/usr/local/bastille/jails/apache/root/etc/rc.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The configuration of Apache will not be described here as it is closely dependent on the setup, but this jail can reach (in bridge mode) all the VMs that will be placed on the same bridge.&lt;/p&gt;
&lt;h2&gt;Migrating the VMs&lt;/h2&gt;
&lt;p&gt;For migrating the VMs, I decided to proceed as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Updating the operating systems&lt;/strong&gt; of the original VMs - to have the latest version of the kernel and all userland. The VMs are not UEFI, so it will be necessary to have the exact names of the kernel and &lt;code&gt;initrd&lt;/code&gt; as they will need to be specified in the configuration file of &lt;code&gt;vm-bhyve&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creating templates&lt;/strong&gt; of the VMs with &lt;code&gt;vm-bhyve&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Snapshotting the VM disks&lt;/strong&gt; and initial transfer to the new server with the VMs still running.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shutting down all the source VMs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creating a new snapshot&lt;/strong&gt; and performing an incremental transfer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adjusting configurations&lt;/strong&gt; and changing DNS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I updated everything using &lt;code&gt;dnf&lt;/code&gt;, and rebooted when there was also a kernel update. I took note of the versions to use, namely &lt;code&gt;vmlinuz-4.18.0-513.18.1.el8_9.x86_64&lt;/code&gt; and &lt;code&gt;initramfs-4.18.0-513.18.1.el8_9.x86_64.img&lt;/code&gt; for Rocky Linux 8.10, and &lt;code&gt;vmlinuz-5.14.0-362.18.1.el9_3.0.1.x86_64&lt;/code&gt; and &lt;code&gt;initramfs-5.14.0-362.18.1.el9_3.0.1.x86_64.img&lt;/code&gt; for Rocky Linux 9.4.&lt;/p&gt;
&lt;h3&gt;Migrating Rocky Linux 8.10 VMs&lt;/h3&gt;
&lt;p&gt;On the destination server, I created the VMs. I used the &lt;code&gt;linux-zvol&lt;/code&gt; template, then modified the configurations:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;vm create -t linux-zvol -s 1G -m 8G -c 4 vm100
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I created a virtual disk of 1 GB because it will be replaced by the dataset sent from the current production server, so it's a fictitious size. At that point, I deleted the &lt;code&gt;zvol&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs destroy zroot/VMs/vm100/disk0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I performed an initial snapshot of the source VMs:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs snapshot zfspool/vm-100-disk-0@Move01
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then I copied this first snapshot to the destination machine/VM:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs send -R zfspool/vm-100-disk-0@Move01 | mbuffer -s 128k -m 512M | ssh root@destMachine &amp;quot;zfs receive -F zroot/VMs/vm100/disk0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the end of the copy, you can do a test and try to boot. For the Rocky Linux 8.10 VMs, I had no problems because the &lt;code&gt;/boot&lt;/code&gt; partition is in &lt;code&gt;ext4&lt;/code&gt;. I then configured the VM as follows, running the command &lt;code&gt;vm configure vm100&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;loader=&amp;quot;grub&amp;quot;
cpu=&amp;quot;8&amp;quot;
memory=&amp;quot;12G&amp;quot;
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;virtio-blk&amp;quot;
disk0_name=&amp;quot;disk0&amp;quot;
disk0_dev=&amp;quot;sparse-zvol&amp;quot;
uuid=&amp;quot;the-uuid&amp;quot;
network0_mac=&amp;quot;the-mac&amp;quot;
grub_run0=&amp;quot;linux /vmlinuz-4.18.0-553.22.1.el8_10.x86_64 root=/dev/vda3&amp;quot;
grub_run1=&amp;quot;initrd /initramfs-4.18.0-553.22.1.el8_10.x86_64.img&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All I needed to do is: pass to GRUB the name of the kernel and the &lt;code&gt;initramfs&lt;/code&gt;. It is now possible to start the machine and do a test and connect to the console:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;vm start vm100
vm console vm100
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In theory, the machine should boot correctly. It will probably be necessary to change the network interface configurations - in my case, even keeping the &lt;code&gt;virtio&lt;/code&gt; and the MAC address, it changed from &lt;code&gt;ens18&lt;/code&gt; to &lt;code&gt;enp0s5&lt;/code&gt; - but everything else should be fine.&lt;/p&gt;
&lt;p&gt;At this point, if the source VM was turned off/not reachable or simply there is nothing new to synchronize, the migration is complete. Otherwise, it will be necessary to shut down the source VM, create a new snapshot, and transfer it. Let's start by shutting down the source VM and the destination one (&lt;code&gt;vm stop vm100&lt;/code&gt;), roll back to the snapshot transferred to the destination server, create a new snapshot, and perform an incremental transfer:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs rollback zroot/VMs/vm100/disk0@Move01
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On the source server:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs snapshot zfspool/vm-100-disk-0@Move02
zfs send -R -i zfspool/vm-100-disk-0@Move01 zfspool/vm-100-disk-0@Move02 | mbuffer -s 128k -m 512M | ssh root@destMachine &amp;quot;zfs receive -F zroot/VMs/vm100/disk0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this way, we have updated the destination VM and transferred only the differences, without altering the configuration of &lt;code&gt;vm-bhyve&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Start the machine - if all goes well, the migration of this VM is finished.&lt;/p&gt;
&lt;h3&gt;Migrating Rocky Linux 9.4 VMs&lt;/h3&gt;
&lt;p&gt;For the Rocky Linux 9.4 VMs, the situation was more complex: the partitions were all - even &lt;code&gt;/boot&lt;/code&gt;—in &lt;strong&gt;XFS&lt;/strong&gt;. And, for some reason, the GRUB launched by bhyve cannot read from XFS. Therefore, I had to proceed differently.&lt;/p&gt;
&lt;p&gt;I copied, using &lt;code&gt;rsync&lt;/code&gt;, the &lt;code&gt;/boot&lt;/code&gt; of the original VPS (in ZFS) to a directory on the FreeBSD server (specifically, on the VPS I ran the command: &lt;code&gt;rsync -avhHPx --numeric-ids /boot root@FreeBSDHOST:/tmp/&lt;/code&gt;). In this way, I kept the files available.&lt;/p&gt;
&lt;p&gt;I shut down the machine on the original server and copied its &lt;code&gt;zvol&lt;/code&gt; to the new FreeBSD host using the same method as the others. At that point, I recreated the &lt;code&gt;/boot&lt;/code&gt; partition of my VPS in &lt;code&gt;ext3&lt;/code&gt; - directly from the FreeBSD host:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;pkg install fusefs-ext2
kldload fusefs
mkfs.ext3 /dev/zvol/zroot/VMs/vm104/disk0s1
fuse-ext2 -o force /dev/zvol/zroot/VMs/vm104/disk0s1 /mnt/
cd /mnt
rsync -avhHPx /tmp/boot/. .
umount /mnt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this way, GRUB will be able to access the &lt;code&gt;/boot&lt;/code&gt; partition to load the kernel and &lt;code&gt;initramfs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is the &lt;code&gt;vm-bhyve&lt;/code&gt; configuration for this VM:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;loader=&amp;quot;grub&amp;quot;
cpu=&amp;quot;8&amp;quot;
memory=&amp;quot;12G&amp;quot;
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;virtio-blk&amp;quot;
disk0_name=&amp;quot;disk0&amp;quot;
disk0_dev=&amp;quot;sparse-zvol&amp;quot;
uuid=&amp;quot;the-uuid&amp;quot;
network0_mac=&amp;quot;the-mac&amp;quot;
grub_run0=&amp;quot;linux /vmlinuz-5.14.0-427.37.1.el9_4.x86_64 root=/dev/vda3&amp;quot;
grub_run1=&amp;quot;initrd /initramfs-5.14.0-427.37.1.el9_4.x86_64.img&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Launching the machine, however, it will hang during boot and, after a timeout, will ask for administrator credentials to enter a recovery shell. This is because the &lt;code&gt;blkid&lt;/code&gt; of the &lt;code&gt;/boot&lt;/code&gt; partition has changed, and the &lt;code&gt;fstab&lt;/code&gt; of the VM still reports the data of the old XFS partition. In this case, I used the &lt;code&gt;blkid&lt;/code&gt; command in the VM and copied the UUID of the new partition. Then modify the &lt;code&gt;/etc/fstab&lt;/code&gt; file of the VM and put the new &lt;code&gt;blkid&lt;/code&gt;, as well as changing "xfs" to "ext3". After a reboot, the system should start without problems, again with a network card to reconfigure.&lt;/p&gt;
&lt;p&gt;This procedure worked correctly for all VMs. In this way, the storage remains on &lt;code&gt;virtio-blk&lt;/code&gt; even if it would be optimal for the driver to be changed to &lt;code&gt;nvme&lt;/code&gt;. To make this change, you will need to enter the VMs, create a file called &lt;code&gt;/etc/dracut.conf.d/00-custom.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-conf"&gt;add_drivers+=&amp;quot; nvme &amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And regenerate the &lt;code&gt;initramfs&lt;/code&gt; - in this way, the &lt;code&gt;nvme&lt;/code&gt; driver will be supported at boot:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;dracut --regenerate-all --force
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will now be enough to change the configurations of &lt;code&gt;vm-bhyve&lt;/code&gt;—&lt;code&gt;virtio-blk&lt;/code&gt; becomes &lt;code&gt;nvme&lt;/code&gt;, and &lt;code&gt;/dev/vda3&lt;/code&gt; becomes &lt;code&gt;/dev/nvme0n1p3&lt;/code&gt;, for example:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;loader=&amp;quot;grub&amp;quot;
cpu=&amp;quot;8&amp;quot;
memory=&amp;quot;12G&amp;quot;
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;nvme&amp;quot;
disk0_name=&amp;quot;disk0&amp;quot;
disk0_dev=&amp;quot;sparse-zvol&amp;quot;
uuid=&amp;quot;the-uuid&amp;quot;
network0_mac=&amp;quot;the-mac&amp;quot;
grub_run0=&amp;quot;linux /vmlinuz-5.14.0-427.37.1.el9_4.x86_64 root=/dev/nvme0n1p3&amp;quot;
grub_run1=&amp;quot;initrd /initramfs-5.14.0-427.37.1.el9_4.x86_64.img&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Migrating the OPNsense VM&lt;/h3&gt;
&lt;p&gt;For the VM with OPNsense, the procedure was even simpler. It was enough to create a VM of type &lt;code&gt;freebsd-zvol&lt;/code&gt; and copy the disk as done for the others. In this case, I replicated the MAC address of the original virtualized network interface (Proxmox server) to ensure that the underlying FreeBSD recognizes it as the same. FreeBSD is less picky about these things.&lt;/p&gt;
&lt;p&gt;The final &lt;code&gt;vm-bhyve&lt;/code&gt; configuration file will be:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;loader=&amp;quot;bhyveload&amp;quot;
cpu=&amp;quot;2&amp;quot;
memory=&amp;quot;1G&amp;quot;
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;virtio-blk&amp;quot;
disk0_name=&amp;quot;disk0&amp;quot;
disk0_dev=&amp;quot;sparse-zvol&amp;quot;
uuid=&amp;quot;my-uuid&amp;quot;
network0_mac=&amp;quot;my-mac&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Configuring Automatic VM Startup&lt;/h2&gt;
&lt;p&gt;To ensure that the VMs all start at boot, just add them to &lt;code&gt;/etc/rc.conf&lt;/code&gt; as follows, giving a 15-second delay between one VM and another:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;[...]
vm_enable=&amp;quot;YES&amp;quot;
vm_dir=&amp;quot;zfs:zroot/VMs&amp;quot;
vm_list=&amp;quot;vm100 vm101 [...] opnsense&amp;quot;
vm_delay=&amp;quot;15&amp;quot;
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Setting Up Backups&lt;/h2&gt;
&lt;p&gt;At this point, I configured external backups, every hour, similarly to &lt;a href="https://it-notes.dragas.net/2022/05/30/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-2/"&gt;how I described in a previous article&lt;/a&gt;. I also added a local snapshot every 15 minutes, always using &lt;code&gt;zfs-autobackup&lt;/code&gt;. To do this, I created a new tag:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;zfs set autobackup:localsnap=true zroot
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then I modified the &lt;code&gt;/etc/crontab&lt;/code&gt; file, adding this line:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-cron"&gt;*/15    *       *       *       *       root    /usr/local/bin/zfs-autobackup localsnap --keep-source 15min3h,1h1d &amp;gt; /dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is, it will perform a snapshot every 15 minutes and keep them for 3 hours, then keep one per hour for a day. In this way, in case of quick recovery due to a problem/error, I won't need to transfer the entire dataset/VM from the backup.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The migration is complete: after changing the DNS, the client performed some tests, and everything works properly. The setup has been active for over a week, and there have been no issues. The performance is excellent; I did not perform tests compared to the previous setup since the hardware of the new FreeBSD host is more powerful and modern, so it wouldn't make sense.&lt;/p&gt;
&lt;p&gt;Apart from the manager, no user was informed of the change, and in the last week, no reports have been received. The VMs are stable, and the host's load is very low.&lt;/p&gt;
&lt;p&gt;The operation actually took less than two hours in total - most of the time has been consumed by the send/receive operations - and gave excellent results. The alternative would have been to install Proxmox on a new host and move the VMs - I probably would have saved a few minutes, but now I can use bhyve, as well as the simplicity and power of the underlying FreeBSD.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Mon, 21 Oct 2024 07:33:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/10/21/from-proxmox-to-freebsd-story-of-a-migration/</guid><category>freebsd</category><category>proxmox</category><category>ownyourdata</category><category>bhyve</category><category>virtualization</category><category>server</category><category>filesystems</category><category>linux</category><category>snapshots</category><category>zfs</category></item><item><title>From Cloud Chaos to FreeBSD Efficiency</title><link>https://it-notes.dragas.net/2024/07/04/from-cloud-chaos-to-freebsd-efficiency/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/datacenter.webp" alt="From Cloud Chaos to FreeBSD Efficiency"&gt;&lt;/p&gt;&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A few months ago, a client asked me to take care of their Kubernetes cluster (hosted on AWS and GCP). In their opinion, the costs were exorbitantly high for relatively simple and lean websites. Sure, they had many visits, but nothing too excessive development-wise.&lt;/p&gt;
&lt;p&gt;I kindly declined. Unfortunately, their situation is all too common these days: they hired developers accustomed to working that way, convinced that a system administrator is now unnecessary because "the cloud has infinite potential." They were used to considering optimization as secondary because "we have infinite power" (and this is already a spoiler for the ending).&lt;/p&gt;
&lt;p&gt;Being open to dialogue and new experiences, they asked for my opinion on the matter. We talked for a while, and I explained that, in my view, for the type of setup they had (standard, with various replicas and variants, but primarily based on two platforms), it didn't make sense. I saw it as complicating things. An over-engineering of something simple. Like taking a cruise ship to cross a river.&lt;/p&gt;
&lt;p&gt;They then asked me to create something simple that would serve as a development server and for backups, to understand what kind of solution I had in mind.&lt;/p&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;So, I started building everything. I began with FreeBSD 13.2-RELEASE, but in the meantime, 14.0-RELEASE came out, so that’s the version I delivered.&lt;/p&gt;
&lt;p&gt;I installed the operating system on a physical server, leased from one of the main European providers. Benefiting from one of their auctions (good deals can be found on weekends), they found a sufficiently powerful machine, with 128GB of RAM, 2 NVMe drives of 1TB each, and two spinning disks of 2TB each for less than 100 euros per month. They also took another, less powerful one for additional backups and to back up the first one.&lt;/p&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;p&gt;I decided to keep the host as clean as possible and concentrated the services in jails (managed by BastilleBSD) and VMs. The machine was divided as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A series of bridges - to be used for different projects. Jails of the same project and/or type use the same bridge and can communicate with each other, sharing some resources (MariaDB, etc.).&lt;/li&gt;
&lt;li&gt;A bhyve VM with &lt;a href="https://alpinelinux.org/"&gt;Alpine Linux&lt;/a&gt; - in my opinion, the best distribution for running Docker containers. Do we really need systemd just to launch Docker? They mainly use it as a pre-production test bench, connected via VPN to their company LAN. It is the core of their "online" development, i.e., outside their computers. It has 32GB of RAM, 200GB of disk (obviously bhyve is configured with NVMe drivers), and 4 cores assigned.&lt;/li&gt;
&lt;li&gt;A VNET jail with a reverse proxy (nginx) - they know how to modify virtual hosts and generate certificates with certbot, pointing to the underlying jails.&lt;/li&gt;
&lt;li&gt;A series of "empty" VNET jails, to be cloned, for each type of setup (they mainly have CMS based on WordPress and Laravel, so with all dependencies inside - nginx, php, redis, etc. except the databases).&lt;/li&gt;
&lt;li&gt;A VNET jail with MariaDB installed, to be cloned, to be attached to different projects as needed.&lt;/li&gt;
&lt;li&gt;zfs-autobackup performs local snapshots, keeping: one every 15 minutes for 3 hours, one per hour for 24 hours, one per day for 3 days.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Backups &lt;a href="https://it-notes.dragas.net/2022/05/30/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-2/"&gt;are also performed using zfs-autobackup&lt;/a&gt; and, in case of disaster recovery in rapid times, a zfs-send (and corresponding zfs-receive) every 10 minutes on another machine (the other, smaller one, also taken at auction), with the same bridges, firewall rules, BastilleBSD, and bhyve installed - ready to start in case of disaster. Being a test server, we didn't consider to implement a proper HA - at the moment, it wouldn't make sense.&lt;/p&gt;
&lt;p&gt;They also have another job with zfs-autobackup that performs an additional backup on a server (Debian in their offices). &lt;a href="https://my-notes.dragas.net/posts/2024/who-is-the-real-owner-of-your-data/"&gt;Safe data, in my opinion, are those in storage under your b...ench&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I delivered everything to them and gave a brief course to the more experienced devs on how to manage things. No explanation on the Alpine Linux VM, but I showed them the jails, how to clone, configure, and manage them.&lt;/p&gt;
&lt;h2&gt;Real-world Testing&lt;/h2&gt;
&lt;p&gt;I didn't hear from them anymore. After a few weeks, one of the devs contacted me urgently because a junior unfortunately made a mistake and deleted an entire project from one of the jails. I explained that the local snapshots were restorable with a command, and he was thrilled. He restored both the development jail and the one with the database made two minutes before the "mishap" and they restarted immediately.&lt;/p&gt;
&lt;p&gt;I realized that this event would change some of their procedures and criteria.&lt;/p&gt;
&lt;p&gt;I hadn't heard from anyone for months. This morning, I received a call from their manager, whom I hadn't heard from since the beginning, and he told me how things had been going these months.&lt;/p&gt;
&lt;h2&gt;Lessons Learned&lt;/h2&gt;
&lt;p&gt;First, this person has good communication and commercial skills but little technical background. He is open-minded and tends to study carefully what is proposed to him. He doesn't discard any solution a priori, without having touched its pros and cons.&lt;/p&gt;
&lt;p&gt;They had leased servers with cPanel and were inserting their content inside them. The devs who arrived a few years ago suggested making a technological transition, eliminating these "obsolete" servers and "outdated" methodologies, pushing everything to the cloud and containerizing everything. When we first talked, he told me how they were "lucky to make that transition because their load had increased enormously and the old servers probably wouldn't have handled the load", instead autoscaling saved them. I had some reservations about autoscaling without particular controls, but clearly, I cannot impose my choices on others.&lt;/p&gt;
&lt;p&gt;To cut a long story short: seeing what happened with that junior dev's mistake (and the simplicity with which it was possible to restart immediately), they decided to increase the use of FreeBSD jails and reduce, at least on secondary loads, the use of their Cloud managed with Kubernetes. As they transitioned to jails, however, they noticed some slowdowns. These slowdowns worsened day by day. According to the devs, it would have been appropriate to go back to having, again, autoscaling ("we need moar powaaaaar!!!") but, fortunately, their boss decided to investigate carefully. They realized that these workloads (based on &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt;) were storing sessions on files. Over time, these millions of files (several gigabytes per day) slowed everything down because, for specific operations, Laravel scanned the entire directory. In other words, on the "cloud," they needed much more power than necessary (and much more disk space, but that was cheaper) to carry this load, which was, in fact, unnecessary. After realizing this, they moved the sessions to Redis. Needless to say, everything became extremely faster, even compared to the previous setup on Kubernetes and autoscaling.&lt;/p&gt;
&lt;p&gt;At that point, it was clear that one of the problems with their setup is (as often happens) poor optimization. Today, there's a tendency to rush, "throw in" functions, features, libraries, plugins, etc. without considering the interactions and consequences. If it works, it's fine. Even if it increases computational complexity exponentially just to, for example, change the color of an icon (absurd example, but to give an idea).&lt;/p&gt;
&lt;p&gt;They then started moving even the main Laravel workloads (thanks to the optimization implemented). At this point, they began moving some of the WordPress sites even though they were extremely concerned. In the cluster, every day, at fairly irregular intervals, the load would rise and everything would slow down until autoscaling started scaling up to the imposed limits. CPU at 100% on all containers, and the devs noticed that the load came from a series of "php" processes. Recreating the containers helped for some minutes, but did not solve the problem.&lt;/p&gt;
&lt;p&gt;To their great surprise, all this did not happen on the FreeBSD jails. The load was significantly lower, without any of these spikes. Satisfied, they decided to use this as their final setup. One of the devs, however, wanted to get to the bottom of it and decided to run a test: he moved some of these WordPress sites to the Alpine VM, on Docker. At that point, the spikes resumed, saturating the CPU of the Alpine machine.&lt;/p&gt;
&lt;p&gt;Without going into details, they eventually realized that there was a vulnerability in one (or more) of the many plugins installed on the WordPress sites, which was being exploited to inject a process, probably a cryptominer. The name given to the process was "php" - so the devs, not being system experts, did not worry about understanding better whether it was really php or another process pretending to be it. On FreeBSD, all this did not happen because the injected executable could not run - there was no &lt;a href="https://docs.freebsd.org/en/books/handbook/linuxemu/"&gt;Linux compatibility&lt;/a&gt; activated on the server.&lt;/p&gt;
&lt;p&gt;Until then, they considered these (expensive) spikes as organic and did not worry too much about them. Paying to have their friendly intruders mine.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;They asked me to help, as much as possible, to &lt;a href="https://it-notes.dragas.net/2022/02/05/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-1-system-and-jails-setup/"&gt;move other services to FreeBSD&lt;/a&gt;. It won't be easy, probably we will need to use bhyve a lot, but they decided that this is the platform they want to focus on in the coming years.&lt;/p&gt;
&lt;p&gt;Undoubtedly, this is a success story of FreeBSD and, indirectly, of correct and careful management of one's resources. Too often today, there is the superficial belief that the cloud, with its "infinite" resources, is the solution to all problems. And that Kubernetes is the best solution for everything. I, on the other hand, have always believed that there is the right tool for everything. You can hammer a nail with a screwdriver, but it's not the most suitable and efficient tool.&lt;/p&gt;
&lt;p&gt;Today they spend about 1/10 of what they used to spend before, they have more control over their data and the tools they use. Undoubtedly, all this was also caused by poor optimization and control by those who manage the infrastructure, but the question is: how often do people decide that, in the end, it is okay to spend more (especially if it is someone else's money) rather than go crazy for hours behind such a situation? While having defined and limited resources (albeit elevated) poses different problems - but of optimization. And in the age of energy and resource savings, it might be wise to give more importance to optimization.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Abundance led to waste&lt;/em&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Thu, 04 Jul 2024 08:41:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/07/04/from-cloud-chaos-to-freebsd-efficiency/</guid><category>freebsd</category><category>zfs</category><category>backup</category><category>data</category><category>filesystems</category><category>snapshots</category><category>recovery</category><category>networking</category><category>security</category><category>server</category><category>hosting</category><category>linux</category><category>ownyourdata</category><category>jail</category><category>virtualization</category><category>alpine</category><category>bhyve</category><category>docker</category></item><item><title>Proxmox vs FreeBSD: Which Virtualization Host Performs Better?</title><link>https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/server_rack.webp" alt="Proxmox vs FreeBSD: Which Virtualization Host Performs Better?"&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Skip to the &lt;a href="/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/#heading-11"&gt;Conclusion&lt;/a&gt; for a summary. &lt;/p&gt;
&lt;h3&gt;Preamble&lt;/h3&gt;
&lt;p&gt;I have always been passionate about virtualization and have consistently used it. &lt;/p&gt;
&lt;p&gt;The first solution I installed on my infrastructures (and those of clients) was &lt;a href="https://it-notes.dragas.net/2023/08/27/that-old-netbsd-server-running-since-2010/"&gt;Xen on NetBSD&lt;/a&gt;, with great success. I then used Xen on Linux and, since 2012, OpenNebula, followed by Proxmox in 2013. &lt;a href="https://it-notes.dragas.net/categories/proxmox/"&gt;Proxmox&lt;/a&gt; has always given me great satisfaction, and even today I consider it a valuable platform that I install gladly. I have also used other hypervisors like &lt;a href="https://xcp-ng.org/"&gt;XCP-ng&lt;/a&gt; but less frequently, and in recent years, I have started to make extensive use of bhyve. &lt;/p&gt;
&lt;p&gt;About two and a half years ago, &lt;a href="https://it-notes.dragas.net/2022/01/24/why-were-migrating-many-of-our-servers-from-linux-to-freebsd/"&gt;we began a progressive process of migrating our servers (and those of our clients) from Linux to FreeBSD&lt;/a&gt;, &lt;a href="https://it-notes.dragas.net/2022/02/05/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-1-system-and-jails-setup/"&gt;using jails&lt;/a&gt; (when possible) or VMs on bhyve. In some cases, &lt;a href="https://it-notes.dragas.net/2023/03/14/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-3/"&gt;migrating setups from Proxmox to FreeBSD&lt;/a&gt; resulted in performance improvements, even with the same hardware. In some instances, 
I migrated VMs without notifying clients, and they contacted me a few days later to inquire if we had new hardware because they noticed better performance. &lt;/p&gt;
&lt;p&gt;After years, I decided to conduct a test to determine if this was just a perception or if there was a technical basis behind it. Of course, &lt;em&gt;this test has no scientific validity&lt;/em&gt;, and the results were obtained on specific hardware and at a specific time, so on different hardware, workload, and situations, the results could be entirely opposite. 
However, I tried to have as scientific and objective an approach as possible since I am comparing two solutions that I care about and use daily. &lt;/p&gt;
&lt;h3&gt;Hardware and Test Conditions&lt;/h3&gt;
&lt;p&gt;I often see comparative tests done on VMs from various providers. In my opinion, this comparison makes no sense because a VM from any provider shares its hardware with many other VMs, so the results will vary depending on the load of the "neighbors" and will never be reliable. &lt;/p&gt;
&lt;p&gt;For this test, I decided to take a physical server with the following characteristics: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intel Core i7-6700 &lt;/li&gt;
&lt;li&gt;2x SSD M.2 NVMe 512 GB &lt;/li&gt;
&lt;li&gt;4x RAM 16384 MB DDR4 &lt;/li&gt;
&lt;li&gt;NIC 1 Gbit Intel I219-LM &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The hardware is not recent, but still very widespread. On more recent hardware, the results might differ, but the test will be based on this configuration. &lt;/p&gt;
&lt;p&gt;I installed &lt;a href="https://www.proxmox.com/en/"&gt;Proxmox 8.2.2&lt;/a&gt; starting from the Debian template of the provider and &lt;a href="https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_12_Bookworm"&gt;manually installed it following the instructions&lt;/a&gt;. I created a partition for Proxmox and left one partition free on each of the two NVME drives to create (at different times) the ZFS pool (in mirror) and the LVM on top of the Linux software raid. &lt;/p&gt;
&lt;p&gt;After all the tests, I installed &lt;a href="https://www.freebsd.org/"&gt;FreeBSD&lt;/a&gt; 14.1-RELEASE on ZFS on the same host, using &lt;em&gt;bsdinstall&lt;/em&gt; from an &lt;a href="https://mfsbsd.vx.sk/"&gt;mfsbsd image&lt;/a&gt; since the provider does not directly support installing FreeBSD from its panel or rescue mode. &lt;/p&gt;
&lt;p&gt;In both installations, I always trimmed the NVME drives before starting the tests, and in the case of ZFS, I set (both on Proxmox and FreeBSD) compression to zstd and atime to off. 
No other changes were made compared to the standard installation. &lt;/p&gt;
&lt;p&gt;On FreeBSD, the VM was created and managed with &lt;a href="https://github.com/churchers/vm-bhyve"&gt;vm-bhyve (devel)&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;On Proxmox, I tested the physical host on ZFS and ext4 and the VM on ZFS and LVM as LVM is the standard and most common setup in Proxmox. &lt;/p&gt;
&lt;p&gt;On FreeBSD, I tested the host on ZFS and the VM with both virtio and nvme drivers, on zvol, and as an image file within a ZFS dataset. &lt;/p&gt;
&lt;p&gt;I used &lt;a href="https://github.com/akopytov/sysbench"&gt;sysbench&lt;/a&gt; installed from the official Debian repository (on Proxmox and VM) and from the FreeBSD package on the respective host. &lt;/p&gt;
&lt;p&gt;The VMs, both on Proxmox and FreeBSD, have nearly identical characteristics and default configuration (apart from the nvme drivers set on bhyve, and for that reason, I also tested virtio).&lt;/p&gt;
&lt;p&gt;For those who want to reproduce my tests, here are the detailed configurations of the VMs used in bhyve:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FreeBSD bhyve VM Configuration with NVMe Driver&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;loader=&amp;quot;uefi&amp;quot;
cpu=4
memory=4096M
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;nvme&amp;quot;
disk0_name=&amp;quot;disk0.img&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;FreeBSD bhyve VM Configuration with virtio Driver&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;loader=&amp;quot;uefi&amp;quot;
cpu=4
memory=4096M
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;virtio-blk&amp;quot;
disk0_name=&amp;quot;disk0.img&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Proxmox VM Configuration&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Component&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Details&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.00 GiB [balloon=0]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Processors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 (1 sockets, 4 cores) [x86-64-v2-AES]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BIOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default (SeaBIOS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Display&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Machine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default (i440fx)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SCSI Controller&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VirtIO SCSI single&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CD/DVD Drive (ide2)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;local:iso/debian-12.5.0-amd64-netinst.iso,media=cdrom,size=629M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hard Disk (scsi0)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;zfspool:vm-100-disk-0,cache=writeback,discard=on,iothread=1,size=50G,ssd=1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network Device (net0)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;virtio=BC:24:11:22:3D:F0,bridge=vmbr0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In all the configurations, I used Debian 12 as the VM operating system, with the file system on ext4.&lt;/p&gt;
&lt;p&gt;I chose Debian 12 as it is a stable, widespread, and modern Linux distribution. I did not test a FreeBSD VM because, in my setups, &lt;a href="https://it-notes.dragas.net/2023/11/27/migrating-from-vm-to-hierarchical-jails-freebsd/"&gt;I tend not to virtualize FreeBSD on FreeBSD but to use nested jails&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All tests were performed multiple times, and I took the median results. CPU and RAM were tested only on the first VM (on Proxmox (ZFS) and FreeBSD (ZFS and nvme)) as they are not dependent on the underlying storage. Storage performance, on the other hand, was tested on all configurations.&lt;/p&gt;
&lt;h3&gt;CPU and RAM Tests on VMs&lt;/h3&gt;
&lt;p&gt;On both VMs:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-shell"&gt;sysbench --test=cpu --cpu-max-prime=20000 run
sysbench --test=memory run
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Comparative Results&lt;/h4&gt;
&lt;h5&gt;CPU Test&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Events per Second&lt;/th&gt;
&lt;th&gt;Total Time (s)&lt;/th&gt;
&lt;th&gt;Latency (avg) (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proxmox&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;498.08&lt;/td&gt;
&lt;td&gt;10.0010&lt;/td&gt;
&lt;td&gt;2.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;473.65&lt;/td&gt;
&lt;td&gt;10.0019&lt;/td&gt;
&lt;td&gt;2.11&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;CPU Percentage Analysis&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Difference in Events per Second&lt;/strong&gt;: ((498.08 - 473.65) / 498.08 approx -4.91\%)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difference in Total Time&lt;/strong&gt;: ((10.0019 - 10.0010) / 10.0010 approx +0.009\%)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difference in Latency (avg)&lt;/strong&gt;: ((2.11 - 2.01) / 2.01 approx +4.98\%)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;RAM Test&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Total Operations&lt;/th&gt;
&lt;th&gt;Operations per Second&lt;/th&gt;
&lt;th&gt;Total MiB Transferred&lt;/th&gt;
&lt;th&gt;MiB/sec&lt;/th&gt;
&lt;th&gt;Latency (avg) (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proxmox&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;64777227&lt;/td&gt;
&lt;td&gt;6476757.59&lt;/td&gt;
&lt;td&gt;63259.01&lt;/td&gt;
&lt;td&gt;6324.96&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;68621063&lt;/td&gt;
&lt;td&gt;6861139.06&lt;/td&gt;
&lt;td&gt;67012.76&lt;/td&gt;
&lt;td&gt;6700.33&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;RAM Percentage Analysis&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Difference in Total Operations&lt;/strong&gt;: ((68621063 - 64777227) / 64777227 approx +5.94\%)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difference in Operations per Second&lt;/strong&gt;: ((6861139.06 - 6476757.59) / 6476757.59 approx +5.94\%)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difference in Total MiB Transferred&lt;/strong&gt;: ((67012.76 - 63259.01) / 63259.01 approx +5.93\%)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difference in MiB/sec&lt;/strong&gt;: ((6700.33 - 6324.96) / 6324.96 approx +5.93\%)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CPU and RAM Comparative Results Table&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Proxmox (KVM)&lt;/th&gt;
&lt;th&gt;FreeBSD (bhyve)&lt;/th&gt;
&lt;th&gt;Difference (%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;Events/s&lt;/td&gt;
&lt;td&gt;498.08&lt;/td&gt;
&lt;td&gt;473.65&lt;/td&gt;
&lt;td&gt;-4.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Time (s)&lt;/td&gt;
&lt;td&gt;10.0010&lt;/td&gt;
&lt;td&gt;10.0019&lt;/td&gt;
&lt;td&gt;+0.009&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;2.01&lt;/td&gt;
&lt;td&gt;2.11&lt;/td&gt;
&lt;td&gt;+4.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;Ops&lt;/td&gt;
&lt;td&gt;64777227&lt;/td&gt;
&lt;td&gt;68621063&lt;/td&gt;
&lt;td&gt;+5.94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Ops/s&lt;/td&gt;
&lt;td&gt;6476757.59&lt;/td&gt;
&lt;td&gt;6861139.06&lt;/td&gt;
&lt;td&gt;+5.94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;MiB&lt;/td&gt;
&lt;td&gt;63259.01&lt;/td&gt;
&lt;td&gt;67012.76&lt;/td&gt;
&lt;td&gt;+5.93&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;MiB/s&lt;/td&gt;
&lt;td&gt;6324.96&lt;/td&gt;
&lt;td&gt;6700.33&lt;/td&gt;
&lt;td&gt;+5.93&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Interpretation of CPU and RAM Results&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CPU Performance&lt;/strong&gt;:&lt;/li&gt;
&lt;li&gt;The VM on FreeBSD has slightly lower CPU performance compared to Proxmox (-4.91% in events per second).&lt;/li&gt;
&lt;li&gt;The total execution time is nearly identical, with a negligible difference.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The average latency is slightly higher on FreeBSD (+4.98%).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;RAM Performance&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;The VM on FreeBSD has better RAM performance compared to Proxmox (+5.94% in operations and MiB/sec).&lt;/li&gt;
&lt;li&gt;The average latency is identical in both configurations.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In summary, while Proxmox provides more consistent CPU performance, FreeBSD demonstrates superior memory performance. The choice between Proxmox and FreeBSD may depend on the specific workload requirements and the importance of consistent performance versus higher throughput.&lt;/p&gt;
&lt;h3&gt;I/O Performance Tests&lt;/h3&gt;
&lt;p&gt;The test has been conducted using sysbench, with this command line:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;sysbench --test=fileio --file-total-size=30G prepare
sysbench --test=fileio --file-total-size=30G --file-test-mode=rndrw  --max-time=300 --max-requests=0 run
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;I/O Comparative Performance Data with Percentage Differences&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;VM on Proxmox (ZFS)&lt;/th&gt;
&lt;th&gt;VM on Proxmox (LVM)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (ZFS, NVMe)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (ZFS, Virtio)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (zvol)&lt;/th&gt;
&lt;th&gt;Host FreeBSD (ZFS)&lt;/th&gt;
&lt;th&gt;Host Proxmox (ZFS)&lt;/th&gt;
&lt;th&gt;Host Proxmox (ext4)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File creation speed (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;407.82&lt;/td&gt;
&lt;td&gt;461.52&lt;/td&gt;
&lt;td&gt;1467.83&lt;/td&gt;
&lt;td&gt;1398.81&lt;/td&gt;
&lt;td&gt;1333.64&lt;/td&gt;
&lt;td&gt;1625.67&lt;/td&gt;
&lt;td&gt;968.64&lt;/td&gt;
&lt;td&gt;633.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reads per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;650.09&lt;/td&gt;
&lt;td&gt;504.80&lt;/td&gt;
&lt;td&gt;11183.44&lt;/td&gt;
&lt;td&gt;806.93&lt;/td&gt;
&lt;td&gt;11834.53&lt;/td&gt;
&lt;td&gt;1234.62&lt;/td&gt;
&lt;td&gt;920.95&lt;/td&gt;
&lt;td&gt;498.37&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Writes per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;433.40&lt;/td&gt;
&lt;td&gt;336.54&lt;/td&gt;
&lt;td&gt;7455.62&lt;/td&gt;
&lt;td&gt;537.95&lt;/td&gt;
&lt;td&gt;7889.69&lt;/td&gt;
&lt;td&gt;823.08&lt;/td&gt;
&lt;td&gt;613.96&lt;/td&gt;
&lt;td&gt;332.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;fsyncs per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1387.08&lt;/td&gt;
&lt;td&gt;1076.97&lt;/td&gt;
&lt;td&gt;23858.08&lt;/td&gt;
&lt;td&gt;1721.79&lt;/td&gt;
&lt;td&gt;25247.36&lt;/td&gt;
&lt;td&gt;2634.01&lt;/td&gt;
&lt;td&gt;1964.96&lt;/td&gt;
&lt;td&gt;1063.19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read throughput (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10.16&lt;/td&gt;
&lt;td&gt;7.89&lt;/td&gt;
&lt;td&gt;174.74&lt;/td&gt;
&lt;td&gt;12.61&lt;/td&gt;
&lt;td&gt;184.91&lt;/td&gt;
&lt;td&gt;19.29&lt;/td&gt;
&lt;td&gt;14.39&lt;/td&gt;
&lt;td&gt;7.79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write throughput (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6.77&lt;/td&gt;
&lt;td&gt;5.26&lt;/td&gt;
&lt;td&gt;116.49&lt;/td&gt;
&lt;td&gt;8.41&lt;/td&gt;
&lt;td&gt;123.28&lt;/td&gt;
&lt;td&gt;12.86&lt;/td&gt;
&lt;td&gt;9.59&lt;/td&gt;
&lt;td&gt;5.19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;741163&lt;/td&gt;
&lt;td&gt;575588&lt;/td&gt;
&lt;td&gt;12749157&lt;/td&gt;
&lt;td&gt;919952&lt;/td&gt;
&lt;td&gt;13491459&lt;/td&gt;
&lt;td&gt;1407592&lt;/td&gt;
&lt;td&gt;1049894&lt;/td&gt;
&lt;td&gt;568277&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Average latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.40&lt;/td&gt;
&lt;td&gt;0.52&lt;/td&gt;
&lt;td&gt;0.02&lt;/td&gt;
&lt;td&gt;0.33&lt;/td&gt;
&lt;td&gt;0.02&lt;/td&gt;
&lt;td&gt;0.21&lt;/td&gt;
&lt;td&gt;0.29&lt;/td&gt;
&lt;td&gt;0.53&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;95th percentile latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.30&lt;/td&gt;
&lt;td&gt;3.25&lt;/td&gt;
&lt;td&gt;0.06&lt;/td&gt;
&lt;td&gt;1.58&lt;/td&gt;
&lt;td&gt;0.05&lt;/td&gt;
&lt;td&gt;1.32&lt;/td&gt;
&lt;td&gt;1.79&lt;/td&gt;
&lt;td&gt;2.71&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22.65&lt;/td&gt;
&lt;td&gt;32.30&lt;/td&gt;
&lt;td&gt;35.49&lt;/td&gt;
&lt;td&gt;13.60&lt;/td&gt;
&lt;td&gt;77.53&lt;/td&gt;
&lt;td&gt;9.03&lt;/td&gt;
&lt;td&gt;9.47&lt;/td&gt;
&lt;td&gt;17.39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total test time (s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;300.0475&lt;/td&gt;
&lt;td&gt;300.1147&lt;/td&gt;
&lt;td&gt;300.0020&lt;/td&gt;
&lt;td&gt;300.0226&lt;/td&gt;
&lt;td&gt;300.0012&lt;/td&gt;
&lt;td&gt;300.0416&lt;/td&gt;
&lt;td&gt;300.0159&lt;/td&gt;
&lt;td&gt;300.1381&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Percentage Differences Compared to VM on Proxmox (ZFS)&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;VM on Proxmox (LVM)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (ZFS, NVMe)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (ZFS, Virtio)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (zvol)&lt;/th&gt;
&lt;th&gt;Host FreeBSD (ZFS)&lt;/th&gt;
&lt;th&gt;Host Proxmox (ZFS)&lt;/th&gt;
&lt;th&gt;Host Proxmox (ext4)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File creation speed (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+13.18%&lt;/td&gt;
&lt;td&gt;+259.77%&lt;/td&gt;
&lt;td&gt;+242.99%&lt;/td&gt;
&lt;td&gt;+227.02%&lt;/td&gt;
&lt;td&gt;+298.62%&lt;/td&gt;
&lt;td&gt;+137.52%&lt;/td&gt;
&lt;td&gt;+55.25%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reads per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-22.34%&lt;/td&gt;
&lt;td&gt;+1619.98%&lt;/td&gt;
&lt;td&gt;+24.13%&lt;/td&gt;
&lt;td&gt;+1720.45%&lt;/td&gt;
&lt;td&gt;+89.92%&lt;/td&gt;
&lt;td&gt;+41.67%&lt;/td&gt;
&lt;td&gt;-23.34%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Writes per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-22.35%&lt;/td&gt;
&lt;td&gt;+1620.26%&lt;/td&gt;
&lt;td&gt;+24.12%&lt;/td&gt;
&lt;td&gt;+1720.42%&lt;/td&gt;
&lt;td&gt;+89.91%&lt;/td&gt;
&lt;td&gt;+41.66%&lt;/td&gt;
&lt;td&gt;-23.34%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;fsyncs per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-22.36%&lt;/td&gt;
&lt;td&gt;+1620.02%&lt;/td&gt;
&lt;td&gt;+24.13%&lt;/td&gt;
&lt;td&gt;+1720.18%&lt;/td&gt;
&lt;td&gt;+89.90%&lt;/td&gt;
&lt;td&gt;+41.66%&lt;/td&gt;
&lt;td&gt;-23.35%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read throughput (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-22.34%&lt;/td&gt;
&lt;td&gt;+1619.88%&lt;/td&gt;
&lt;td&gt;+24.11%&lt;/td&gt;
&lt;td&gt;+1719.98%&lt;/td&gt;
&lt;td&gt;+89.86%&lt;/td&gt;
&lt;td&gt;+41.63%&lt;/td&gt;
&lt;td&gt;-23.33%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write throughput (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-22.30%&lt;/td&gt;
&lt;td&gt;+1620.68%&lt;/td&gt;
&lt;td&gt;+24.22%&lt;/td&gt;
&lt;td&gt;+1720.97%&lt;/td&gt;
&lt;td&gt;+89.96%&lt;/td&gt;
&lt;td&gt;+41.65%&lt;/td&gt;
&lt;td&gt;-23.33%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-22.34%&lt;/td&gt;
&lt;td&gt;+1620.16%&lt;/td&gt;
&lt;td&gt;+24.12%&lt;/td&gt;
&lt;td&gt;+1720.31%&lt;/td&gt;
&lt;td&gt;+89.92%&lt;/td&gt;
&lt;td&gt;+41.65%&lt;/td&gt;
&lt;td&gt;-23.31%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Average latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+30.00%&lt;/td&gt;
&lt;td&gt;-95.00%&lt;/td&gt;
&lt;td&gt;-17.50%&lt;/td&gt;
&lt;td&gt;-95.00%&lt;/td&gt;
&lt;td&gt;-47.50%&lt;/td&gt;
&lt;td&gt;-27.50%&lt;/td&gt;
&lt;td&gt;+32.50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;95th percentile latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+41.30%&lt;/td&gt;
&lt;td&gt;-97.39%&lt;/td&gt;
&lt;td&gt;-31.30%&lt;/td&gt;
&lt;td&gt;-97.83%&lt;/td&gt;
&lt;td&gt;-42.61%&lt;/td&gt;
&lt;td&gt;-22.17%&lt;/td&gt;
&lt;td&gt;+17.83%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+42.60%&lt;/td&gt;
&lt;td&gt;+56.69%&lt;/td&gt;
&lt;td&gt;-39.96%&lt;/td&gt;
&lt;td&gt;+242.30%&lt;/td&gt;
&lt;td&gt;-60.13%&lt;/td&gt;
&lt;td&gt;-58.19%&lt;/td&gt;
&lt;td&gt;-23.22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total test time (s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+0.02%&lt;/td&gt;
&lt;td&gt;-0.02%&lt;/td&gt;
&lt;td&gt;-0.01%&lt;/td&gt;
&lt;td&gt;-0.02%&lt;/td&gt;
&lt;td&gt;-0.02%&lt;/td&gt;
&lt;td&gt;-0.01%&lt;/td&gt;
&lt;td&gt;+0.01%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Percentage Differences Compared to VM on Proxmox (LVM) as this is the standard Proxmox setup&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;VM on Proxmox (ZFS)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (ZFS, NVMe)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (ZFS, Virtio)&lt;/th&gt;
&lt;th&gt;VM on FreeBSD (zvol)&lt;/th&gt;
&lt;th&gt;Host FreeBSD (ZFS)&lt;/th&gt;
&lt;th&gt;Host Proxmox (ZFS)&lt;/th&gt;
&lt;th&gt;Host Proxmox (ext4)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File creation speed (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-11.64%&lt;/td&gt;
&lt;td&gt;+218.04%&lt;/td&gt;
&lt;td&gt;+203.09%&lt;/td&gt;
&lt;td&gt;+188.97%&lt;/td&gt;
&lt;td&gt;+252.24%&lt;/td&gt;
&lt;td&gt;+109.88%&lt;/td&gt;
&lt;td&gt;+37.18%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reads per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+28.78%&lt;/td&gt;
&lt;td&gt;+2115.42%&lt;/td&gt;
&lt;td&gt;+59.85%&lt;/td&gt;
&lt;td&gt;+2244.40%&lt;/td&gt;
&lt;td&gt;+144.58%&lt;/td&gt;
&lt;td&gt;+82.44%&lt;/td&gt;
&lt;td&gt;-1.27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Writes per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+28.78%&lt;/td&gt;
&lt;td&gt;+2115.37%&lt;/td&gt;
&lt;td&gt;+59.85%&lt;/td&gt;
&lt;td&gt;+2244.35%&lt;/td&gt;
&lt;td&gt;+144.57%&lt;/td&gt;
&lt;td&gt;+82.43%&lt;/td&gt;
&lt;td&gt;-1.27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;fsyncs per second&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+28.79%&lt;/td&gt;
&lt;td&gt;+2115.30%&lt;/td&gt;
&lt;td&gt;+59.87%&lt;/td&gt;
&lt;td&gt;+2244.30%&lt;/td&gt;
&lt;td&gt;+144.58%&lt;/td&gt;
&lt;td&gt;+82.45%&lt;/td&gt;
&lt;td&gt;-1.28%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read throughput (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+28.77%&lt;/td&gt;
&lt;td&gt;+2114.70%&lt;/td&gt;
&lt;td&gt;+59.82%&lt;/td&gt;
&lt;td&gt;+2243.60%&lt;/td&gt;
&lt;td&gt;+144.49%&lt;/td&gt;
&lt;td&gt;+82.38%&lt;/td&gt;
&lt;td&gt;-1.27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write throughput (MiB/s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+28.71%&lt;/td&gt;
&lt;td&gt;+2114.64%&lt;/td&gt;
&lt;td&gt;+59.89%&lt;/td&gt;
&lt;td&gt;+2243.73%&lt;/td&gt;
&lt;td&gt;+144.49%&lt;/td&gt;
&lt;td&gt;+82.32%&lt;/td&gt;
&lt;td&gt;-1.33%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+28.77%&lt;/td&gt;
&lt;td&gt;+2114.98%&lt;/td&gt;
&lt;td&gt;+59.83%&lt;/td&gt;
&lt;td&gt;+2243.94%&lt;/td&gt;
&lt;td&gt;+144.55%&lt;/td&gt;
&lt;td&gt;+82.40%&lt;/td&gt;
&lt;td&gt;-1.27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Average latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-23.08%&lt;/td&gt;
&lt;td&gt;-96.15%&lt;/td&gt;
&lt;td&gt;-36.54%&lt;/td&gt;
&lt;td&gt;-96.15%&lt;/td&gt;
&lt;td&gt;-59.62%&lt;/td&gt;
&lt;td&gt;-44.23%&lt;/td&gt;
&lt;td&gt;+1.92%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;95th percentile latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-29.23%&lt;/td&gt;
&lt;td&gt;-98.15%&lt;/td&gt;
&lt;td&gt;-51.38%&lt;/td&gt;
&lt;td&gt;-98.46%&lt;/td&gt;
&lt;td&gt;-59.38%&lt;/td&gt;
&lt;td&gt;-44.92%&lt;/td&gt;
&lt;td&gt;-16.62%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max latency (ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-29.88%&lt;/td&gt;
&lt;td&gt;+9.88%&lt;/td&gt;
&lt;td&gt;-57.89%&lt;/td&gt;
&lt;td&gt;+140.03%&lt;/td&gt;
&lt;td&gt;-72.04%&lt;/td&gt;
&lt;td&gt;-70.68%&lt;/td&gt;
&lt;td&gt;-46.16%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total test time (s)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-0.02%&lt;/td&gt;
&lt;td&gt;-0.04%&lt;/td&gt;
&lt;td&gt;-0.03%&lt;/td&gt;
&lt;td&gt;-0.04%&lt;/td&gt;
&lt;td&gt;-0.02%&lt;/td&gt;
&lt;td&gt;-0.03%&lt;/td&gt;
&lt;td&gt;+0.01%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Analysis of Performance Data&lt;/h4&gt;
&lt;p&gt;The performance data collected from various configurations of Proxmox and FreeBSD provides a comprehensive view of the I/O capabilities and highlights some significant differences. Here is an analysis of the key findings:&lt;/p&gt;
&lt;h5&gt;Comparative Analysis&lt;/h5&gt;
&lt;h6&gt;Hypothesis on NVMe Performance and fsync&lt;/h6&gt;
&lt;p&gt;An important observation from my tests is that VMs with the bhyve NVMe driver show significantly higher performance compared to the same VMs with the virtio driver or compared to the physical host system. This difference initially led me to hypothesize that the bhyve NVMe driver might not correctly respect fsync operations, returning a positive result before the underlying file system has confirmed the final write. However, this was just a theory based on benchmark results and is not supported by concrete data. Furthermore, some developers have reviewed the code and found no evidence to suggest this behavior, and I personally have never encountered any potential issues that would indicate such a problem.&lt;/p&gt;
&lt;p&gt;Specifically, I observed that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The VM with the virtio driver has performance comparable to Proxmox.&lt;/li&gt;
&lt;li&gt;The VM with the NVMe driver, whether on a ZFS dataset or zvol, shows performance superior to the physical FreeBSD host.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Host Physical Systems and Filesystems&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Creation Speed&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host FreeBSD (ZFS)&lt;/strong&gt; shows the highest file creation speed at 1625.67 MiB/s, which is +68.03% compared to Host Proxmox (ZFS) and +156.72% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ext4)&lt;/strong&gt; has a file creation speed of 633.13 MiB/s, which is -34.62% compared to Host Proxmox (ZFS).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read and Write Operations per Second&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Host FreeBSD (ZFS)&lt;/strong&gt; demonstrates the highest read and write operations per second with 1234.62 reads/s and 823.08 writes/s.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reads per second: +34.06% compared to Host Proxmox (ZFS) and +147.80% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;li&gt;Writes per second: +34.04% compared to Host Proxmox (ZFS) and +147.61% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ext4)&lt;/strong&gt; shows a lower performance with 498.37 reads/s and 332.25 writes/s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ZFS)&lt;/strong&gt; has 920.95 reads/s and 613.96 writes/s.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fsync Operations per Second&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Host FreeBSD (ZFS)&lt;/strong&gt; achieves the highest fsync operations per second at 2634.01 fsyncs/s, which is +34.02% compared to Host Proxmox (ZFS) and +147.73% compared to Host Proxmox (ext4).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ext4)&lt;/strong&gt; has a lower performance with 1063.19 fsyncs/s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ZFS)&lt;/strong&gt; achieves 1964.96 fsyncs/s.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Throughput&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Host FreeBSD (ZFS)&lt;/strong&gt; again leads in throughput with 19.29 MiB/s read and 12.86 MiB/s write.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read throughput: +34.03% compared to Host Proxmox (ZFS) and +147.53% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;li&gt;Write throughput: +34.08% compared to Host Proxmox (ZFS) and +147.79% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ext4)&lt;/strong&gt; has the lowest throughput with 7.79 MiB/s read and 5.19 MiB/s write.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ZFS)&lt;/strong&gt; has 14.39 MiB/s read and 9.59 MiB/s write.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latency&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Host FreeBSD (ZFS)&lt;/strong&gt; shows the lowest average latency at 0.21 ms and 95th percentile latency at 1.32 ms.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Average latency: -27.59% compared to Host Proxmox (ZFS) and -60.38% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;li&gt;95th percentile latency: -26.27% compared to Host Proxmox (ZFS) and -51.29% compared to Host Proxmox (ext4).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ext4)&lt;/strong&gt; has the highest average latency at 0.53 ms and 95th percentile latency at 2.71 ms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Proxmox (ZFS)&lt;/strong&gt; has an average latency of 0.29 ms and 95th percentile latency of 1.79 ms.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;VMs vs Physical Hosts&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Creation Speed&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; demonstrates an outstanding file creation speed at 1467.83 MiB/s (+218.04% compared to VM on Proxmox (LVM) and +259.77% compared to VM on Proxmox (ZFS)).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; achieves 1333.64 MiB/s, which is also significantly higher than VM on Proxmox (LVM) and VM on Proxmox (ZFS).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read and Write Operations per Second&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; shows exceptional performance with 11183.44 reads/s and 7455.62 writes/s.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; also performs excellently with 11834.53 reads/s and 7889.69 writes/s.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fsync Operations per Second&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; achieves 23858.08 fsyncs/s, and &lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; achieves 25247.36 fsyncs/s, both significantly higher than any other configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Throughput&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; achieves the highest throughput with 174.74 MiB/s read and 116.49 MiB/s write.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; also has high throughput at 184.91 MiB/s read and 123.28 MiB/s write.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latency&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; shows very low average latency at 0.02 ms and 95th percentile latency at 0.06 ms.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; has similarly low latencies, indicating fast response times for I/O operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;VM Configurations Comparison&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Creation Speed&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Among VMs, &lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; leads, followed by &lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt;, and then &lt;strong&gt;VM on FreeBSD (ZFS, Virtio)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read and Write Operations per Second&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; and &lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; both outperform &lt;strong&gt;VM on Proxmox (ZFS)&lt;/strong&gt; and &lt;strong&gt;VM on Proxmox (LVM)&lt;/strong&gt; configurations significantly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM on Proxmox (ZFS)&lt;/strong&gt; outperforms &lt;strong&gt;VM on Proxmox (LVM)&lt;/strong&gt; in read and write operations.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fsync Operations per Second&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; and &lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; have significantly higher fsync operations compared to &lt;strong&gt;VM on Proxmox (ZFS)&lt;/strong&gt; and &lt;strong&gt;VM on Proxmox (LVM)&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Throughput&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; and &lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; have the highest throughput, followed by &lt;strong&gt;VM on Proxmox (ZFS)&lt;/strong&gt; and then &lt;strong&gt;VM on Proxmox (LVM)&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latency&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VM on FreeBSD (ZFS, NVMe)&lt;/strong&gt; and &lt;strong&gt;VM on FreeBSD (zvol)&lt;/strong&gt; show the lowest latencies among the VMs, indicating faster response times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM on Proxmox (ZFS)&lt;/strong&gt; shows lower latencies compared to &lt;strong&gt;VM on Proxmox (LVM)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Cache Settings and Performance Influence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cache settings can significantly influence the performance of virtualization systems. In my setup, I did not modify the cache settings for the NVMe and virtio drivers, keeping the default settings. It is possible that the observed performance differences are also due to how different operating systems manage the caches of NVMe devices. I encourage other system administrators to explore the cache settings of their systems to see if changes in this area can influence benchmark results.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Regarding RAM and CPU, the performance of the VMs is comparable. There are slight differences in favor of Proxmox for CPU and FreeBSD for RAM, but in my opinion, these differences are so negligible that they wouldn't sway the decision towards one solution or the other.&lt;/p&gt;
&lt;p&gt;The I/O performance data clearly indicates that VM on FreeBSD with NVMe and ZFS outperforms all other configurations by a significant margin. This is evident in the file creation speed, read/write operations per second, fsync operations per second, throughput, and latency metrics. &lt;/p&gt;
&lt;p&gt;When comparing physical hosts, Host FreeBSD (ZFS) demonstrates excellent performance, particularly in comparison to Host Proxmox (ZFS) and Host Proxmox (ext4). &lt;/p&gt;
&lt;p&gt;When comparing VMs, VM on FreeBSD (ZFS, NVMe) and VM on FreeBSD (zvol) configurations stand out as the top performers. &lt;/p&gt;
&lt;p&gt;The VM using virtio on FreeBSD also shows strong performance, albeit not as high as the NVMe configuration. It significantly outperforms Proxmox configurations in terms of file creation speed, read/write operations per second, and throughput, while maintaining competitive latencies.&lt;/p&gt;
&lt;p&gt;The virtio driver provides a stable and reliable option, making it a suitable choice for environments where the NVMe driver cannot be used. This makes FreeBSD with virtio a balanced option for virtualization, offering both high performance and reliability.&lt;/p&gt;
&lt;p&gt;By examining these performance metrics, users can make informed decisions about their virtualization and storage configurations to optimize their systems for specific workloads and performance requirements.&lt;/p&gt;
&lt;p&gt;In light of these tests and experiments, I can therefore affirm that my sensations (and those of many users) of greater "snappiness" of the VMs on FreeBSD can be confirmed. Certainly, Proxmox is a stable solution, rich in features, battle-tested, and has many other valid points, but FreeBSD, especially with the nvme driver, demonstrates very high performance and a very low overhead in installation and operation.&lt;/p&gt;
&lt;p&gt;I will continue to use both solutions with great satisfaction, but I will be even more encouraged to implement virtualization servers based on FreeBSD and bhyve.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Mon, 10 Jun 2024 05:53:45 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/</guid><category>freebsd</category><category>linux</category><category>proxmox</category><category>kvm</category><category>bhyve</category><category>hosting</category><category>filesystems</category><category>virtualization</category><category>zfs</category><category>debian</category><category>server</category></item><item><title>Migrating from an Old Linux Server to a New FreeBSD Machine</title><link>https://it-notes.dragas.net/2023/10/25/migrating-from-an-old-linux-server-to-a-new-freebsd-machine/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/content/images/2023/10/3500d14b-cb7e-4de6-af9e-0ca135985b41.webp" alt="Migrating from an Old Linux Server to a New FreeBSD Machine"&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Preamble:&lt;/em&gt; I believe it's time to bid farewell to this venerable Linux server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;  &lt;em&gt;The article chronicles the journey of transitioning from an outdated Linux server, running for 1690 days without updates, to a modern FreeBSD machine. This migration involved using tools like mfsBSD, BastilleBSD, Borg Backup, and bhyve. Despite initial hesitations due to the Linux server's impeccable performance, the transition was smooth, resulting in improved manageability and efficiency. The piece emphasizes the importance of regular system updates and anticipates revisiting the topic in the future with new uptime achievements and updates.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This server loyally served for years as a secondary backup server while also providing a few minor services to users. As it often happens, it remained in operation, neglected and without updates for years. Stable operating systems have the "flaw" of being forgotten, giving the false impression that they don't need maintenance or updates. This machine continued its service without oversight for years. When approached for a service request (not due to malfunctions), I advised the client to upgrade the whole system. A mere update would not suffice, so I suggested starting afresh on new hardware with FreeBSD as the primary OS.&lt;/p&gt;
&lt;p&gt;The client was understandably hesitant given the uptime stats:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;08:58:43 up 1690 days, 21:32, 4 users, load average: 9.57, 10.15, 8.76&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Not a single error, not a single hiccup. From his perspective, a similar setup to what was installed many years ago and still working flawlessly was preferred. Nevertheless, he trusted my expertise and let me proceed.&lt;/p&gt;
&lt;p&gt;This server had a plethora of duties, among which:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One of the pivotal tasks was running &lt;a href="https://www.proxmox.com/en/proxmox-backup-server/overview"&gt;Proxmox Backup Server&lt;/a&gt; via Docker. Proxmox Backup Server requires Debian, but this server was running on Ubuntu 16.04 (previously upgraded from Ubuntu 14.04 – yes, ancient!). Hence, Proxmox Backup Server was still at version 1.x.&lt;/li&gt;
&lt;li&gt;Another critical function was storing backups made through &lt;a href="https://www.borgbackup.org/"&gt;BorgBackup&lt;/a&gt; on its file system. The /home directory used a mirrored btrfs file system, and each backed-up server had its user on this system. Clients could backup (using a push method) only via VPN and only during specific windows when the server permitted (by adding specific firewall rules via Jenkins. Jenkins also managed connection protocols, snapshots, backups, etc.).&lt;/li&gt;
&lt;li&gt;Among the lesser tasks, the server ran a few Docker containers with HandBrake on various presets. The client processed video conversions by uploading the original files via sftp, and after some hours, fetched the converted files from the destination directory. This will not be replicated on the new FreeBSD server since they now handle this operation locally on their high-performance MacBook Pro with Apple Silicon. However, a future restoration isn't off the table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first thing I did was install FreeBSD on the new hardware. Given that it's a physical server on Hetzner (an auction pick due to disk space needs over power), and FreeBSD wasn't an option, I used &lt;a href="https://mfsbsd.vx.sk/"&gt;mfsBSD&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After booting the physical server in Linux rescue, I copied mfsBSD onto the disks using &lt;code&gt;dd&lt;/code&gt; and restarted. On boot, I SSHed into mfsBSD and executed the installation using &lt;code&gt;bsdinstall&lt;/code&gt;—a robust and efficient method.&lt;/p&gt;
&lt;p&gt;I set up a raidz1 with all four 6 TB disks, resulting in a final storage space of 21.8T, ample for now without the video files.&lt;/p&gt;
&lt;p&gt;To ensure continuity, I kept a setup similar to the old one. The clients would essentially continue with their usual backup procedure without necessitating drastic changes to backup scripts. To avoid storing these backups directly in the physical machine's /home and to leave the door open for future services, I installed &lt;a href="https://bastillebsd.org/"&gt;BastilleBSD&lt;/a&gt; and began setting up several jails. I replaced the old Linux machine's behavior with a VNET FreeBSD jail. In past scenarios, I've created Linux jails (thanks to BastilleBSD) and transferred the old server into the jail using rsync, making minor configuration tweaks. While this usually works, it doesn't address the underlying issue of an obsolete setup. Given the opportunity, I opted for a modern toolset.&lt;/p&gt;
&lt;p&gt;Thus, I copied every home directory (along with their historic backups) in its entirety, installed BorgBackup, and re-established the VPN. With a VNET jail, I can craft networking devices and fine-tune configurations. After recreating user accounts, inputting the various SSH &lt;code&gt;authorized_keys&lt;/code&gt;, and checking all clients, I set up a snapshot plan on the host. This ensures that if a client is compromised with the potential (however remote) for breach and backup deletion, a ZFS snapshot of the entire jail remains available.&lt;/p&gt;
&lt;p&gt;As mentioned, one of the core tools on the old server was Proxmox Backup Server. It's not natively installable on FreeBSD, necessitating a VM. Enter the fantastic &lt;code&gt;bhyve&lt;/code&gt;, supported by &lt;code&gt;vm-bhyve&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, one issue arose: backups would consume vast amounts of space, and I wanted to avoid housing an enormous disk image (or a zvol) with both VMs and backups. So, I opted for a slightly less performant but more flexible solution: installing Debian 12 and Proxmox Backup Server on the VM while placing backups on a separate ZFS dataset on the physical machine, exported via NFS and mounted on the VM.&lt;/p&gt;
&lt;p&gt;Given that the physical server has an internal bridge "vm-public" with IP &lt;code&gt;192.168.124.1&lt;/code&gt; and the VM is at &lt;code&gt;192.168.124.2&lt;/code&gt;, I just created a dataset named &lt;code&gt;zroot/PBS&lt;/code&gt; and added the following line to &lt;code&gt;/etc/exports&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/zroot/PBS -alldirs -maproot=root -network 192.168.124.2/32&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To enable NFS, insert into &lt;code&gt;/etc/rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;rpcbind_enable=&amp;quot;YES&amp;quot; 
nfs_server_enable=&amp;quot;YES&amp;quot; 
mountd_flags=&amp;quot;-r&amp;quot; 
rpc_lockd_enable=&amp;quot;YES&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Within the VM, create &lt;code&gt;/PBS&lt;/code&gt; and include in &lt;code&gt;/etc/fstab&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;192.168.124.1:/zroot/PBS /PBS nfs rw,async,soft,intr,noexec 0 0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;After Proxmox Backup Server's installation, simply set up the datastores in &lt;code&gt;/PBS/&lt;/code&gt;, and they'll directly store on the physical machine's ZFS dataset.&lt;/p&gt;
&lt;p&gt;For firewall configurations, I exposed port 8007, redirecting it towards the VM, and everything started functioning smoothly. I then set a Proxmox Backup Server replica from the old to the new server. After completion, I changed the Proxmox Backup Server IP on all Proxmox hosts to point to the new server. Smooth sailing.&lt;/p&gt;
&lt;p&gt;The old Ubuntu server also managed other minor services, which have become obsolete and weren't replicated.&lt;/p&gt;
&lt;p&gt;The transition was seamless, the client is pleased, and I'm content since each service is now neatly segregated into its jail or VM. The machine's load is minimal, which might pave the way for other tasks, via VPN. Everything now rests on ZFS, and the icing on the cake: I made the client promise not to reach another 1690 days of uptime but to timely update as required.&lt;/p&gt;
&lt;p&gt;I'm not entirely convinced the promise will hold—meaning, in a few years, I might yet be discussing this "new" server, highlighting another impressive uptime and another upgrade journey.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Wed, 25 Oct 2023 16:39:37 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2023/10/25/migrating-from-an-old-linux-server-to-a-new-freebsd-machine/</guid><category>freebsd</category><category>bhyve</category><category>borg</category><category>btrfs</category><category>container</category><category>data</category><category>docker</category><category>filesystems</category><category>jail</category><category>server</category><category>snapshots</category><category>virtualization</category><category>vpn</category><category>proxmox</category><category>backup</category><category>linux</category></item><item><title>Creating a Mikrotik CHR - RouterOS 7 - bhyve VM in FreeBSD</title><link>https://it-notes.dragas.net/2023/03/21/creating-a-mikrotik-chr-routeros-7-bhyve-vm-in-freebsd-2/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/content/images/2023/03/mikrotik-1.jpeg" alt="Creating a Mikrotik CHR - RouterOS 7 - bhyve VM in FreeBSD"&gt;&lt;/p&gt;&lt;p&gt;While I love &lt;a href="https://it-notes.dragas.net/2022/01/24/why-were-migrating-many-of-our-servers-from-linux-to-freebsd/"&gt;FreeBSD&lt;/a&gt;-based router solutions (OPNsense, PFsense, etc.), I also appreciate and use &lt;a href="https://mikrotik.com"&gt;MikroTik&lt;/a&gt; devices and software. They produce and sell reasonably-priced, efficient hardware, and have implemented some interesting proprietary solutions (EoIP, etc.). Additionally, they're a European company. From the smallest Wi-Fi router to the largest enterprise routing platform, they employ the same software with (almost) the same features.&lt;/p&gt;
&lt;p&gt;That's why I'm also implementing virtualized MikroTik CHR solutions - they're lightweight, efficient, and can handle a significant amount of traffic with minimal resource overhead.&lt;/p&gt;
&lt;p&gt;Our FreeBSD hypervisors run &lt;a href="https://it-notes.dragas.net/2023/03/14/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-3/"&gt;vm-bhyve&lt;/a&gt; as a lightweight, efficient, and intelligent management tool for VMs.&lt;/p&gt;
&lt;p&gt;Even though MikroTik states that bhyve is not supported (as they believe it's merely a paravirtualization software), CHR based on RouterOS 6 works flawlessly, &lt;a href="https://github.com/churchers/vm-bhyve/wiki/Supported-Guest-Examples"&gt;following the hints provided by the vm-bhyve documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, things change when dealing with RouterOS 7. It doesn't boot at all, and if you upgrade from RoS 6 to RoS 7, it ceases to function entirely.&lt;/p&gt;
&lt;p&gt;It seems that the MikroTik CHR image based on RouterOS 7 has an unusual partition table, somewhere between MBR and GPT. For this reason, Proxmox (KVM) doesn't experience any issues, while bhyve seems unable to properly boot the VM. I conducted several tests, but the best solution was suggested by user &lt;a href="https://forum.mikrotik.com/viewtopic.php?t=184254"&gt;kriszos on the MikroTik forum&lt;/a&gt; (even if kriszos was dealing with Hyper-V).&lt;/p&gt;
&lt;p&gt;The script should be used on a machine with the following tools installed: gdisk, wget, unzip, qemu-img, qemu-nbd, and rsync:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;#!/bin/bash
wget --no-check-certificate https://download.mikrotik.com/routeros/7.8/chr-7.8.img.zip -O /tmp/chr.img.zip
unzip -p /tmp/chr.img.zip &amp;gt; /tmp/chr.img
rm -rf  chr.qcow2
qemu-img convert -f raw -O qcow2 /tmp/chr.img chr.qcow2
rm -rf /tmp/chr.im*
modprobe nbd
qemu-nbd -c /dev/nbd0 chr.qcow2
rm -rf /tmp/tmp*
mkdir /tmp/tmpmount/
mkdir /tmp/tmpefipart/
mount /dev/nbd0p1 /tmp/tmpmount/
rsync -a /tmp/tmpmount/ /tmp/tmpefipart/
umount /dev/nbd0p1
mkfs -t fat /dev/nbd0p1
mount /dev/nbd0p1 /tmp/tmpmount/
rsync -a /tmp/tmpefipart/ /tmp/tmpmount/
umount /dev/nbd0p1
rm -rf /tmp/tmp*
(
echo 2 # use GPT
echo t # change partition code
echo 1 # select first partition
echo 8300 # change code to Linux filesystem 8300
echo r # Recovery/transformation
echo h # Hybrid MBR
echo 1 2 # partitions added to the hybrid MBR
echo n # Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? (Y/N)
echo   # Enter an MBR hex code (default 83)
echo y # Set the bootable flag? (Y/N)
echo   # Enter an MBR hex code (default 83)
echo n # Set the bootable flag? (Y/N)
echo n # Unused partition space(s) found. Use one to protect more partitions? (Y/N)
echo w # write changes to disk
echo y # confirm
) | gdisk /dev/nbd0
qemu-nbd -d /dev/nbd0
echo &amp;quot;script finished, created file chr.qcow2&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I used the script on a machine with Proxmox installed, and it worked correctly. Once the relevant image was obtained, it was converted to raw format to be fed to bhyve:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;qemu-img convert -f qcow2 -O raw chr.qcow2 chr.img
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now that we have the correct image available, here's an example of a VM configuration managed by vm-bhyve:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;loader=&amp;quot;uefi&amp;quot;
graphics=&amp;quot;no&amp;quot;
cpu=&amp;quot;2&amp;quot;
memory=“128M&amp;quot;
network0_type=&amp;quot;virtio-net&amp;quot;
network0_switch=&amp;quot;public&amp;quot;
disk0_type=&amp;quot;virtio-blk&amp;quot;
disk0_name=“chr.img”
uuid=“cafecafe-cafe-cafe-cafe-cafecafecafe”
network0_mac=“ca:fe:ca:fe:ca:fe”
&lt;/code&gt;&lt;/pre&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 21 Mar 2023 12:27:34 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2023/03/21/creating-a-mikrotik-chr-routeros-7-bhyve-vm-in-freebsd-2/</guid><category>freebsd</category><category>proxmox</category><category>virtualization</category><category>hosting</category><category>linux</category><category>server</category><category>tutorial</category><category>kvm</category><category>mikrotik</category><category>bhyve</category></item><item><title>How we are migrating (many of) our servers from Linux to FreeBSD - Part 3 - Proxmox to FreeBSD</title><link>https://it-notes.dragas.net/2023/03/14/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-3/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/server_rack.webp" alt="How we are migrating (many of) our servers from Linux to FreeBSD - Part 3 - Proxmox to FreeBSD"&gt;&lt;/p&gt;&lt;p&gt;In recent years, &lt;a href="https://it-notes.dragas.net/2022/01/24/why-were-migrating-many-of-our-servers-from-linux-to-freebsd/"&gt;we've been migrating many of our servers from Linux to FreeBSD&lt;/a&gt; as part of our consolidation and optimization efforts. Specifically, we've been &lt;a href="https://it-notes.dragas.net/2022/02/05/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-1-system-and-jails-setup/"&gt;moving services that were previously deployed using Docker onto FreeBSD&lt;/a&gt;, and it has proven to be a great choice for handling workloads efficiently.&lt;/p&gt;
&lt;p&gt;To this end, we've also been migrating many of our virtual machines (VMs) to FreeBSD, deploying services within FreeBSD jails. In some cases, these jails have even replaced entire VMs and run bare metal. Although we prefer to move to native FreeBSD whenever possible, sometimes it's not the best option for all the services we offer. As a result, one of our most critical physical servers has been left behind for years.&lt;/p&gt;
&lt;div class="hc-toc"&gt;&lt;/div&gt;

&lt;p&gt;This server was a Proxmox server that we installed many years ago and updated to version 6.4. It hosted some critical services, but upgrading to Proxmox 7.x posed some challenges. In particular, &lt;a href="https://forum.proxmox.com/threads/unified-cgroup-v2-layout-upgrade-warning-pve-6-4-to-7-0/"&gt;some of the LXC containers required tweaks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, this server was quite old, with only four physical disks and 64 GB of RAM. It was located in an OVH data center and had been running well until one of the disks started to malfunction once a week, on Sundays. This would trigger a RAID reconstruction that kept the system busy for about two days.&lt;/p&gt;
&lt;p&gt;Despite my preference for simple setups, this server had been deployed gradually over many years, and everything was tied together. As a result, unraveling the system to resolve the issues was not a simple task. &lt;em&gt;Sometimes the combination of simple things can make everything complex&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The Proxmox Server&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://www.proxmox.com/en/"&gt;Proxmox&lt;/a&gt; server was configured as the central hub for various services, including primary DNS, web hosting, VOIP, and more. It featured several bridges, each with its own specific purpose, and was connected to a virtual machine running &lt;a href="https://mikrotik.com"&gt;MikroTik CHR&lt;/a&gt;. This machine was responsible for consolidating all incoming VPNs from the MikroTik devices we managed, both ours and those belonging to our clients. Additionally, it provided a series of bridges to manage these devices and all server management VPNs and other services. The Proxmox server also housed several virtual machines running Linux, FreeBSD, OpenBSD, and NetBSD, as well as LXC containers.&lt;/p&gt;
&lt;p&gt;Over the last two years, we've been migrating most of these virtual machines and containers to FreeBSD-based VMs, which feature their own specific jails. Consequently, most of the VMs we've had to move were BSD-based, while only five Linux VMs remained. The LXC containers hosted a range of services, including servers managed by &lt;a href="https://www.virtualmin.com"&gt;Virtualmin&lt;/a&gt;, a large installation of &lt;a href="https://www.zimbra.com"&gt;Zimbra&lt;/a&gt; (which was hosted within an LXC container running CentOS 7), as well as some minor Alpine Linux-based machines. We located all these virtual machines and containers in a LAN created and managed by CHR. All public IPs were managed by CHR, which relied on NAT mappings to establish communication between them. CHR had thus become the heart of our system, and if it experienced any issues, it could potentially take down the entire system. Fortunately, it remained stable for years.&lt;/p&gt;
&lt;h3&gt;Migration - first steps&lt;/h3&gt;
&lt;p&gt;The first step I took was to install FreeBSD on the new server. Easy peasy. The next step was to find a way for the CHR to migrate to the new server (under &lt;a href="https://bhyve.org"&gt;bhyve&lt;/a&gt;) and continue to manage all the public IPs of the original server. The problem is that OVH, with its failover IPs, &lt;a href="https://it-notes.dragas.net/2022/01/14/freebsd-assign-ovh-failover-ips-to-freebsd-jails/"&gt;ties a specific MAC address to each individual IP address&lt;/a&gt;. Therefore, the only way was to create a bridge on the FreeBSD server (on the Proxmox server, I already had the bridge on the physical network card) and create an L2 tunnel between the two servers - I used OpenVPN with tap interfaces, specifically inserted into the bridges. I could have used other methods and techniques, but I wanted to experiment with a setup that could allow, if necessary, to bridge a larger number of physical and virtual servers even if the IPs are all mapped to a single server. OVH does not allow, in fact, the splitting of classes, so a move must be made for the entire class, not for a single IP address.&lt;/p&gt;
&lt;p&gt;Initially, MikroTik CHR 7 did not boot on bhyve. In the end, &lt;a href="https://it-notes.dragas.net/2023/03/21/creating-a-mikrotik-chr-routeros-7-bhyve-vm-in-freebsd-2/"&gt;I managed to make it work&lt;/a&gt;, but I had other problems, probably related to the MTU of the interfaces. So I thought about taking the opportunity to unbind the LXC containers and VMs from CHR and remove MikroTik from the setup. With RouterOS version 7, in fact, Wireguard-based VPNs are also supported, so within a few days, it was possible to update the few routers still on 6.x and recreate some VPNs using Wireguard. I mapped both the VMs and LXC containers directly to their respective public IPs, greatly simplifying the steps. Everything worked perfectly.&lt;/p&gt;
&lt;p&gt;The next step was to test the first migrations, starting from the VMs already on FreeBSD. For simplicity, I created a new FreeBSD VM in bhyve and copied (via zfs-send and zfs-receive) the datasets related to &lt;a href="https://bastillebsd.org"&gt;BastilleBSD&lt;/a&gt;. All services are installed in jails managed by Bastille, so this was enough to have, in a short time, a new operating server equivalent to the previous one. At that point, I shut down the original server, connected the VM to the bridge linked to the tunnel (after modifying its MAC address), turned on the new FreeBSD VM (on bhyve), and everything started to work correctly - but from the new physical server.&lt;/p&gt;
&lt;p&gt;One by one, I moved all the FreeBSD VMs. For Linux, NetBSD, and OpenBSD, I simply copied the images and pointed bhyve to them. Some small specific configuration on vm-bhyve and everything started to work correctly. &lt;a href="https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/"&gt;Where possibile&lt;/a&gt;, I replaced the “virtio” with “nvme” as &lt;a href="https://klarasystems.com/articles/virtualization-showdown-freebsd-bhyve-linux-kvm/"&gt;it performs much better on bhyve&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Migration - LXC containers to Virtual Machines&lt;/h3&gt;
&lt;p&gt;For LXC containers, I initially thought of creating an Alpine Linux virtual machine, installing LXD, and copying each individual container. It worked for some of them, but for others, I started to encounter strange issues, similar to those that would have required manual intervention to upgrade from Proxmox 6.x to 7.x. As is often the case with Linux-based solutions, compatibility is not always preserved between updates, so I would have had to fine-tune all the containers, which I didn't feel like doing. The containers had been created (at the time) to optimize RAM usage on the Proxmox machine, but to date, they have caused more problems than benefits. In some cases, certain processes got "stuck," making it impossible to "reboot" the LXC container, requiring the entire physical node to be rebooted. If they had been virtual machines, I could have given a "kill" command from the virtualizer (to the respective KVM process, in that case) and restarted it.&lt;/p&gt;
&lt;p&gt;For greater compatibility and ease of future management, I decided to convert the LXC containers into actual VMs on bhyve. The process was simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating an empty VM with vm-bhyve and booting the VM with SystemRescueCD.&lt;/li&gt;
&lt;li&gt;Creating destination partitions and file systems in the VM, then doing a complete rsync of the original LXC container.&lt;/li&gt;
&lt;li&gt;Adjusting the fstab file, installing the kernel on the destination VM, and creating the initrd (some containers were already copies of VMs, so the kernel remained installed and updated, even though it wasn't being used. The initrd, on the other hand, did not include the &lt;em&gt;nvme&lt;/em&gt; or &lt;em&gt;virtio&lt;/em&gt; drivers, so I had to regenerate it anyway.)&lt;/li&gt;
&lt;li&gt;Adjusting the bhyve vm configuration file, doing one last rsync after shutting down the services, shutting down the original LXC container, and starting the bhyve VM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything worked correctly, so one by one, I moved all the containers. The largest one ended up on another physical node (also FreeBSD with bhyve) temporarily because the space on the new server was not sufficient to contain it. It didn't need to be on this server, so no problem.&lt;/p&gt;
&lt;p&gt;One by one, the LXC containers started on the new server. Apart from some minor adjustments to the destination VMs (different network interface names, etc.), I didn't encounter any particular problems even after several days. Everything works perfectly.&lt;/p&gt;
&lt;p&gt;At the very end, I re-created the MikroTik CHR VM. I’ll keep this setup separate for now, as strictly tied to eoip interfaces. This was the main reason why I haven’t performed the migration before. Things were too tied together and I had to untie everything, step by step.&lt;/p&gt;
&lt;h3&gt;…and then one of the Linux VMs started to freeze&lt;/h3&gt;
&lt;p&gt;Several Linux VMs are just the basis on which Docker runs. One of them (not even among the busiest) started, every 12/15 hours, to completely freeze. It stopped responding to ping, and it was impossible to give any type of command from the console. In a word: &lt;em&gt;stuck&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Searching the web, I found some references to this problem and, observing the errors of an ssh session that was left connected (stuck, but still showing the last error), I found it to be a problem &lt;a href="https://forums.freebsd.org/threads/bhyve-debian-with-docker-unstable.87956/"&gt;similar to the one described in this post&lt;/a&gt;, namely:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;&amp;quot;watchdog: BUG: soft lockup - CPU#0 stuck for 22s! [khugepaged:67]&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I tried various solutions such as changing the storage driver, the number of cores, the distribution (from Alpine to Debian), etc., but none of these operations solved the issue. I also noticed that the problem occurs with all Linux VMs, but only those with a recent kernel (&amp;gt; 5.10.x) freeze, while the others continue to work. The problem does not occur, however, with the *BSDs.&lt;/p&gt;
&lt;p&gt;In the end, I:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced the number of cores to 1 for the VMs that did not have a high load (some remained with multiple cores), hypothesising a problem with allocating cores that were too busy&lt;/li&gt;
&lt;li&gt;Gave the command: "&lt;em&gt;/usr/bin/echo 60 &amp;gt; /proc/sys/kernel/watchdog_thresh&lt;/em&gt;" to the VM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The VM became stable, and I have not seen that error/warning on any other machine since. I will investigate further, but I believe it is a problem related to the Linux kernel, which, for some reason, generates a kernel panic if particular situations of CPU concurrency are generated.&lt;/p&gt;
&lt;h3&gt;The End…and a nice OOM!&lt;/h3&gt;
&lt;p&gt;After moving everything, I was finally able to migrate the entire class of OVH IPs from one physical server to another. The operation was quite quick, but in order to avoid problems, I notified all users and performed the operation on a Sunday and during off-peak hours. The whole process took about 10 minutes and there were no hitches of any kind.&lt;/p&gt;
&lt;p&gt;For safety reasons, I kept the Proxmox machine active for a few more days, but there was no need to use it. However, after a couple of days, I encountered a problem: the largest VM, in some cases, was being "killed" because FreeBSD generated an OOM. I had never seen, from FreeBSD 13.0 onwards, any OOM related to "abuse" of RAM usage by ZFS, but in this case, it actually happened.&lt;/p&gt;
&lt;p&gt;In the end, I understood that ZFS, on FreeBSD, is able to release memory, but not quickly enough to manage any "spikes" in individual VMs. In fact, the VMs do not know the situation of the physical host's RAM, so they will tend to occupy all the space allotted to them (even if only for caching). A sudden spike (i.e. if you create and launch a new VM) could cause a sudden increase in RAM usage by the bhyve process, and FreeBSD could be forced to kill it, even if part of the RAM is only ARC cache. While Proxmox supports HA (i.e., control over whether the VM is running), vm-bhyve only launches the VM (bhyve process). I should manage it with tools like &lt;em&gt;&lt;a href="https://mmonit.com/monit/"&gt;monit&lt;/a&gt;&lt;/em&gt;, but for now, I preferred to simply set limits on ZFS RAM usage using "vfs.zfs.arc_max", and there have been no more problems.&lt;/p&gt;
&lt;h3&gt;Final considerations&lt;/h3&gt;
&lt;p&gt;The operation was long but linear. The most complex part was unraveling all the configurations related to MikroTik CHR and the VPNs linked to each individual LXC machine/container. Once everything was implemented on a dedicated VM, the operation was fairly straightforward.&lt;/p&gt;
&lt;p&gt;The hardware specifications of the destination physical server are slightly better than the starting one, but the final performance of the setup has greatly improved. The VMs are very responsive (even those that were previously LXC containers running directly on bare metal) and, thanks to ZFS, I can make local snapshots every 5 minutes. In addition, every 10 minutes, I can copy (using the excellent zfs-autobackup) all the VMs and jails to other nodes &lt;a href="https://it-notes.dragas.net/2022/05/30/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-2/"&gt;both as a backup and as an immediate restart in case of disaster&lt;/a&gt;. I just need to map the IPs, and everything will start working very quickly. Proxmox also allows you to perform this type of operation with ZFS, but you still need to have Proxmox (in a compatible version) on the target machine. With the current setup, I only need any FreeBSD node that supports bhyve.&lt;/p&gt;
&lt;p&gt;Proxmox is an excellent tool, well-developed, open-source, efficient, and stable. We manage many installations, including complex ones (&lt;a href="https://it-notes.dragas.net/2020/06/29/create-automatic-snapshots-on-cephfs/"&gt;ceph clusters&lt;/a&gt;, etc.), and it has never let us down. However, not all tools are ideal for all situations, and for setups like the one described, the new configuration based on FreeBSD has shown significantly interesting performance and greater management and maintenance granularity.&lt;/p&gt;
&lt;p&gt;Virtualizing on vm-bhyve is not complex, but it is certainly not comparable, at the current state, to the simplicity of using a clean and complete interface like Proxmox's. A complete HA system is still missing (sure, it's achievable manually, but...), as well as complete management web interface. However, for knowledgeable users, it is undoubtedly a powerful tool that allows you to have excellent FreeBSD as a base. I'm totally satisfied with my migration and the result is far better than I expected.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 14 Mar 2023 13:00:00 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2023/03/14/how-we-are-migrating-many-of-our-servers-from-linux-to-freebsd-part-3/</guid><category>freebsd</category><category>alpine</category><category>data</category><category>bhyve</category><category>filesystems</category><category>docker</category><category>ha</category><category>hardware</category><category>hosting</category><category>linux</category><category>lxc</category><category>networking</category><category>ovh</category><category>proxmox</category><category>recovery</category><category>restore</category><category>server</category><category>snapshots</category><category>virtualization</category><category>web</category><category>zfs</category><category>backup</category><category>jail</category><category>container</category><category>mikrotik</category><category>ownyourdata</category><category>series</category></item><item><title>Creating an Alpine Linux VM on bhyve - with root on ZFS (optionally encrypted)</title><link>https://it-notes.dragas.net/2022/11/01/creating-an-alpine-vm-on-bhyve-with-root-on-zfs-optionally-encrypted/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/alps.webp" alt="Creating an Alpine Linux VM on bhyve - with root on ZFS (optionally encrypted)"&gt;&lt;/p&gt;&lt;p&gt;Bhyve is great - and we’re using it with a lot of guest operating systems.&lt;/p&gt;
&lt;p&gt;One of my favourite Linux distributions is &lt;a href="https://alpinelinux.org"&gt;Alpine Linux&lt;/a&gt; - it’s great as a docker or lxc/lxd host, is light, stable and easily manageable.&lt;/p&gt;
&lt;p&gt;On FreeBSD, &lt;a href="https://github.com/churchers/vm-bhyve"&gt;vm-bhyve&lt;/a&gt; already provides a good template for Alpine Linux, but it’s based on the plain standard image with boot on ext4.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So we need the &lt;a href="https://alpinelinux.org/downloads/"&gt;alpine-extended iso&lt;/a&gt; -&lt;/strong&gt; with zfs module.&lt;/p&gt;
&lt;p&gt;Let’s create a new Alpine Linux bhyve VM:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;vm create -t alpine -s 50G -m 4G -c 2 alpinevm&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now let’s configure it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;vm configure alpinevm&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s change some options: &lt;em&gt;vmlinuz-vanilla&lt;/em&gt; and &lt;em&gt;initramfs-vanilla&lt;/em&gt; should be changed to &lt;em&gt;vmlinuz-lts&lt;/em&gt; and &lt;em&gt;initramfs-lts&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;More, we should instruct grub to boot from ZFS. The configuration should be similar to this:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;[…]
grub_install0=&amp;quot;linux /boot/vmlinuz-lts initrd=/boot/initramfs-lts alpine_dev=cdrom:iso9660 modules=loop,squashfs,sd-mod,usb-storage,sr-mod&amp;quot;
grub_install1=&amp;quot;initrd /boot/initramfs-lts&amp;quot;
grub_run0=&amp;quot;linux /boot/vmlinuz-lts root=rpool/ROOT/alpine rootfstype=zfs modules=ext4,zfs&amp;quot;
grub_run1=&amp;quot;initrd /boot/initramfs-lts&amp;quot;
[…]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’s now time to start with the installation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;vm install alpinevm &lt;em&gt;alpine-extended.iso&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, follow &lt;a href="https://wiki.alpinelinux.org/wiki/Root_on_ZFS_with_native_encryption"&gt;this Alpine Linux Wiki guide&lt;/a&gt;. Remember that we’re dealing with “&lt;em&gt;vda&lt;/em&gt;” devices, not &lt;em&gt;"sda"&lt;/em&gt;, so change them accordingly. If you don’t want to have an encrypted rootfs dataset, just avoid the encryption line in the zpool create command.&lt;/p&gt;
&lt;p&gt;At the end of the installation procedure, reboot and enjoy your new Alpine Linux bhyve VM.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 01 Nov 2022 15:47:35 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2022/11/01/creating-an-alpine-vm-on-bhyve-with-root-on-zfs-optionally-encrypted/</guid><category>alpine</category><category>linux</category><category>server</category><category>tutorial</category><category>zfs</category><category>freebsd</category><category>hosting</category><category>filesystems</category><category>bhyve</category><category>virtualization</category></item></channel></rss>