<?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 - openbsd</title><link>https://it-notes.dragas.net/categories/openbsd/</link><description>Articles in category openbsd</description><language>en</language><lastBuildDate>Wed, 19 Nov 2025 09:16:00 +0100</lastBuildDate><atom:link href="https://it-notes.dragas.net/categories/openbsd/feed.xml" rel="self" type="application/rss+xml"></atom:link><item><title>Static Web Hosting on the Intel N150: FreeBSD, SmartOS, NetBSD, OpenBSD and Linux Compared  </title><link>https://it-notes.dragas.net/2025/11/19/static-web-hosting-intel-n150-freebsd-smartos-netbsd-openbsd-linux/</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;Update&lt;/strong&gt;: This post has been updated to include &lt;strong&gt;Docker&lt;/strong&gt; benchmarks and a comparison of container overhead versus FreeBSD Jails and illumos Zones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Some operating systems (FreeBSD and Linux) support kernel TLS (kTLS) and the related SSL_sendfile path in nginx, which can improve HTTPS performance for static files. Since this feature is not available on all the systems included in the comparison (for example NetBSD, OpenBSD and illumos), the benchmarks were run with a common baseline configuration that does not rely on kTLS. The goal is to compare the systems under similar conditions rather than to measure OS specific optimizations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I often get very specific infrastructure requests from clients. Most of the time it is some form of hosting. My job is usually to suggest and implement the setup that fits their goals, skills and long term plans.  &lt;/p&gt;
&lt;p&gt;If there are competent technicians on the other side, and they are willing to learn or already comfortable with Unix style systems, my first choices are usually one of the BSDs or an illumos distribution. If they need a control panel, or they already have a lot of experience with a particular stack that will clearly help them, I will happily use Linux and it usually delivers solid, reliable results.  &lt;/p&gt;
&lt;p&gt;Every now and then someone asks the question I like the least:  &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“But how does it &lt;em&gt;perform&lt;/em&gt; compared to X or Y?”  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have never been a big fan of benchmarks. At best they capture a very specific workload on a very specific setup. They are almost never a perfect reflection of what will happen in the real world.  &lt;/p&gt;
&lt;p&gt;For example, I discovered that idle bhyve VMs seem to use fewer resources when the host is illumos than when the host is FreeBSD. It looks strange at first sight, but the illumos people are clearly working very hard on this, and the result is a very capable and efficient platform.  &lt;/p&gt;
&lt;p&gt;Despite my skepticism, from time to time I enjoy running some comparative tests. I already did it with &lt;a href="https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/"&gt;Proxmox KVM versus FreeBSD bhyve&lt;/a&gt;, and I also &lt;a href="https://it-notes.dragas.net/2025/09/19/freebsd-vs-smartos-whos-faster-for-jails-zones-bhyve/"&gt;compared Jails, Zones, bhyve and KVM&lt;/a&gt; on the same Intel N150 box. That led to the FreeBSD vs SmartOS article where I focused on CPU and memory performance on this small mini PC.  &lt;/p&gt;
&lt;p&gt;This time I wanted to do something simpler, but also closer to what I see every day: &lt;strong&gt;static web hosting.&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;Instead of synthetic CPU or I/O tests, I wanted to measure how different operating systems behave when they serve a small static site with nginx, both over HTTP and HTTPS.  &lt;/p&gt;
&lt;p&gt;This is &lt;strong&gt;not&lt;/strong&gt; meant to be a super rigorous benchmark. I used the default nginx packages, almost default configuration, and did not tune any OS specific kernel settings. In my experience, careful tuning of kernel and network parameters can easily move numbers by several tens of percentage points. The problem is that very few people actually spend time chasing such optimizations. Much more often, once a limit is reached, someone yells “we need mooooar powaaaar” while the real fix would be to tune the existing stack a bit.&lt;/p&gt;
&lt;p&gt;So the question I want to answer here is more modest and more practical:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With default nginx and a small static site, how much does the choice of host OS really matter on this Intel N150 mini PC?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Spoiler&lt;/em&gt;: less than people think, at least for plain HTTP. Things get more interesting once TLS enters the picture.&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;br /&gt;
These benchmarks are a snapshot of my specific hardware, network and configuration. They are useful to compare &lt;em&gt;relative&lt;/em&gt; behavior on this setup. They are not a universal ranking of operating systems. Different CPUs, NICs, crypto extensions, kernel versions or nginx builds can completely change the picture.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Test setup&lt;/h2&gt;
&lt;p&gt;The hardware is the same Intel N150 mini PC I used in my previous tests: a small, low power box that still has enough cores to be interesting for lab and small production workloads.  &lt;/p&gt;
&lt;p&gt;On it, I installed several operating systems and environments, always on the bare metal, not nested inside each other. On each OS I installed nginx from the official packages.  &lt;/p&gt;
&lt;h3&gt;Software under test&lt;/h3&gt;
&lt;p&gt;On the host:  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SmartOS&lt;/strong&gt;, with:&lt;br /&gt;
- a Debian 12 LX zone&lt;br /&gt;
- an Alpine Linux 3.22 LX zone&lt;br /&gt;
- a native SmartOS zone  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt; 14.3-RELEASE:&lt;br /&gt;
- nginx running inside a native jail  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenBSD&lt;/strong&gt; 7.8:&lt;br /&gt;
- nginx on the host  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NetBSD&lt;/strong&gt; 10.1:&lt;br /&gt;
- nginx on the host  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debian&lt;/strong&gt; 13.2:&lt;br /&gt;
- nginx on the host &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alpine Linux&lt;/strong&gt; 3.22:&lt;br /&gt;
- nginx on the host&lt;br /&gt;
- Docker: Debian 13 container running on the Alpine host (ports mapped)&lt;/p&gt;
&lt;p&gt;I also tried to include &lt;strong&gt;DragonFlyBSD&lt;/strong&gt;, but the NIC in this box is not supported. Using a different NIC just for one OS would have made the comparison meaningless, so I excluded it.  &lt;/p&gt;
&lt;h3&gt;nginx configuration&lt;/h3&gt;
&lt;p&gt;In all environments:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nginx was installed from the system packages  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker_processes&lt;/code&gt; was set to &lt;code&gt;auto&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;the web root contained the same static content  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important part is that I used &lt;strong&gt;exactly the same &lt;code&gt;nginx.conf&lt;/code&gt; file for all operating systems and all combinations in this article&lt;/strong&gt;. I copied the same configuration file verbatim to every host, jail and zone. The only changes were the IP address and file paths where needed, for example for the TLS certificate and key.  &lt;/p&gt;
&lt;p&gt;The static content was a default build of the example site generated by &lt;a href="https://bssg.dragas.net/"&gt;&lt;strong&gt;BSSG&lt;/strong&gt;, my Bash static site generator&lt;/a&gt;. The web root was the same logical structure on every OS and container type.  &lt;/p&gt;
&lt;p&gt;There is no OS specific tuning in the configuration and no kernel level tweaks. This is very close to a “package install plus minimal config” situation.  &lt;/p&gt;
&lt;h3&gt;TLS configuration&lt;/h3&gt;
&lt;p&gt;For HTTPS I used a very simple configuration, identical on every host.  &lt;/p&gt;
&lt;p&gt;Self signed certificate created with:  &lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;openssl req -x509 -newkey rsa:4096 -nodes -keyout server.key -out server.crt -days 365 -subj &amp;quot;/CN=localhost&amp;quot;  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Example nginx &lt;code&gt;server&lt;/code&gt; block for HTTPS (simplified):  &lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-nginx"&gt;server {  
listen 443 ssl http2;  
listen [::]:443 ssl http2;  

server_name _;  

ssl_certificate /etc/nginx/ssl/server.crt;  
ssl_certificate_key /etc/nginx/ssl/server.key;  

root /var/www/html;  
index index.html index.htm;  

location / {  
try_files $uri $uri/ =404;  
}  
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The HTTP virtual host is also the same everywhere, with the root pointing to the BSSG example site.  &lt;/p&gt;
&lt;h3&gt;Load generator&lt;/h3&gt;
&lt;p&gt;The tests were run from my workstation on the same LAN:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;client host: a mini PC machine connected at 2.5 Gbit/s  &lt;/li&gt;
&lt;li&gt;switch: 2.5 Gbit/s  &lt;/li&gt;
&lt;li&gt;test tool: &lt;code&gt;wrk&lt;/code&gt;  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each target host I ran:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wrk -t4 -c50 -d10s http://IP&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;wrk -t4 -c10 -d10s http://IP&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;wrk -t4 -c50 -d10s https://IP&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;wrk -t4 -c10 -d10s https://IP&lt;/code&gt;  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each scenario was executed multiple times to reduce noise; the numbers below are medians (or very close to them) from the runs.&lt;/p&gt;
&lt;h2&gt;The contenders&lt;/h2&gt;
&lt;p&gt;To keep things readable, I will refer to each setup as follows:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SmartOS Debian LX&lt;/strong&gt; → SmartOS host, Debian 12 LX zone  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SmartOS Alpine LX&lt;/strong&gt; → SmartOS host, Alpine 3.22 LX zone  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SmartOS Native&lt;/strong&gt; → SmartOS host, native zone  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FreeBSD Jail&lt;/strong&gt; → FreeBSD 14.3-RELEASE, nginx in a jail  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenBSD Host&lt;/strong&gt; → OpenBSD 7.8, nginx on the host  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NetBSD Host&lt;/strong&gt; → NetBSD 10.1, nginx on the host  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debian Host&lt;/strong&gt; → Debian 13.2, nginx on the host  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alpine Host&lt;/strong&gt; → Alpine 3.22, nginx on the host  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker Container&lt;/strong&gt; → Alpine host, Debian 13 Docker container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything uses the same nginx configuration file and the same static site.  &lt;/p&gt;
&lt;h2&gt;Static HTTP results&lt;/h2&gt;
&lt;p&gt;Let us start with plain HTTP, since this removes TLS from the picture and focuses on the kernel, network stack and nginx itself.  &lt;/p&gt;
&lt;h3&gt;HTTP, 4 threads, 50 concurrent connections&lt;/h3&gt;
&lt;p&gt;Approximate median &lt;code&gt;wrk&lt;/code&gt; results:  &lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;HTTP 50 connections&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SmartOS Debian LX&lt;/td&gt;
&lt;td&gt;~46.2 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SmartOS Alpine LX&lt;/td&gt;
&lt;td&gt;~49.2 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SmartOS Native&lt;/td&gt;
&lt;td&gt;~63.7 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FreeBSD Jail&lt;/td&gt;
&lt;td&gt;~63.9 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenBSD Host&lt;/td&gt;
&lt;td&gt;~64.1 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NetBSD Host&lt;/td&gt;
&lt;td&gt;~64.0 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debian Host&lt;/td&gt;
&lt;td&gt;~63.8 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alpine Host&lt;/td&gt;
&lt;td&gt;~63.9 k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker Container&lt;/td&gt;
&lt;td&gt;~63.7 k&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two things stand out:  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All the native or jail/container setups on the hosts that are not LX zones cluster around 63 to 64k requests per second.  &lt;/li&gt;
&lt;li&gt;The two SmartOS LX zones sit slightly lower, in the 46 to 49k range, which is still very respectable for this hardware.  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In other words, as long as you are on the host or in something very close to it (FreeBSD jail, SmartOS native zone, NetBSD, OpenBSD, Linux on bare metal), static HTTP on nginx will happily max out around 64k requests per second with this small Intel N150 CPU.  &lt;/p&gt;
&lt;p&gt;The Debian and Alpine LX zones on SmartOS are a bit slower, but not dramatically so. They still deliver close to 50k requests per second and, in a real world scenario, you would probably saturate the network or the client long before hitting those numbers.  &lt;/p&gt;
&lt;h3&gt;HTTP, 4 threads, 10 concurrent connections&lt;/h3&gt;
&lt;p&gt;With fewer concurrent connections, absolute throughput drops, but the relative picture is similar:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SmartOS Native around 44k  &lt;/li&gt;
&lt;li&gt;NetBSD and Alpine Host around 34 to 35k  &lt;/li&gt;
&lt;li&gt;FreeBSD, Debian, OpenBSD around 31 to 33k  &lt;/li&gt;
&lt;li&gt;The Docker Container sits slightly lower at ~30.2k req/s, showing a small overhead from the networking layer  &lt;/li&gt;
&lt;li&gt;The SmartOS LX zones sit slightly below, around 35 to 37k req/s  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important conclusion is simple:  &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For plain HTTP static hosting, once nginx is installed and correctly configured, the choice between these operating systems makes very little difference on this hardware. Zones and jails add negligible overhead, LX zones add a small one.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are only serving static content over HTTP, your choice of OS should be driven by other factors: ecosystem, tooling, update strategy, your own expertise and preference.  &lt;/p&gt;
&lt;h2&gt;Static HTTPS results&lt;/h2&gt;
&lt;p&gt;TLS is where things start to diverge more clearly and where CPU utilization becomes interesting.  &lt;/p&gt;
&lt;h3&gt;HTTPS, 4 threads, 50 concurrent connections&lt;/h3&gt;
&lt;p&gt;Approximate medians:  &lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;HTTPS 50 connections&lt;/th&gt;
&lt;th&gt;CPU notes at 50 HTTPS connections&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SmartOS Debian LX&lt;/td&gt;
&lt;td&gt;~51.4 k&lt;/td&gt;
&lt;td&gt;CPU saturated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SmartOS Alpine LX&lt;/td&gt;
&lt;td&gt;~40.4 k&lt;/td&gt;
&lt;td&gt;CPU saturated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SmartOS Native&lt;/td&gt;
&lt;td&gt;~52.8 k&lt;/td&gt;
&lt;td&gt;CPU saturated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FreeBSD Jail&lt;/td&gt;
&lt;td&gt;~62.9 k&lt;/td&gt;
&lt;td&gt;around 60% CPU idle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenBSD Host&lt;/td&gt;
&lt;td&gt;~39.7 k&lt;/td&gt;
&lt;td&gt;CPU saturated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NetBSD Host&lt;/td&gt;
&lt;td&gt;~40.4 k&lt;/td&gt;
&lt;td&gt;CPU saturated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debian Host&lt;/td&gt;
&lt;td&gt;~62.8 k&lt;/td&gt;
&lt;td&gt;about 20% CPU idle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alpine Host&lt;/td&gt;
&lt;td&gt;~62.4 k&lt;/td&gt;
&lt;td&gt;small idle headroom, around 7% idle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker Container&lt;/td&gt;
&lt;td&gt;~62.7 k&lt;/td&gt;
&lt;td&gt;CPU saturated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These numbers tell a more nuanced story.  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FreeBSD, Debian and Alpine on bare metal form a “fast TLS” group.&lt;/strong&gt;&lt;br /&gt;
All three sit around 62 to 63k requests per second with 50 concurrent HTTPS connections.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FreeBSD does this while using significantly less CPU.&lt;/strong&gt;&lt;br /&gt;
During the HTTPS tests with 50 connections, the FreeBSD host still had around 60% CPU idle. It is the platform that handled TLS load most comfortably in terms of CPU headroom.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Debian and Alpine are close in throughput, but push the CPU harder.&lt;/strong&gt;&lt;br /&gt;
Debian still had some idle time left, Alpine even less. In practice, all three are excellent here, but FreeBSD gives you more room before you hit the wall.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SmartOS, NetBSD and OpenBSD form a “good but heavier” TLS group.&lt;/strong&gt;&lt;br /&gt;
Their HTTPS throughput is in the 40 to 52k req/s range and they reach full CPU usage at 50 concurrent connections. OpenBSD and NetBSD stabilize around 39 to 40k req/s. SmartOS native and the Debian LX zone manage slightly better (around 51 to 53k) but still with the CPU pegged.  &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;HTTPS, 4 threads, 10 concurrent connections&lt;/h3&gt;
&lt;p&gt;With lower concurrency:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FreeBSD, Debian and Alpine still sit in roughly the 29 to 31k req/s range  &lt;/li&gt;
&lt;li&gt;SmartOS Native and LX zones are in the mid to high 30k range  &lt;/li&gt;
&lt;li&gt;The Docker Container drops slightly to ~27.8k req/s  &lt;/li&gt;
&lt;li&gt;NetBSD and OpenBSD sit around 26 to 27k req/s  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The relative pattern is the same: for this TLS workload, FreeBSD and modern Linux distributions on bare metal appear to make better use of the cryptographic capabilities of the CPU, delivering higher throughput or more headroom or both.  &lt;/p&gt;
&lt;h2&gt;What TLS seems to highlight&lt;/h2&gt;
&lt;p&gt;The HTTPS tests point to something that is not about nginx itself, but about the TLS stack and how well it can exploit the hardware.  &lt;/p&gt;
&lt;p&gt;On this Intel N150, my feeling is:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FreeBSD, with the userland and crypto stack I am running, is very efficient at TLS here. It delivers the highest throughput while keeping plenty of CPU in reserve.  &lt;/li&gt;
&lt;li&gt;Debian and Alpine, with their recent kernels and libraries, are also strong performers, close to FreeBSD in throughput, but with less idle CPU.  &lt;/li&gt;
&lt;li&gt;NetBSD, OpenBSD and SmartOS (native and LX) are still perfectly capable of serving a lot of HTTPS traffic, but they have to work harder to keep up and they hit 100% CPU much earlier.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This matches what I see in day to day operations: TLS performance is often less about “nginx vs something else” and more about the combination of:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the TLS library version and configuration  &lt;/li&gt;
&lt;li&gt;how well the OS uses the CPU crypto instructions  &lt;/li&gt;
&lt;li&gt;kernel level details in the network and crypto paths  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I suspect the differences here are mostly due to how each system combines its TLS stack (OpenSSL, LibreSSL and friends), its kernel and its hardware acceleration support. It would take a deeper dive into profiling and configuration knobs to attribute the gaps precisely.  &lt;/p&gt;
&lt;p&gt;In any case, on this specific mini PC, if I had to pick a platform to handle a large amount of HTTPS static traffic, FreeBSD, Debian and Alpine would be my first candidates, in that order.  &lt;/p&gt;
&lt;h2&gt;Zones, jails, containers and Docker: overhead in practice&lt;/h2&gt;
&lt;p&gt;Another interesting part of the story is the overhead introduced by different isolation technologies.  &lt;/p&gt;
&lt;p&gt;From these tests and the &lt;a href="https://it-notes.dragas.net/2025/09/19/freebsd-vs-smartos-whos-faster-for-jails-zones-bhyve/"&gt;previous virtualization article on the same N150 machine&lt;/a&gt;, the picture is consistent:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FreeBSD jails behave almost like bare metal and are significantly more efficient than Docker.&lt;/strong&gt;&lt;br /&gt;
For both HTTP and HTTPS, running nginx in a jail on FreeBSD 14.3-RELEASE produces numbers practically identical to native hosts.&lt;br /&gt;
The contrast with Docker is striking: while the Docker container required 100% CPU to reach peak for the HTTP and HTTPS throughput, &lt;strong&gt;the FreeBSD jail delivered the same speed with ~60% of the CPU sitting idle&lt;/strong&gt;. In terms of performance cost per request, Jails are drastically cheaper.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SmartOS native zones are also very close to the metal.&lt;/strong&gt;&lt;br /&gt;
Static HTTP performance reaches the same 64k req/s region and HTTPS is only slightly behind the "fast TLS" group, although with higher CPU usage.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SmartOS LX zones introduce a noticeable but modest overhead.&lt;/strong&gt;&lt;br /&gt;
Both Debian and Alpine LX zones on SmartOS perform slightly worse than the native zone or FreeBSD jails. For static HTTP they are still very fast. For HTTPS the Debian LX zone remains competitive but costs more CPU, while the Alpine LX zone is slower.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker on Linux performs efficiently but eats the margins.&lt;/strong&gt;
I ran an additional test using a Debian 13 Docker container running on the Alpine Linux host.
At peak load (50 connections), the throughput was impressive and virtually identical to bare metal: ~63.7k req/s for HTTP and ~62.7k req/s for HTTPS.
However, there is a clear cost. First, while the bare metal host maintained a small CPU buffer (~7% idle) during the HTTPS test, Docker &lt;strong&gt;saturated the CPU to 100%&lt;/strong&gt;.
Second, at lower concurrency (10 connections), the overhead became visible. The Docker container scored ~30.2k req/s for HTTP and ~27.8k req/s for HTTPS, slightly trailing the ~31-34k and ~29-31k range of the bare metal counterparts. The abstraction layers (NAT, bridging, namespaces) are extremely efficient, but they are not completely free.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This leads to a clear conclusion on efficiency: &lt;strong&gt;FreeBSD Jails provide the highest throughput with the lowest CPU cost.&lt;/strong&gt; LX zones and Docker containers can match the speed (or come close), but they burn significantly more CPU cycles to do so.&lt;/p&gt;
&lt;h2&gt;What this means for real workloads&lt;/h2&gt;
&lt;p&gt;It is easy to get lost in tables and percentages, so let us go back to the initial question.  &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A client wants static hosting.&lt;br /&gt;
Does the choice between FreeBSD, SmartOS, NetBSD or Linux matter in terms of performance?  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For &lt;strong&gt;plain HTTP&lt;/strong&gt; on this hardware, with nginx and the same configuration:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Not really.&lt;br /&gt;
All the native hosts and FreeBSD jails deliver roughly the same maximum throughput, in the 63 to 64k req/s range. SmartOS LX zones are slightly slower but still strong.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For &lt;strong&gt;HTTPS&lt;/strong&gt;:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes, it starts to matter a bit more.  &lt;/li&gt;
&lt;li&gt;FreeBSD stands out for how relaxed the CPU is under high TLS load.  &lt;/li&gt;
&lt;li&gt;Debian and Alpine are very close in throughput, with more CPU used but still with some headroom.  &lt;/li&gt;
&lt;li&gt;SmartOS, NetBSD and OpenBSD can still push a lot of HTTPS traffic, but they reach 100% CPU earlier and stabilize at lower request rates.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Does this mean you should always choose FreeBSD or Debian or Alpine for static HTTPS hosting?  &lt;/p&gt;
&lt;p&gt;Not necessarily.  &lt;/p&gt;
&lt;p&gt;In real deployments, the bottleneck is rarely the TLS performance of a single node serving a small static site. Network throughput, storage, logging, reverse proxies, CDNs and application layers all play a role.  &lt;/p&gt;
&lt;p&gt;However, knowing that FreeBSD and current Linux distributions can squeeze more out of a small CPU under TLS is useful when you are:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sizing hardware for small VPS nodes that must serve many HTTPS requests  &lt;/li&gt;
&lt;li&gt;planning to consolidate multiple services on a low power box  &lt;/li&gt;
&lt;li&gt;deciding whether you can afford to keep some CPU aside for other tasks (cache, background jobs, monitoring, and so on)  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As always, the right answer depends on the complete picture: your skills, your tooling, your backups, your monitoring, the rest of your stack, and your tolerance for troubleshooting when things go sideways.  &lt;/p&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;From these small tests, my main takeaways are:  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Static HTTP is basically solved on all these platforms.&lt;/strong&gt;&lt;br /&gt;
On a modest Intel N150, every system tested can push around 64k static HTTP requests per second with nginx set to almost default settings. For many use cases, that is already more than enough.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TLS performance is where the OS and crypto stack start to matter.&lt;/strong&gt;&lt;br /&gt;
FreeBSD, Debian and Alpine squeeze more HTTPS requests out of the N150, and FreeBSD in particular does it with a surprising amount of idle CPU left. NetBSD, OpenBSD and SmartOS need more CPU to reach similar speeds and stabilize at lower throughput once the CPU is saturated.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Jails and native zones are essentially free, LX zones cost a bit more.&lt;/strong&gt;&lt;br /&gt;
FreeBSD jails and SmartOS native zones show very little overhead for this workload. SmartOS LX zones are still perfectly usable, but if you are chasing every last request per second you will see the cost of the translation layer.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Benchmarks are only part of the story.&lt;/strong&gt;&lt;br /&gt;
If your team knows OpenBSD inside out and has tooling, scripts and workflows built around it, you might happily accept using more CPU on TLS in exchange for security features, simplicity and familiarity. The same goes for NetBSD or SmartOS in environments where their specific strengths shine.  &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will not choose an operating system for a client just because a benchmark looks nicer. These numbers are one of the many inputs I consider. What matters most is always the combination of reliability, security, maintainability and the human beings who will have to operate the&lt;br /&gt;
system at three in the morning when something goes wrong.  &lt;/p&gt;
&lt;p&gt;Still, it is nice to know that if you put a tiny Intel N150 in front of a static site and you pick FreeBSD or a modern Linux distribution for HTTPS, you are giving that little CPU a fair chance to shine.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Wed, 19 Nov 2025 09:16:00 +0100</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/11/19/static-web-hosting-intel-n150-freebsd-smartos-netbsd-openbsd-linux/</guid><category>freebsd</category><category>smartos</category><category>illumos</category><category>linux</category><category>netbsd</category><category>openbsd</category><category>jail</category><category>zones</category><category>docker</category><category>hosting</category><category>server</category><category>sysadmin</category><category>ownyourdata</category></item><item><title>Launching BSSG - My Journey from Dynamic CMS to Bash Static Site Generator</title><link>https://it-notes.dragas.net/2025/04/07/launching-bssg-my-journey-from-dynamic-cms-to-bash-static-site-generator/</link><description>&lt;p&gt;&lt;img src="https://unsplash.com/photos/0gkw_9fy0eQ/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzQzOTQ2ODgyfA&amp;force=true&amp;w=1920" alt="Photo by Patrick Fore on Unsplash"&gt;&lt;/p&gt;&lt;p&gt;I've had my own website practically forever. Back in the late '90s, I already had a web page on my ISP's server, and since at least 2001, I've had my own homepage on my own server. I've never been a great graphic designer, let alone a skilled webmaster, so I've always tried to keep things minimal and compatible.&lt;/p&gt;
&lt;p&gt;Initially, like many others, I wrote HTML pages by hand. Then I used WYSIWYG creation tools, and eventually, I landed on CMS (Content Management Systems).&lt;/p&gt;
&lt;h2&gt;The Era of Dynamic CMS&lt;/h2&gt;
&lt;p&gt;I liked &lt;a href="https://en.wikipedia.org/wiki/Content_management_system"&gt;CMS&lt;/a&gt; because they allowed me to focus on the content and not on the correctness of the generated HTML. Thanks to them, I started writing my first blog shortly afterward.&lt;/p&gt;
&lt;p&gt;Over the years, I've used many tools like PHPNuke, FlatNuke (created and developed by my friend &lt;a href="https://simonevellei.com/"&gt;Simone Vellei&lt;/a&gt;), eventually moving through Joomla and Wordpress. Wordpress always seemed like the most suitable tool for the job, and I used it for many years. Even today, mainly on the sysadmin side, I manage hundreds of Wordpress sites, and they are reasonably reliable, aside from the plugins (because &lt;a href="https://www.youtube.com/live/_IdH5YTBAGs?t=9801"&gt;the problem with Wordpress isn't the software itself, but many of the external plugins&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;But this is precisely the problem: all dynamic CMS require constant and continuous security updates because, without them, the chances of defacement are extremely high.&lt;/p&gt;
&lt;h2&gt;Discovering Static Site Generators&lt;/h2&gt;
&lt;p&gt;And that's precisely why, when I discovered Carlos Fenollosa's &lt;a href="https://github.com/cfenollosa/bashblog"&gt;bashblog&lt;/a&gt; in 2014, it immediately became clear that, indeed, there was no reason to continue down the path of dynamic CMS. I don't write often, I don't update often, there's no reason to regenerate all the content with every visit. Sure, WordPress caching plugins are often quite effective, but they are still add-ons that need to be kept up to date. And I'm not a fan of adding things to streamline. Often, less is more.&lt;/p&gt;
&lt;p&gt;So, I started using bashblog for some 'secondary' projects until, in 2015, I &lt;a href="https://www.dragas.net/posts/da-wordpress-a-pelican/"&gt;migrated my 'old' Italian blog from WordPress to Pelican&lt;/a&gt;. Shortly after, I &lt;a href="https://www.dragas.net/posts/da-pelican-a-nikola/"&gt;moved from Pelican to Nikola&lt;/a&gt;, and that blog is still generated by Nikola, although (that blog's) updates are now extremely rare (so much so that I consider it almost abandoned). I also created the first Docker container for Nikola and, for a long time, it was listed among the deployment methods on their site.&lt;/p&gt;
&lt;h2&gt;Building My Own: BSSG&lt;/h2&gt;
&lt;p&gt;But bashblog continued to fascinate me. So in 2015, for fun, I started developing my own Static Site Generator from scratch. I called it (with little imagination), &lt;a href="https://bssg.dragas.net"&gt;BSSG - Bash Static Site Generator&lt;/a&gt;. The plan was for it to be compatible with the main OSes I use, to remain sufficiently simple and straightforward (!!!), and to be tailored to my needs. I intended to use it only and exclusively for small private things, starting with a sort of diary of mine - more professional than personal - and leave the 'official' blogs to more tested and 'professional' tools.&lt;/p&gt;
&lt;p&gt;As time went by, I added some small features I liked: theming support, archives, tags (initially absent). Over time, many functions were added, and the script grew large – large enough to make me pause and ask myself some questions about the long-term stability of this solution. So, it remained only for my 'diary', which, however, grew year after year to the point where I needed to devise some kind of optimization. I then developed (more for fun than out of real necessity) a caching system. On rebuild, only what needs to be rebuilt is reconstructed, making the operation sufficiently fast even as the number of posts grows. Obviously, there are limits: using bash and external tools, the efficiency cannot be compared to that of a proper programming language.&lt;/p&gt;
&lt;h2&gt;Brief Detour: ITNBlog&lt;/h2&gt;
&lt;p&gt;And it's here that I decided, in preparation for opening a new blog (this one), to create a new tool called &lt;a href="https://itnblog.dragas.net"&gt;ITNBlog&lt;/a&gt;. I would develop it in Python and focus a bit more on performance and completeness. But ITNBlog stalled very quickly: time was limited, I'm not a full-time developer, so I realized I would spend too much time on development and too little on content creation.&lt;/p&gt;
&lt;p&gt;Therefore, in 2018, I launched this blog but using &lt;a href="https://ghost.org/"&gt;Ghost&lt;/a&gt;, a solution that gave me good results, including performance-wise. I chose Ghost because I thought that, writing content also from my phone while on the go, a real CMS would be useful. Spoiler: no, it didn't turn out that way, so a few years later I decided to migrate this blog to &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;. Nevertheless, I continued to develop ITNBlog on and off, as a hobby, without any particular ambitions.&lt;/p&gt;
&lt;p&gt;At some point, however, I found myself in a particular situation: Hugo deprecated some features, and the theme I had chosen moved forward. But I ended up in an unpleasant situation: using the latest version of Hugo and the current version of the theme would produce unacceptable output; staying with the old version of Hugo while waiting for the theme update meant making a compromise. I actually build the blog from different devices, and they all have different versions of Hugo installed. Change the theme? Feasible, but I would have had to modify almost the entire site.&lt;/p&gt;
&lt;p&gt;I considered migrating to &lt;a href="https://github.com/gyptazy/manpageblog"&gt;manpageblog&lt;/a&gt; by &lt;a href="https://gyptazy.com/"&gt;gyptazy&lt;/a&gt; – I personally love its simplicity and retro look, and it was the main candidate to replace Hugo. I also created a script and migrated all my posts into the correct format.&lt;/p&gt;
&lt;h2&gt;BSSG to the Rescue (and ITNBlog's Role)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;That's when I realized: I would implement the few missing features needed to make ITNBlog sufficiently complete, and this blog would be published using it, ensuring I'd be committed to its development. However, ITNBlog is not mature enough to be released publicly, so for now, it will remain the engine just for my blog. Then I thought again about BSSG – development had stalled some time ago, but it was still in use – and figured that perhaps, with a little tidying up, I could release &lt;em&gt;it&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because I'm tired of seeing people use dynamic CMS even to implement primarily static blogs or websites – and BSSG, despite its limitations and inefficiencies, works. And there are many themes to choose from. In short, you can install it and generate your blog in seconds.&lt;/p&gt;
&lt;h2&gt;Why Choose BSSG?&lt;/h2&gt;
&lt;p&gt;BSSG is the result of a 10-year evolution. The code isn't extremely consistent, some interesting features are missing (which I plan to implement), and it could use refactoring as the build script is monstrously large. But it works, it's portable (and much of the complexity increased precisely because of portability), and it generates sites that achieve very high accessibility and speed scores.&lt;/p&gt;
&lt;p&gt;Here are some highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Portability:&lt;/strong&gt; Uses native OS tools (e.g., &lt;code&gt;md5sum&lt;/code&gt; on Linux, &lt;code&gt;md5&lt;/code&gt; on OpenBSD and NetBSD). Portability itself added much of the complexity!&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Simple Theming:&lt;/strong&gt; Themes are just simple CSS files, so the structure remains the same – simplifying theme switching or creating new ones. More than 50 themes &lt;a href="https://bssg.dragas.net/example"&gt;are already available&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Essential Features:&lt;/strong&gt; Supports RSS feed generation, sitemap.xml, OpenGraph tags (to improve social sharing), internationalization (the blog can be in languages other than English – but not multilingual, at least for now), etc.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Built-in Backup and Restore script:&lt;/strong&gt; It will just copy the configuration file, posts, and pages. Nothing else.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Minimal Dependencies.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Markdown Support:&lt;/strong&gt; Posts and pages are in Markdown (CommonMark, Pandoc, and markdown.pl are supported).&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Feature Images.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Optional GNU Parallel Integration:&lt;/strong&gt; To speed up build times when there are many posts. This feature significantly impacts the code and has caused me numerous headaches over time. But it's optional (if &lt;code&gt;parallel&lt;/code&gt; isn't found, it proceeds traditionally) and only provides benefits when the number of posts increases: with few posts, performance actually degrades.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;High Accessibility and Performance Scores:&lt;/strong&gt; Sites built with BSSG achieve excellent scores.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;BSD Licensed:&lt;/strong&gt; Released under a BSD license.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One of the problems I've always had with all CMS and SSGs has been choosing a theme. In some cases (like Hugo), the theme heavily influences the output, which is both good and bad. Good because it makes each site unique, but bad because it makes switching themes difficult. In the past, I've sometimes found myself having to change themes because they were abandoned and no longer updated. BSSG works differently: theming comes from using a different CSS file, which makes its structure more rigid, but switching from one theme to another is trivial. To help with the choice, I created a script that will build your site using all the themes present in the &lt;code&gt;themes&lt;/code&gt; directory, just like on the examples page of the official website. This way, it will be easy to see and test your site with all available themes. If you want to add a touch of originality, you can choose the 'random' theme, and one will be chosen randomly from the list at each site regeneration.&lt;/p&gt;
&lt;h2&gt;Admin Interface (Experimental)&lt;/h2&gt;
&lt;p&gt;BSSG is in production use by some clients (for their internal sites), for whom I also created a basic admin interface (using Node Express, partly to chew on a bit of Node), but I don't feel ready to release it immediately as it's not sufficiently tested. It has an integrated Markdown editor and allows post scheduling, generating the files and launching BSSG with the right options at the right time. This could be that connecting link between traditional CMS and SSGs. There are others, but this one is tightly integrated with BSSG.&lt;/p&gt;
&lt;h2&gt;BSSG is Available Today&lt;/h2&gt;
&lt;p&gt;Starting today, BSSG is publicly available. It's not perfect, it probably doesn't make sense to do something of this complexity in bash, development will proceed slowly – but it's here, available to anyone who might find it useful.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bssg.dragas.net"&gt;Happy blogging everyone!&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Mon, 07 Apr 2025 08:11:36 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/04/07/launching-bssg-my-journey-from-dynamic-cms-to-bash-static-site-generator/</guid><category>bssg</category><category>ssg</category><category>ownyourdata</category><category>freebsd</category><category>openbsd</category><category>netbsd</category><category>linux</category><category>server</category><category>web</category><category>blogging</category></item><item><title>OSDay 2025 - Why Choose to Use the BSDs in 2025</title><link>https://it-notes.dragas.net/2025/03/23/osday-2025-why-choose-bsd-in-2025/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/nana_bianca.avif" alt="Photo: Nana Bianca - Firenze"&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;This is the text underlying my presentation at &lt;a href="https://osday.dev"&gt;OSDay 2025&lt;/a&gt;, held on 21 March 2025 in Florence, Italy. There was limited time, so I couldn't go into much detail and had to keep things more general and structured than usual. You can watch &lt;a href="https://www.youtube.com/live/_IdH5YTBAGs?t=24936s"&gt;the video of my talk on YouTube&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The slides can be downloaded &lt;a href="/slides/osday_2025.pdf"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Happy reading!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OSDay Florence - 21 March 2025 - &lt;a href="https://osday.dev/schedule/9688a15e-e9ed-4803-8ac9-114400446bf4"&gt;Why Choose to Use the BSDs in 2025&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;"I'm Stefano Marinelli, &lt;a href="https://it-notes.dragas.net/2024/10/03/i-solve-problems-eurobsdcon/"&gt;I solve problems&lt;/a&gt;."&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I'm the founder and Barista of the &lt;a href="https://bsd.cafe"&gt;BSD Cafe&lt;/a&gt;, a community of *BSD enthusiasts.&lt;/p&gt;
&lt;p&gt;I work in my company, called &lt;a href="https://prodottoinrete.it"&gt;Prodottoinrete&lt;/a&gt; - a container of ideas and solutions.&lt;/p&gt;
&lt;p&gt;I'm passionate about technology and computing, and I've made my passion my profession. Every morning, when I sit in front of the computer, a new world opens up for me to explore.&lt;/p&gt;
&lt;p&gt;I've been a Linux user since 1996, before I turned 17. Back then, I used Fidonet and would read about alternative operating systems. I experimented with Linux distributions from CDs, and by 1997, Linux became my everyday system. It was only in 2002 that I began exploring BSD systems, largely thanks to FreeBSD's fantastic handbook.&lt;/p&gt;
&lt;p&gt;The relationship we had with Open Source 20-30 years ago was fundamentally different than today. Back then, embracing Open Source meant thinking differently. It meant embracing freedom. We chose Linux and the BSDs when Windows and commercial Unix systems dominated the market. Not because they were simple or free (as in free beer), but for freedom from impositions - both technological and ideological.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I solve problems.&lt;/strong&gt; And to solve problems effectively, we need to recognize when the landscape has changed.&lt;/p&gt;
&lt;p&gt;The reality today is that while we won that war - Open Source is everywhere - we're facing a new challenge. The "mainstream" Open Source world is creating monocultures. The focus has shifted from technologies to specific tools. We're seeing innovation for novelty's sake, not problem-solving.&lt;/p&gt;
&lt;p&gt;This shift has profound implications. In a world dominated by cyber threats, where everything is connected and we completely depend on technology, the value of stability has been lost. By stability, I don't just mean that a system doesn't crash. I mean continuity over time, upgradeability, and system visibility.&lt;/p&gt;
&lt;p&gt;Instead, the industry seems obsessed with the hype cycle. "New" is prioritized over secure and stable. The mantra has become:
- "It will be fixed in the next version"
- "We need automatic restarts when it crashes"
- "Do we need software that crashes less? We have systemd and Kubernetes to restart crashed workloads!"
- "We need moooarrr powaaaaaaar!!!!"&lt;/p&gt;
&lt;p&gt;Let me give you a concrete example. A program written in Rust should be memory safe - that's one of the main selling points of the language. But if that program uses unsafe functions and segfaults, what advantage does it offer over a mature C implementation? Stability matters more than the implementation language.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I solve problems.&lt;/strong&gt; And creating a monoculture does not solve problems - it creates new ones.&lt;/p&gt;
&lt;p&gt;Yes, Linux, Docker, and Kubernetes are better than closed source solutions. But when everyone uses the same tools, freedom dies. We use them because "everyone does" rather than because they're the best tool for our specific needs.&lt;/p&gt;
&lt;p&gt;If we had only used what everyone else used, we wouldn't have Linux or the BSDs today. There would be no LibreOffice, no Nextcloud. We'd just have Windows variations and expensive Unix systems. We'd be bound by licenses and vendors, stuck with closed solutions.&lt;/p&gt;
&lt;p&gt;This is where the BSDs offer a compelling alternative: "Be free and evaluate alternatives. Always."&lt;/p&gt;
&lt;p&gt;For those who don't know, the original BSD started in the 1970s (before Linux was conceived). Minix was created as an educational OS because it was believed that BSD, mature and professional, would be the Open Source OS that would dominate the market. A legal case stalled development and scared adopters, but in 1993, NetBSD and FreeBSD emerged. OpenBSD forked from NetBSD later, then DragonflyBSD from FreeBSD.&lt;/p&gt;
&lt;p&gt;As Linus Torvalds said in 1993, "If 386BSD had been available when I started on Linux, Linux would probably never had happened."&lt;/p&gt;
&lt;p&gt;What makes the BSDs special is their philosophy:
- Kernel and userland developed by same teams
- Consistency in tools and updates
- Excellent documentation - especially OpenBSD, where insufficient docs are considered a bug
- Man pages contain virtually everything
- Evolution, not Revolution&lt;/p&gt;
&lt;p&gt;Let me briefly introduce the main BSD variants that I work with daily:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FreeBSD&lt;/strong&gt; is a generalist system. It focuses on stability and performance - with HardenedBSD as a security-enhanced fork. It has native ZFS, Boot Environments, and complete separation between OS and packages. It's had container support via jails since 2000 - which predates Linux cgroups by a decade! It offers bhyve virtualization (more efficient than KVM). OPNsense and pfSense are based on FreeBSD, as pf is a powerful firewall. It's used by Netflix for streaming video delivery and forms the foundation for PlayStation consoles. MacOS and iOS also contain some FreeBSD code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenBSD&lt;/strong&gt; focuses on security and code correctness. Its code is constantly audited and simplified - less is more. The team believes "The more complex the code, the less maintainable." It has security mechanisms like pledge() and unveil(). OpenSSH (and many other nice things) originated and are developed here. Development is driven by team priorities, not user requests. It's ideal for routers, firewalls, and security-critical systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NetBSD&lt;/strong&gt; lives by the motto "Of course it runs NetBSD!" Its focus is on correctness, portability, and proper implementation. It supports 50+ architectures. Development centers on compatibility, which necessitates code quality. It must function on decades-old hardware. It's ideal for systems that require stability without the need for continuous updates, like embedded devices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I solve problems.&lt;/strong&gt; And in my experience, the BSDs have consistently proven to be excellent problem-solvers. Here are some real-world benefits I've experienced:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better stability and security&lt;/li&gt;
&lt;li&gt;Simplified administration - upgrades won't destroy your system&lt;/li&gt;
&lt;li&gt;&lt;a href="https://it-notes.dragas.net/2024/07/04/from-cloud-chaos-to-freebsd-efficiency/"&gt;Less vulnerability to common attacks&lt;/a&gt; - "We don't need this patch, you're running OpenBSD and it's been fixed 20 years ago"&lt;/li&gt;
&lt;li&gt;Network interfaces maintain consistent names - ix0 will remain ix0, not renaming from enx3e3300c9e14e to enp10s0f0np0&lt;/li&gt;
&lt;li&gt;FreeBSD shows lower system load compared to Linux&lt;/li&gt;
&lt;li&gt;FreeBSD handles I/O pressure better - &lt;a href="https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/"&gt;on the same hardware, I've seen 70% time reduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;FreeBSD delivers improved end-user experience/responsiveness&lt;/li&gt;
&lt;li&gt;NetBSD provides the comfort of "Don't worry - your platform will be supported for the foreseeable future"&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So why choose BSD in 2025? I believe there are several compelling reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security in an increasingly hostile environment&lt;/li&gt;
&lt;li&gt;Stability in a world obsessed with novelty&lt;/li&gt;
&lt;li&gt;Performance without unnecessary complexity&lt;/li&gt;
&lt;li&gt;Freedom from the mainstream monoculture&lt;/li&gt;
&lt;li&gt;Systems designed with coherent philosophy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don't be afraid to try BSD systems - despite the Beastie mascot, they don't hurt and you'll appreciate them!&lt;/p&gt;
&lt;p&gt;See you at &lt;a href="https://bsd.cafe"&gt;BSD Cafe&lt;/a&gt;!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Sun, 23 Mar 2025 10:30:00 +0100</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/03/23/osday-2025-why-choose-bsd-in-2025/</guid><category>osday</category><category>freebsd</category><category>netbsd</category><category>openbsd</category><category>zfs</category><category>server</category><category>ownyourdata</category></item><item><title>I Solve Problems</title><link>https://it-notes.dragas.net/2024/10/03/i-solve-problems-eurobsdcon/</link><description>&lt;p&gt;&lt;img src="https://2024.eurobsdcon.org/images/banner-2024.jpg" alt="I Solve Problems"&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Addendum:&lt;/strong&gt; during the event, I was interviewed by &lt;a href="https://soc.feditime.com/users/Tubsta"&gt;Jason Tubnor&lt;/a&gt; for the &lt;a href="https://www.bsdnow.tv/"&gt;BSD Now&lt;/a&gt; Podcast, where I provided further information about the talk and the BSD Cafe project. Here is &lt;a href="https://www.bsdnow.tv/579"&gt;the link to the episode&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is the text underlying my presentation at EuroBSDCon 2024, on 21 September 2024, in Dublin, Ireland and BSDCan 2025, 13 June 2025, Ottawa, Canada.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The slides can be downloaded &lt;a href="https://it-notes.dragas.net/slides/EuroBSDCon2024_Marinelli.pdf"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The BSDCan 2025 video can &lt;a href="https://www.youtube.com/watch?v=UnVp25-6Qao"&gt;be viewed here&lt;/a&gt;. This is more up-to-date than the EuroBSDCon one.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The EuroBSDCon 2024 video, not yet separated from the live stream, can &lt;a href="https://www.youtube.com/watch?t=19285&amp;amp;v=u_bdSqqHm58"&gt;be viewed here&lt;/a&gt; - At first, I was a bit tense, then I relaxed.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Happy reading!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EuroBSDCon Dublin - 21 September 2024 - &lt;a href="https://events.eurobsdcon.org/2024/talk/LNMLZX/"&gt;Why (and how) we're migrating many of our servers from Linux to the BSDs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;"I'm Stefano Marinelli, I solve problems."&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I’m the &lt;a href="https://bsd.cafe"&gt;founder and Barista of the BSD Cafe&lt;/a&gt;, a community of *BSD enthusiasts.&lt;/p&gt;
&lt;p&gt;I work in my company, called Prodottoinrete - a container of ideas and solutions.&lt;/p&gt;
&lt;p&gt;I’m passionate about technology and computing, and I’ve made my passion my profession. Every morning, when I sit in front of the computer, a new world opens up for me to explore, and I try to share this passion with my clients. Sometimes, I succeed.&lt;/p&gt;
&lt;p&gt;I've been a Linux user since 1996, before I turned 17. Back then, I used Fidonet and would read about alternative operating systems. Curiosity got the best of me, and I bought a set of CDs with various Linux distributions at the first opportunity. I tried it, I liked it, but at the time, I didn’t find it advantageous, so I continued using it for secondary tasks while Windows remained my daily driver.&lt;/p&gt;
&lt;p&gt;Things changed in late 1997. I decided to go deeper into Linux and, with the purchase of a new, more powerful computer, I realized that aside from gaming, Linux could be my everyday system. This came in handy when I started university in 1998, where the computer science department was very oriented towards Open Source solutions. I was one of the few students who already understood the concepts of Open Source and knew how to use Linux. I was also one of the few who wasn’t baffled when we found Solaris machines in the lab. After all, there were similarities.&lt;/p&gt;
&lt;p&gt;Over the years, I became one of the administrators of that lab, which was almost entirely Linux-based.&lt;/p&gt;
&lt;p&gt;In 2000, I was fortunate to have &lt;a href="https://en.wikipedia.org/wiki/%C3%96zalp_Babao%C4%9Flu"&gt;Professor Özalp Babaoğlu&lt;/a&gt; as my lecturer, which pushed me to explore other operating systems like the BSDs. However, all I had at the time was an old Compaq laptop (486/25 MHz and 4 MB RAM) and no fast internet connection. So, apart from some theoretical studies, I postponed hands-on experiments until I had better resources. By 2002, thanks to a broadband connection and a new computer, I began exploring BSD systems. I started with FreeBSD, largely thanks to its fantastic handbook. I asked my parents to buy a laser printer so I could "print academic material" - but really, I wanted to print all the documentation I could find, starting from the FreeBSD handbook. And it was incredibly helpful.&lt;/p&gt;
&lt;p&gt;Before long, FreeBSD became my daily driver - entire nights spent compiling KDE while I slept a meter away from my laptop’s wildly spinning fans - but FreeBSD ran much, much better on that machine than Linux did. Unfortunately, OpenBSD was too slow to be usable with any graphical interface.&lt;/p&gt;
&lt;p&gt;In 2003, my final thesis focused on virtualization on Open Source systems, NetBSD/Xen was one of the best and most efficient solutions I tested.&lt;/p&gt;
&lt;p&gt;Shortly after, I found a job at a company that was just beginning to offer Linux-based solutions, mainly for web and mail servers, but I was criticized because I completed tasks that didn’t require constant interventions - this hurt the company’s billing. That’s when I set my future guidelines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I would work for myself, following my own philosophy.&lt;/li&gt;
&lt;li&gt;I would not be tied to any particular vendor. I love exploring and learning, so I would always study solutions in depth and recommend the one I thought best suited for the client.&lt;/li&gt;
&lt;li&gt;I solve problems - I don’t sell boxes.&lt;/li&gt;
&lt;li&gt;I would use and promote Open Source solutions whenever possible.&lt;/li&gt;
&lt;li&gt;I would use a BSD whenever feasible and Linux where a BSD was not suitable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In every technological decision, my priority is solving my clients’ specific problems, not selling a predefined solution. &lt;strong&gt;I solve problems.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I was often told that Open Source systems were “toys for universities” and that the real world ran on something else (mostly meaning Windows). I pressed on. In some cases, I offered to be paid only if the results were achieved, showing how much they’d save compared to traditional licensing costs. It worked, but...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They accepted Linux, albeit reluctantly, but rejected BSDs because they didn’t know them. In some cases, I managed to convince them. In others, sadly, I didn’t.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Result: I decided to use the BSDs where clients didn’t have direct access - like email servers or web hosting - while using Linux where they specifically requested it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NetBSD/Xen as the virtualization base, &lt;a href="https://it-notes.dragas.net/2023/08/27/that-old-netbsd-server-running-since-2010/"&gt;with excellent longevity and reliability&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;OpenBSD as network/firewall entry points.&lt;/li&gt;
&lt;li&gt;FreeBSD (especially with the introduction of ZFS) for various services, including backup servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It worked. What surprised clients most was the stability and the reduced need for maintenance. They saw more uptime and were happy.&lt;/p&gt;
&lt;p&gt;Problem: &lt;strong&gt;"If nothing is working, what am I paying you for? If everything’s working, what am I paying you for?"&lt;/strong&gt; So, I selected clients and situations that understood that if everything works, it’s because of the work behind the scenes. It’s better to pay for everything to work than to pay to fix problems. The problem to solve, in this case, is not stopping the client’s work. &lt;strong&gt;And I solve problems.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I managed about 65% *BSD machines and 35% Linux. But as Linux’s popularity grew, so did client demand. It became necessary on multiple occasions to replace or implement Linux instead of a BSD, for specific requests.&lt;/p&gt;
&lt;p&gt;At a certain point, Linux virtualization solutions matured, and many of my hosts transitioned from NetBSD/Xen to OpenNebula (often with MooseFS) and then to Proxmox (often with Ceph). This happened because my clients needed to manage their VM lifecycles autonomously, change configurations, migrate hosts, etc.&lt;/p&gt;
&lt;p&gt;Proxmox showed excellent reliability and stability. The VMs were often Linux-based (especially if the client needed direct management) or FreeBSD, but in smaller quantities. My own infrastructure, however, remained primarily BSD-based.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Over time, I gradually started to reflect and 'take stock'.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No *BSD has ever caused me to lose data to the point of having to restore from backup. On Linux, I’ve lost data with ext4, XFS, and btrfs. The most catastrophic case was with XFS - just a few files, backed up and restored, but the client was highly demanding and didn’t take it well. The largest failure was with btrfs - after a reboot, a 50 TB filesystem (in mirror, for backups) simply stopped working. No more mounting possible. Data was lost, but I had further backups. The client was informed and understood the situation. Within a few days, the server was rebuilt from scratch on FreeBSD with ZFS - since then, I haven’t lost a single bit.&lt;/p&gt;
&lt;p&gt;In 2018, I started introducing Docker and Podman to the developers with specific needs, especially to help them with their development. Many developers began incessantly asking for Docker, unfortunately some of them only wanted  to bypass many limitations that traditional setups imposed. Unfortunately, in many cases, those "limitations" were just bad practices - running outdated versions of software and libraries, or not wanting to bother with keeping the stack updated. There are similar problems with other solutions, but at least I can block them. They're great for quick deployment and increased security, but they aren’t always the best choice. Plus, they’re not the only option, despite what many people think these days.&lt;/p&gt;
&lt;p&gt;Linux has had major development over the past years, but this has shifted towards specific players’ interests (mainly cloud providers) rather than technical reasons. Maybe not in the kernel, but many Linux distributions and communities now seem focused on the constant push to replace "the old with the new" with solid theoretical reasons but sometimes seemingly without practical benefit.&lt;/p&gt;
&lt;p&gt;For me, computing should solve problems and provide opportunities to those who use it. &lt;strong&gt;I solve problems.&lt;/strong&gt; Every change or variation will solve one problem but create new ones. It’s crucial to be mindful not to create worse problems than the ones you’re solving, and today’s enterprise world often seems to overlook that.&lt;/p&gt;
&lt;p&gt;It’s common to see software distributed solely via Docker Compose files. Sometimes I use it as an installation tutorial, but I realize they’re just specific pieces precariously glued together (patched files, specific dependency versions, or nothing works).&lt;/p&gt;
&lt;p&gt;The trend is to rush, to simplify deployments as much as possible, sweeping structural problems under the rug. The goal is to "innovate", not necessarily improve - just as long as it’s "new" or "how everyone does it, nowadays".&lt;/p&gt;
&lt;p&gt;A massive business has grown around Linux: certifications, training, pentesting, certified platforms - the community is losing decision-making power. This is a far cry from the early days.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I solve problems.&lt;/strong&gt; And these fast-changing technologies risk creating more problems than they solve, at least in certain situations. The workloads I manage often stay up for years, requiring a more stable, upgradable, and consistent approach.&lt;/p&gt;
&lt;p&gt;If a client’s problem is to have an e-commerce site, they don’t really care if it runs on Docker, Podman, a FreeBSD jail, or a Raspberry Pi cluster - as long as their problem is solved. In fact, clients are happy when their solution is stable, upgradable, and secure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There isn’t a single solution to all problems, but many solutions for each problem.&lt;/strong&gt; My job is to give clients the best solution to solve their specific problem, not the most fashionable one.&lt;/p&gt;
&lt;p&gt;That’s why I decided, several years ago, &lt;em&gt;to reverse the proportion and implement and the BSDs for all possible workloads.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Each *BSD has its characteristics and target audience. Sometimes these targets overlap, but it’s generally not difficult to choose the most appropriate solution.&lt;/p&gt;
&lt;p&gt;The goal of the migration was to create stable, coherent, upgradable, and secure systems.&lt;/p&gt;
&lt;p&gt;By implementing an OpenBSD system, I often don’t need to install any additional packages. When it’s time to upgrade, it’s simple and secure. When a vulnerability emerges, I’m often fortunate to read "OpenBSD is excluded from this issue because it eliminated this risk X years ago..."&lt;/p&gt;
&lt;p&gt;By implementing a NetBSD system, I know I’m installing a system that isn’t in a rush to release new versions and will likely run for years with only a few package updates and security patches, when necessary. And it’s quite rare for a patch to be required.&lt;/p&gt;
&lt;p&gt;By implementing a FreeBSD system, I know I’ll have ZFS at my disposal, a fast and efficient hypervisor like bhyve, and a native, mature jail system that will ensure service and setup separation coherently and precisely. Not as “add-ons” but built into the system itself.&lt;/p&gt;
&lt;p&gt;Moving to the BSDs means, in my experience, reaching systems that are more stable, more easily upgradable, and more consistent in their parts. They don’t chase the hype of the moment, much like the early days of Linux. In the case of FreeBSD, this also means moving to native ZFS and boot environments, giving me greater peace of mind when it comes to upgrades.&lt;/p&gt;
&lt;p&gt;The initial strategy was to migrate what would soon need updates anyway, what would be moved (thus requiring a new setup), and what was causing problems and deserved a deeper dive.&lt;/p&gt;
&lt;p&gt;First, I decided to migrate to FreeBSD the hypervisors not directly accessed by clients, especially on leased servers. The approach was to create a twin machine (to have an objective performance and stability comparison - it wouldn’t make sense to compare it to a different machine), install FreeBSD, bridge it with the production server, install vm-bhyve, and start copying VMs from Proxmox, reconfiguring the main parameters in the configuration file. In some cases, I already used ZFS on Proxmox, so the first part of the migration was a simple zfs-send/receive. In other cases (e.g., when using Ceph), I made an intermediate move by live-migrating the storage to ZFS and then proceeding as in the first case. The first noticeable effect was a reduction in resources used by the host to handle VM traffic - as expected, only FreeBSD’s basic processes and bhyve were running - but at the same time, there was a significant increase in I/O performance, further enhanced by switching the virtual disk driver from virtio to NVMe. This allowed for in-depth testing and revealed that FreeBSD suffers less under heavy I/O (the VMs on Linux tended to block their I/O, an effect I didn’t notice on FreeBSD) and showed significantly lower loads. In short, it handled the load better.&lt;/p&gt;
&lt;p&gt;As an experiment, I decided to migrate two hosts (each with about 10 VMs) of a client - where I had full control—without telling them, over a weekend. By Tuesday, they called me, concerned: they had noticed a massive performance boost and were worried I had upgraded their hardware without approval, thinking that, "given the performance boost", it would cost them a lot. After explaining what I had done, they asked me to run further tests and progressively continue migrating everything. 20 hosts, all based on (sometimes slightly older) versions of Proxmox. And so I did, but taking advantage of their open-mindedness, I went a step further.&lt;/p&gt;
&lt;p&gt;Many of their VMs handled simple workloads - PHP websites, or Java-based management systems (running on Tomcat), device monitoring software for industrial machinery, etc. The decision to use VMs had been made by their highly competent internal IT staff to separate environments and dependencies. It was a perfect use case for jails. I decided to try, VM by VM, to replicate the setups inside FreeBSD jails. In some cases, for convenience, I managed to run everything directly in Linux jails (with &lt;a href="https://wiki.freebsd.org/Linuxulator"&gt;Linuxulator&lt;/a&gt;); in others, it was impossible, so I recreated the setups in individual jails. They immediately noticed an effect: faster operations. It didn’t surprise me. We avoided double buffering (VM and OS), so all the saved RAM could be used by ZFS for its cache and by the host to run other services. Some VMs remained as VMs (e.g., Zimbra). By the end of the operation, I had drastically reduced the number of VMs, replaced by jails, and consequently, the number of hosts. From 20 down to 11 - with a significant monthly cost saving.&lt;/p&gt;
&lt;p&gt;The road was now clear, and I progressively continued down this path. One of the most interesting anecdotes: a client told me that they used to start an operation before taking a coffee break, around 15 minutes, to find the task almost done by the time they returned. After the migration, they shared that they launched the process, grabbed their things, and the task was already complete. An estimated reduction from about 18 minutes to 6 minutes on average. I didn’t investigate too much, but I suspect a combination of factors, with the predominant one &lt;a href="https://it-notes.dragas.net/2024/06/10/proxmox-vs-freebsd-which-virtualization-host-performs-better/"&gt;being bhyve’s NVMe driver&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The main challenge I often face is ideological. Some people are used to thinking that the ideal solution is &lt;strong&gt;X&lt;/strong&gt; - and believe that &lt;strong&gt;X&lt;/strong&gt; is the only solution for their problems. Often, &lt;strong&gt;X&lt;/strong&gt; is the hype of the moment (a few years ago, I fought to convince people that VMware wasn’t necessary and that Proxmox would be a great solution; today, Proxmox is on everyone’s lips - but it’s not the only solution). Often, &lt;strong&gt;X&lt;/strong&gt; is a "cloud" cluster with Kubernetes - running WordPress on it. Even for hosting a law firm’s website, which will be updated every five years.&lt;/p&gt;
&lt;p&gt;When I ask, "Okay, but why? Who will manage it? Where will your data really be, and who will safeguard it?", I get blank faces. They hadn’t considered these questions. No one had even mentioned them. "But everyone I spoke to proposed this type of solution...". It’s like at the beginning with Windows, when I proposed *BSD or Linux. Or later with VMware, when I proposed Proxmox. Or now with Kubernetes, when I propose the BSDs. &lt;/p&gt;
&lt;p&gt;But the simplest solutions are the easiest to maintain and manage over time. My experience has taught me that setting something up is often the easiest part. The hardest part is returning to it after 1, 5, 10 years. Keeping it running, updating it, stabilizing it. For many, IT isn’t their business, but a tool to achieve their goals. A Kubernetes cluster is fantastic, but it requires maintenance. Or it’s external - so it’s no longer ours. We’ve lost control of the data. For many, it’s unnecessary to complicate things. And with every additional layer, we’re creating more problems.&lt;/p&gt;
&lt;p&gt;No &lt;em&gt;BSD system has ever surprised me during an update or a simple reboot. I’ve never encountered, for example, a network interface renaming from &lt;/em&gt;enx3e3300c9e14e&lt;em&gt; to &lt;/em&gt;enp10s0f0np0* on Linux, effectively locking me out of a server. ix0 will remain ix0.&lt;/p&gt;
&lt;p&gt;I’ve never had to recompile ZFS on FreeBSD, only to find that the module wouldn’t load, blocking the filesystem from mounting after reboot.&lt;/p&gt;
&lt;p&gt;Many of the developers I work with have embraced the challenge. Most of them are passionate about technology, and learning a new operating method has been very interesting. Almost all of them, after experiments, were positive and, in fact, began explicitly requesting "jails" instead of Docker hosts. They started using &lt;a href="https://bastillebsd.org/"&gt;BastilleBSD&lt;/a&gt; to clone "template" jails and deploy them. They learned to access ZFS automatic snapshots and recover lost files. They learned to manage the resources at their disposal without repeating the usual mantra of "we need mooooar powaaaar!" every time there’s a problem, a slowdown, or a storage overload. They’ve returned to trying to understand what’s happening, rather than just assembling pieces, libraries, and containers without considering the effects.&lt;/p&gt;
&lt;p&gt;Others, however, struggled, but remained positive nonetheless. And that’s okay. &lt;strong&gt;I solve problems&lt;/strong&gt; and can’t force my solutions on everyone.&lt;/p&gt;
&lt;p&gt;In other cases, the challenge wasn’t technical but "commercial". Often, decision-makers have little to no technical knowledge. Linux sells well. "Cloud" sells even better. A "NetBSD-based solution", unfortunately, has less commercial appeal today. So, they want what they can sell, without focusing too much on the advantages of alternative solutions.&lt;/p&gt;
&lt;p&gt;Linux today is subject to many compliance requirements - I’m often asked which version of OpenSSH I’m running - and they complain when the version (the latest from OpenBSD) isn’t considered "secure" because it doesn’t match their procedures (e.g., OpenSSH_9.2p1 Debian-2+deb12u3). They don’t understand when I explain that the "Debian" part refers to the Linux distribution, not a release. Those who prepare these documents are often, sadly, unaware of what they’re asking for. They just have a checklist.&lt;/p&gt;
&lt;p&gt;The transition is ongoing, and as I see opportunities, I’m migrating from Linux to the BSDs whenever possible. Today, I can say that &lt;strong&gt;78% of the hypervisors I manage run on FreeBSD, and 66% of the workloads (VPS, jails, hosts, etc.) are running on one of the BSDs&lt;/strong&gt; - including solutions like OPNsense. None of the clients have experienced major issues. No one has complained about performance or reliability. All feedback has been positive. Many appreciate moving away from IT monocultures, especially when problems arise - following the recent severe SSH vulnerability, many clients contacted me, worried. It was nice to tell some of them that the exposed SSH service was running OpenBSD’s version, and that OpenBSD wasn’t affected as they had developed a secure mechanism back in 2001. They appreciated it. They want more setups based on OpenBSD.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I'm Stefano Marinelli, I solve problems. And I love solving problems using BSD systems.&lt;/strong&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Thu, 03 Oct 2024 08:53:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/10/03/i-solve-problems-eurobsdcon/</guid><category>eurobsdcon</category><category>bsdcan</category><category>freebsd</category><category>netbsd</category><category>openbsd</category><category>zfs</category><category>server</category><category>ownyourdata</category></item><item><title>Make Your Own CDN with OpenBSD Base and Just 2 Packages</title><link>https://it-notes.dragas.net/2024/08/29/make-your-own-cdn-openbsd/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/web_text.webp" alt="Make Your Own CDN with OpenBSD Base and Just 2 Packages"&gt;&lt;/p&gt;&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This article is a "spin-off" from the previous post "&lt;a href="https://it-notes.dragas.net/2024/08/26/building-a-self-hosted-cdn-for-bsd-cafe-media/"&gt;Building a Self-Hosted CDN for BSD Cafe Media&lt;/a&gt;," which I recommend reading, based on FreeBSD. In that article, I showed how I addressed the issue of geo-replication and geo-distribution of BSD Cafe media content. If you prefer a NetBSD-based setup, &lt;a href="https://it-notes.dragas.net/2024/09/03/make-your-own-cdn-netbsd/"&gt;there's an article that describes how to do it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The internet today relies TOO MUCH on just a few big players. When one of them stops working, half the world is impacted because too many services, in my opinion, depend on them. “Too big to fail,” some might say. 
“Single Point of Failure,” I respond."&lt;/p&gt;
&lt;p&gt;The strength of the internet has always been its extreme decentralization, which is now less evident due to this phenomenon.&lt;/p&gt;
&lt;p&gt;In this article, I want to show how easy it is to create a self-hosted CDN using OpenBSD and just two external packages: &lt;a href="https://varnish-cache.org/"&gt;Varnish&lt;/a&gt; and &lt;a href="https://github.com/go-acme/lego"&gt;Lego&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Actually, only one package is truly needed (Varnish), and SSL certificates could be generated using the built-in &lt;a href="https://man.openbsd.org/acme-client.1"&gt;acme-client&lt;/a&gt; in OpenBSD. However, this might be limiting since acme-client handles certificate generation via traditional methods (using a file in &lt;code&gt;.well-known&lt;/code&gt;), but when dealing with a CDN and several reverse proxies listening, you don’t have perfect control over which one will receive the certificate generation validation request.&lt;/p&gt;
&lt;p&gt;The choice of Varnish is based on several factors, with the main ones being the ability to keep the cache in RAM (which means it can run on read-only systems) and the ability to flush the cache remotely. For example, with each change to my blog, I can choose whether to perform an immediate flush (such as for a new article or an error) or wait for the cache's "natural" expiration (such as for a typo or minor, non-critical changes).&lt;/p&gt;
&lt;p&gt;For convenience and practicality, I’ll use the excellent Lego tool—a Go application that supports many DNS authentication methods, including PowerDNS.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;The steps are quite simple. After installing and updating OpenBSD (using the &lt;a href="https://man.openbsd.org/syspatch"&gt;syspatch&lt;/a&gt; command), start by installing the two packages:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;obcdn# pkg_add lego varnish
quirks-7.14:updatedb-0p0: ok
quirks-7.14 signed on 2024-08-24T13:35:23Z
quirks-7.14: ok
lego-4.16.1: ok
varnish-7.4.2:bzip2-1.0.8p0: ok
varnish-7.4.2:pcre2-10.37p2: ok
useradd: Warning: home directory `/var/varnish' doesn't exist, and -m was not specified
varnish-7.4.2: ok
The following new rcscripts were installed: /etc/rc.d/varnishd
See rcctl(8) for details.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The next step is to enable Varnish:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;rcctl enable varnishd
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Varnish has a generic startup script, but it's best to customize the startup options. To do this, modify the &lt;code&gt;/etc/rc.conf.local&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;varnishd_flags=&amp;quot;-j unix,user=_varnish,ccgroup=_varnish -f /etc/varnish/default.vcl -T localhost:9999 -a localhost:8080 -s default,500m&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This configuration sets Varnish with a 500 MB cache and listens on localhost, port 8080.&lt;/p&gt;
&lt;p&gt;Next, rename the default VCL file to prepare for your own content:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;mv /etc/varnish/default.vcl /etc/varnish/default.vcl.distrib
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a new &lt;code&gt;default.vcl&lt;/code&gt; file. Below is an example based on this blog (at the time of writing). You’ll need to adapt it according to your needs, especially if there are cookies or other dynamic content. Note that Varnish will fetch data from a specific backend accessed in http. If privacy is needed, consider creating a VPN between the backend and Varnish, &lt;a href="https://it-notes.dragas.net/2024/08/26/building-a-self-hosted-cdn-for-bsd-cafe-media/"&gt;as briefly mentioned in the previous article&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-vcl"&gt;vcl 4.1;
import std;

# Backend - it-notes.dragas.net
backend it_notes {
    .host = &amp;quot;myOriginalServer&amp;quot;;
    .port = &amp;quot;80&amp;quot;;
}

# ACL - purge - it-notes.dragas.net
acl purge_it_notes {
    &amp;quot;authorizedIPForCachePurge&amp;quot;;
}

sub vcl_recv {
    # it-notes.dragas.net
    if (req.http.Host == &amp;quot;it-notes.dragas.net&amp;quot;) {
        set req.backend_hint = it_notes;
        set req.http.Host = &amp;quot;it-notes.dragas.net&amp;quot;;

        # PURGE - it-notes.dragas.net
        if (req.method == &amp;quot;PURGE&amp;quot;) {
            std.log(&amp;quot;Purge request received for &amp;quot; + req.url);

            if (!std.ip(req.http.X-Forwarded-For, &amp;quot;0.0.0.0&amp;quot;) ~ purge_it_notes) {
                return (synth(405, &amp;quot;Not allowed.&amp;quot;));
            }

            if (req.url == &amp;quot;/&amp;quot; || req.url == &amp;quot;/*&amp;quot;) {
                ban(&amp;quot;req.http.host == &amp;quot; + req.http.host);
                return(synth(200, &amp;quot;Entire cache has been cleared.&amp;quot;));
            }
            return (purge);
        }

    } else {
        # Other domains - 404
        return (synth(404, &amp;quot;Domain not found&amp;quot;));
    }

    if (req.method != &amp;quot;GET&amp;quot; &amp;amp;&amp;amp; req.method != &amp;quot;HEAD&amp;quot;) {
        return (pipe);
    }

    return (hash);
}

sub vcl_backend_response {
    # TTL - it-notes.dragas.net
    if (bereq.http.host == &amp;quot;it-notes.dragas.net&amp;quot;) {
        if (bereq.url ~ &amp;quot;\.(gif|jpg|jpeg|png|webp|ico|css|js)$&amp;quot;) {
            set beresp.ttl = 1w;
            set beresp.grace = 1d;
            set beresp.keep = 7d;
            unset beresp.http.Set-Cookie;
            unset beresp.http.Cache-Control;
            set beresp.http.Cache-Control = &amp;quot;public, max-age=604800&amp;quot;;
        } else {
            set beresp.ttl = 15m;
            set beresp.grace = 48h;
            set beresp.keep = 7d;
        }
    }

    # Remove some headers
    unset beresp.http.Server;
    unset beresp.http.X-Powered-By;
    unset beresp.http.Via;

    return (deliver);
}

sub vcl_deliver {
    # Add X-Cache header
    if (obj.hits &amp;gt; 0) {
        set resp.http.X-Cache = &amp;quot;HIT&amp;quot;;
    } else {
        set resp.http.X-Cache = &amp;quot;MISS&amp;quot;;
    }

    std.log(&amp;quot;Delivering content for &amp;quot; + req.url + &amp;quot; - Cache: &amp;quot; + resp.http.X-Cache);

    # Remove Varnish headers
    unset resp.http.Via;
    unset resp.http.X-Varnish;

    return (deliver);
}

sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    return (lookup);
}

sub vcl_hit {
    return (deliver);
}

sub vcl_miss {
    return (fetch);
}

sub vcl_purge {
    std.log(&amp;quot;Purge executed for &amp;quot; + req.url);
    return (synth(200, &amp;quot;Purge successful&amp;quot;));
}

sub vcl_synth {
    set resp.http.Content-Type = &amp;quot;text/html; charset=utf-8&amp;quot;;
    set resp.http.Retry-After = &amp;quot;5&amp;quot;;
    synthetic({&amp;quot;&amp;lt;!DOCTYPE html&amp;gt;
        &amp;lt;html&amp;gt;
            &amp;lt;head&amp;gt;
                &amp;lt;title&amp;gt;&amp;quot;} + resp.status + &amp;quot; &amp;quot; + resp.reason + {&amp;quot;&amp;lt;/title&amp;gt;
            &amp;lt;/head&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;h1&amp;gt;Status &amp;quot;} + resp.status + &amp;quot; &amp;quot; + resp.reason + {&amp;quot;&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;&amp;quot;} + resp.reason + {&amp;quot;&amp;lt;/p&amp;gt;
                &amp;lt;h3&amp;gt;Guru Meditation:&amp;lt;/h3&amp;gt;
                &amp;lt;p&amp;gt;XID: &amp;quot;} + req.xid + {&amp;quot;&amp;lt;/p&amp;gt;
                &amp;lt;hr&amp;gt;
                &amp;lt;p&amp;gt;Varnish cache server&amp;lt;/p&amp;gt;
            &amp;lt;/body&amp;gt;
        &amp;lt;/html&amp;gt;
    &amp;quot;});
    return (deliver);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start Varnish and check if it starts correctly:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;rcctl start varnishd
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Generating SSL Certificates&lt;/h2&gt;
&lt;p&gt;Before configuring &lt;a href="https://man.openbsd.org/relayd.conf.5"&gt;relayd&lt;/a&gt;, you’ll need to generate SSL certificates. Lego supports many DNS providers and provides clear and comprehensive examples, so I suggest reading its &lt;a href="https://github.com/go-acme/lego?tab=readme-ov-file"&gt;README file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Certificates generated by Lego are not directly compatible with relayd, so you must generate them in the correct format. Add the &lt;code&gt;-k rsa4096&lt;/code&gt; flag to the Lego command to obtain certificates compatible with relayd.&lt;/p&gt;
&lt;p&gt;Once generated, the certificates will be in a subdirectory of the directory from which the command was launched. For example, if the command is run as root (which is unnecessary, but just for the example), the certificates will be in &lt;code&gt;/root/.lego/certificates/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;relayd expects certificates in a specific location. Copy them to the appropriate directories. In my example:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;obcdn# cp /root/.lego/certificates/it-notes.dragas.net.crt /etc/ssl/
obcdn# cp /root/.lego/certificates/it-notes.dragas.net.key /etc/ssl/private/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remember to copy the files to the correct directories when renewing. You can also create symbolic links, this will make your life easier but it’s less secure.&lt;/p&gt;
&lt;h2&gt;Configuring relayd&lt;/h2&gt;
&lt;p&gt;It’s time to configure relayd. The file is &lt;code&gt;/etc/relayd.conf&lt;/code&gt;, and here’s an example configuration:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;log state changes
prefork 10

table &amp;lt;itnotes&amp;gt; { 127.0.0.1 }

http protocol &amp;quot;http&amp;quot; {
    match request header append &amp;quot;X-Forwarded-For&amp;quot; value &amp;quot;$REMOTE_ADDR&amp;quot;
    match request header append &amp;quot;X-Forwarded-By&amp;quot; value &amp;quot;$SERVER_ADDR:$SERVER_PORT&amp;quot;

    match request path &amp;quot;/*.atom&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.css&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.gif&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.html&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.ico&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.jpg&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.webp&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.js&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.png&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.rss&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.svg&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.xml&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.ttf&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.woff2&amp;quot; tag &amp;quot;CACHE&amp;quot;

    match response tagged &amp;quot;CACHE&amp;quot; header set &amp;quot;Cache-Control&amp;quot; value &amp;quot;public, max-age=604800&amp;quot;

    pass request header &amp;quot;Host&amp;quot; value &amp;quot;it-notes.dragas.net&amp;quot; forward to &amp;lt;itnotes&amp;gt;
}

http protocol &amp;quot;https&amp;quot; {
    match request header append &amp;quot;X-Forwarded-For&amp;quot; value &amp;quot;$REMOTE_ADDR&amp;quot;
    match request header append &amp;quot;X-Forwarded-By&amp;quot; value &amp;quot;$SERVER_ADDR:$SERVER_PORT&amp;quot;

    match response header set &amp;quot;Referrer-Policy&amp;quot; value &amp;quot;no-referrer&amp;quot;
    match response header set &amp;quot;X-Content-Type-Options&amp;quot; value &amp;quot;nosniff&amp;quot;
    match response header set &amp;quot;X-Download-Options&amp;quot; value &amp;quot;noopen&amp;quot;
    match response header set &amp;quot;X-Frame-Options&amp;quot; value &amp;quot;SAMEORIGIN&amp;quot;
    match response header set &amp;quot;X-Permitted-Cross-Domain-Policies&amp;quot; value &amp;quot;none&amp;quot;
    match response header set &amp;quot;X-XSS-Protection&amp;quot; value &amp;quot;1; mode=block&amp;quot;
    match response header set &amp;quot;Strict-Transport-Security&amp;quot; value &amp;quot;max-age=15552000; includeSubDomains; preload&amp;quot;

    match request path &amp;quot;/*.atom&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.css&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.gif&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.html&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.ico&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.jpg&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.webp&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.js&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.png&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.rss&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.svg&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.xml&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.ttf&amp;quot; tag &amp;quot;CACHE&amp;quot;
    match request path &amp;quot;/*.woff2&amp;quot; tag &amp;quot;CACHE&amp;quot;

    match response tagged &amp;quot;CACHE&amp;quot; header set &amp;quot;Cache-Control&amp;quot; value &amp;quot;public, max-age=604800&amp;quot;
    tcp { nodelay, sack, socket buffer 65536, backlog 100 }

    tls { keypair &amp;quot;it-notes.dragas.net&amp;quot; }

    pass request header &amp;quot;Host&amp;quot; value &amp;quot;it-notes.dragas.net&amp;quot; forward to &amp;lt;itnotes&amp;gt;
}

relay &amp;quot;http&amp;quot; {
    listen on vio0 port 80
    protocol &amp;quot;http&amp;quot;

    forward to &amp;lt;itnotes&amp;gt; port 8080
}

relay &amp;quot;https&amp;quot; {
    listen on vio0 port 443 tls
    protocol &amp;quot;https&amp;quot;

    forward to &amp;lt;itnotes&amp;gt; port 8080
}

relay &amp;quot;https6&amp;quot; {
    listen on my:ip:v6:address::1 port 443 tls
    protocol &amp;quot;https&amp;quot;

    forward to &amp;lt;itnotes&amp;gt; port 8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The content of the file is quite self-explanatory. Note that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vio0&lt;/code&gt; is the interface name—it should be modified based on the interface where relayd needs to listen.&lt;/li&gt;
&lt;li&gt;I’ve configured relayd to listen on port 80 as well.&lt;/li&gt;
&lt;li&gt;IPv4 and IPv6 listeners are separated. If IPv6 is not configured, simply comment out that part. Please, if you can, use IPv6. In a fairer world, everyone would have the right to at least one class of public addresses without having to pay exorbitant fees.&lt;/li&gt;
&lt;li&gt;The "keypair" must correspond to the certificate and key names in &lt;code&gt;/etc/ssl&lt;/code&gt; and &lt;code&gt;/etc/ssl/private&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Test the configuration, enable, and start relayd:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;obcdn# relayd -n
configuration OK
obcdn# rcctl enable relayd
obcdn# rcctl start relayd
relayd(ok)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Final Checks&lt;/h2&gt;
&lt;p&gt;The stack is ready. A &lt;code&gt;ps&lt;/code&gt; command will show the process status:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;obcdn# ps aux
USER       PID %CPU %MEM   VSZ   RSS TT  STAT   STARTED       TIME COMMAND
root         1  0.0  0.0   920   276 ??  I       7:10PM    0:00.01 /sbin/init
[...]
_varnish 44999  0.0  0.2  2256  2424 ??  S       8:27PM    0:00.05 varnishd: Varnish-Mgt -i obcdn.my.domain (varnishd)
_varnish 54481  0.0  8.8 34500 88876 ??  S       8:27PM    0:00.60 varnishd: Varnish-Child -i obcdn.my.domain (varnishd)
root     57753  0.0  0.5  4080  4820 ??  IU      8:32PM    0:00.03 /usr/sbin/relayd
_relayd  95940  0.0  0.4  2152  3892 ??  Spc     8:32PM    0:00.01 relayd: pfe (relayd)
_relayd  81032  0.0  0.4  2156  3716 ??  Spc     8:32PM    0:00.01 relayd: hce (relayd)
_relayd  80312  0.0  0.5  2748  5280 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  88919  0.0  0.5  2748  5268 ??  Ipc     8:32PM    0:00.04 relayd: relay (relayd)
_relayd  90186  0.0  0.5  2752  5272 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  32851  0.0  0.5  2736  5284 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  20270  0.0  0.5  2744  5252 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  98826  0.0  0.5  2752  5264 ??  Ipc     8:32PM    0:00.04 relayd: relay (relayd)
_relayd   6454  0.0  0.5  2744  5264 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  90102  0.0  0.5  2740  5276 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  60314  0.0  0.5  2748  5336 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  27246  0.0  0.5  2744  5284 ??  Ipc     8:32PM    0:00.03 relayd: relay (relayd)
_relayd  87082  0.0  0.4  2100  4508 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  53308  0.0  0.4  2096  4496 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  11697  0.0  0.4  2092  4492 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  83636  0.0  0.4  2092  4500 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  74563  0.0  0.4  2096  4484 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  35910  0.0  0.4  2100  4508 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  24911  0.0  0.4  2096  4504 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  78649  0.0  0.4  2096  4496 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  89586  0.0  0.4  2096  4500 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
_relayd  11989  0.0  0.4  2100  4500 ??  Ipc     8:32PM    0:00.02 relayd: ca (relayd)
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, both relayd and Varnish are running correctly.&lt;/p&gt;
&lt;h2&gt;Automating Certificate Renewal&lt;/h2&gt;
&lt;p&gt;As a final step, remember to create a script to renew the certificates, copy them to &lt;code&gt;/etc/ssl&lt;/code&gt; and &lt;code&gt;/etc/ssl/private&lt;/code&gt;, and restart relayd.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations, you now have your own free CDN, with your data, fully under your control. Portable, extendable, controllable, and outside of the big providers' grip.&lt;/p&gt;
&lt;p&gt;If your goal is geo-replication, you should use one of the available methods. Some DNS providers allow selection based on the caller's location (like Bunny.net), or, as I prefer, install your own DNS and use tools to manage operations and resolutions, &lt;a href="https://it-notes.dragas.net/2024/08/26/building-a-self-hosted-cdn-for-bsd-cafe-media/"&gt;as briefly described in the previous article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With multiple separate reverse proxies, separate DNS servers (on different providers and possibly different countries or continents) capable of checking if the reverse proxies are operational, you can achieve an extremely low likelihood of encountering a Single Point of Failure, as all components, once the cache is filled, will be nearly autonomous even in the event of a (temporary) backend outage - i.e., the original node.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Thu, 29 Aug 2024 01:41:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/08/29/make-your-own-cdn-openbsd/</guid><category>openbsd</category><category>server</category><category>hosting</category><category>tutorial</category><category>ownyourdata</category><category>vpn</category><category>ha</category><category>wireguard</category><category>web</category><category>cdn</category><category>bsdcafe</category><category>varnish</category><category>series</category></item><item><title>Make your own VPN - OpenBSD, Wireguard, ipv6 and ad-blocking included</title><link>https://it-notes.dragas.net/2023/04/03/make-your-own-vpn-wireguard-ipv6-and-ad-blocking-included/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/lock_iphone.webp" alt="Make your own VPN - OpenBSD, Wireguard, ipv6 and ad-blocking included"&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Note: This article assumes a setup based on OpenBSD. If you prefer a version based on FreeBSD, &lt;a href="https://it-notes.dragas.net/2023/09/23/make-your-own-vpn-freebsd-wireguard-ipv6-and-ad-blocking-included/"&gt;it is available here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;VPNs are a fundamental tool for securely connecting to your own servers and devices. Many people use commercial VPNs for various reasons, ranging from not trusting their provider (especially when connecting from a public hotspot) to wanting to "go out" on the Internet with a different IP address, perhaps from another country.&lt;/p&gt;
&lt;p&gt;Whatever the reason, solutions are not lacking. I have always set up management VPNs to allow servers and/or clients to communicate with each other using secure channels. Lately, &lt;a href="https://my-notes.dragas.net/posts/2023/the-urgency-of-transitioning-to-ipv6/"&gt;I have been activating IPv6 connectivity on all my devices&lt;/a&gt; (both desktop/servers and mobile devices) and I needed to quickly create a node that concentrated some networks and allowed them to go out on the network in IPv6. The tools I used and will describe are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VPS - in this case, I used a basic &lt;a href="https://hetzner.cloud/?ref=Wh0bprLCIE7w"&gt;Hetzner Cloud&lt;/a&gt; VPS (using this link, you will receive 20 euros of cloud credits), but any provider that provides IPv6 connectivity will do - if you want IPv6, of course.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.openbsd.org"&gt;OpenBSD&lt;/a&gt; - a clean, stable, and secure operating system.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wireguard.com"&gt;Wireguard&lt;/a&gt; - lightweight, secure, and at the same time, not very "chatty", so it is also gentle on mobile device batteries. When there is no traffic, it simply does not transmit/receive anything. Well supported by all major desktop and server operating systems as well as Android and iOS devices.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nlnetlabs.nl/projects/unbound/about/"&gt;Unbound&lt;/a&gt; - can make DNS queries directly to root servers, not through forwarders. It also allows you to insert block-lists and have a result similar to that of Pi-Hole (i.e., ad-blocking).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.spamhaus.org"&gt;SpamHaus&lt;/a&gt; lists - to immediately stop connections to and from users on blacklists.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first step is to activate a VPS and install OpenBSD. On the Hetzner cloud console, there won't be a pre-built OpenBSD image, but only a selection of Linux distributions. Don't worry, just choose any of them and create the VPS. Once done, the OpenBSD ISO image will be available among the "ISO Images". Just insert the virtual CD, restart the VPS, and the OpenBSD installation will appear in the console.&lt;/p&gt;
&lt;p&gt;I won't go into detail, the operation is simple and straightforward. The only precaution (in the case of a Hetzner Cloud VPS) is &lt;em&gt;to use "autoconf" for IPv4 but, for now, do not configure IPv6&lt;/em&gt;. It will be configured later.&lt;/p&gt;
&lt;p&gt;Install all OpenBSD updates (using the &lt;em&gt;syspatch&lt;/em&gt; command) and restart, the kernel will be relinked.&lt;/p&gt;
&lt;p&gt;Wireguard, on OpenBSD, is fully integrated into the base system and does not require the installation of external packages. This is a big advantage because over time, support for everything related to Wireguard will be managed directly by the main OpenBSD development team.&lt;/p&gt;
&lt;p&gt;The first step is to configure IPv6 on the VPS. In the case of Hetzner, unfortunately, they only provide a /64, so it will be necessary to segment the assigned network. In this example, it will be divided into /72 subnetworks - to find valid subclasses, it will be possible to use &lt;a href="https://subnettingpractice.com/ipv6-subnet-calculator.html"&gt;a calculator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The /etc/hostname.vio0 file should look something like this:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;inet autoconf
inet6 2001:db8:cafe:cafe::1 72 
!route add -net ::/0 fe80::1%vio0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In short, keep the base address assigned by Hetzner, but change the netmask to /72 - thus giving the possibility of having other networks available.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;sh /etc/netstart vio0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will reconfigure the network interface and allow IPv6 to start working. To test it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;ping6 google.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything has been configured correctly, the ping will be executed and google.com will reply.&lt;/p&gt;
&lt;p&gt;It is now necessary to enable forwarding for IPv4 and IPv6. Enter these lines in the /etc/sysctl.conf file:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To apply those changes you can reboot or just type:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;sysctl net.inet.ip.forwarding=1
sysctl net.inet6.ip6.forwarding=1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To configure Wireguard, a few steps will be necessary. First of all, the private key will need to be created:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;openssl rand -base64 32
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Something like this will come out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;YUkS6cNTyPbXmtVf/23ppVW3gX2hZIBzlHtXNFRp80w=&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now create a new file called /etc/hostname.wg0:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;172.16.0.1/24 wgport 51820 wgkey YUkS6cNTyPbXmtVf/23ppVW3gX2hZIBzlHtXNFRp80w=
inet6 2001:db8:cafe:cafe:100::1 72
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A new Wireguard interface called wg0 is being created. It will have the IPv4 address "172.16.0.1", Wireguard will listen on port 51820, and with the private key created shortly before. It will also have an IPv6 address on one of the subclasses that the provider will have provided.&lt;/p&gt;
&lt;p&gt;Save and activate the interface:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;sh /etc/netstart wg0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything has been entered correctly, it should enable the interface. Now:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;ifconfig wg0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And something like this will be returned:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;wg0: flags=80c3&amp;lt;UP,BROADCAST,RUNNING,NOARP,MULTICAST&amp;gt; mtu 1420
    index 5 priority 0 llprio 3
    wgport 51820
    wgpubkey xxxxxxxxxxxxxxx=
    groups: wg
    inet 172.16.0.1 netmask 0xffffff00 broadcast 172.16.0.255
    inet6 2001:db8:cafe:cafe:100::1 prefixlen 72
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Take note of the &lt;em&gt;wgpubkey&lt;/em&gt; - it will be needed to configure the clients.&lt;/p&gt;
&lt;p&gt;As for the firewall, OpenBSD comes with a basic &lt;em&gt;pf&lt;/em&gt; configuration. In my setups, I tend to block what is not needed and be permissive with what may be useful. However, I like to keep out the "bad guys," so I use blacklists. pf allows elements to be inserted and removed from tables in runtime, so the firewall can be configured accordingly.&lt;/p&gt;
&lt;p&gt;To download and apply Spamhaus lists, I use a simple but effective script &lt;a href="https://daemonforums.org/showthread.php?t=11420"&gt;found on the Internet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So create the script in /usr/local/sbin/spamhaus.sh:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;#!/bin/sh
#
# this is normally run once per day via /etc/daily.local.
#
echo updating Spamhaus DROP lists:
(
  { ftp -o - https://www.spamhaus.org/drop/drop.txt &amp;amp;&amp;amp; \
    ftp -o - https://www.spamhaus.org/drop/dropv6.txt ; \
  } 2&amp;gt;/dev/null | sed &amp;quot;s/;/#/&amp;quot; &amp;gt; /var/db/drop.txt
)
pfctl -t spamhaus -T replace -f /var/db/drop.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Make it executable and run it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;chmod a+rx /usr/local/sbin/spamhaus.sh
/usr/local/sbin/spamhaus.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are many possibilities to configure pf. A fairly simple example could be this:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;ext_if=&amp;quot;vio0&amp;quot;
wg0_if = &amp;quot;wg0&amp;quot;
wg0_networks = &amp;quot;172.16.0.0/24&amp;quot;

set skip on lo

# Spamhaus DROP list:
table &amp;lt;spamhaus&amp;gt; persist file &amp;quot;/var/db/drop.txt&amp;quot;

block drop log quick from &amp;lt;spamhaus&amp;gt;

match in all scrub (no-df random-id max-mss 1440)

match out on $ext_if from { $wg0_networks } nat-to ($ext_if)

#Pass ICMP on ipv6
pass quick proto ipv6-icmp
#Block from ipv6 to wg0 network
block in quick on $ext_if inet6 to { 2001:db8:cafe:cafe:100::/72 }
#Pass Wireguard traffic - in and out
pass quick on $wg0_if

# default deny
block in
block out

# By default, do not permit remote connections to X11
block return in on ! lo0 proto tcp to port 6000:6010

# Port build user does not need network
block return out log proto {tcp udp} user _pbuild

pass in on $ext_if proto tcp to port ssh
pass in on $ext_if proto udp to port 51820

pass out on $ext_if
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a very simple configuration: it blocks everything that is present in the list downloaded from Spamhaus, allows NAT from the Wireguard network to the public interface, allows icmp traffic in IPv6 (necessary for the network to function properly) while blocking incoming traffic to the Wireguard IPv6 LAN (remember that the IPs will be public and directly reachable, so we don't want to expose our devices by default). All traffic on the Wireguard interface will be allowed to pass. Then everything will be blocked and exceptions will be specified, i.e. allowing ssh and Wireguard connections (of course). Authorization will also be granted to allow traffic to exit from the public network interface.&lt;/p&gt;
&lt;p&gt;Reload pf configuration:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;pfctl -f /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything went correctly, the firewall should have loaded the new options.&lt;/p&gt;
&lt;p&gt;To obtain caching of DNS queries and the related ad-block, it is now time to configure Unbound. A while ago, I found a script which I slightly adapted. I don't remember where I got it, so I'll paste it here without citing the original creator.&lt;/p&gt;
&lt;p&gt;Create a script to update the unbound ad-block, in /usr/local/sbin/unbound-adhosts.sh:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;#!/bin/ksh
#
# Using blacklist from pi-hole project https://github.com/pi-hole/
# to enable AD blocking in unbound(8)
#
PATH=&amp;quot;/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin&amp;quot;

# Available blocklists - comment line to disable blocklist
_disconad=&amp;quot;https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt&amp;quot;
_discontrack=&amp;quot;https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt&amp;quot;
_stevenblack=&amp;quot;https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts&amp;quot;

# Global variables
_tmpfile=&amp;quot;$(mktemp)&amp;quot; &amp;amp;&amp;amp; echo '' &amp;gt; $_tmpfile
_unboundconf=&amp;quot;/var/unbound/etc/unbound-adhosts.conf&amp;quot;

# Remove comments from blocklist
function simpleParse {
  ftp -VMo - $1 | \
  sed -e 's/#.*$//' -e '/^[[:space:]]*$/d' &amp;gt;&amp;gt; $2
}

# Parse MalwareDom
#[[ -n ${_malwaredom+x} ]] &amp;amp;&amp;amp; simpleParse $_malwaredom $_tmpfile

# Parse ZeusTracker
#[[ -n ${_zeustracker+x} ]] &amp;amp;&amp;amp; simpleParse $_zeustracker $_tmpfile

# Parse DisconTrack
[[ -n ${_discontrack+x} ]] &amp;amp;&amp;amp; simpleParse $_discontrack $_tmpfile

# Parse DisconAD
[[ -n ${_disconad+x} ]] &amp;amp;&amp;amp;  simpleParse $_disconad $_tmpfile

# Parse StevenBlack
[[ -n ${_stevenblack+x} ]] &amp;amp;&amp;amp; \
  ftp -VMo - $_stevenblack | \
  sed -n '/Start/,$p' | \
  sed -e 's/#.*$//' -e '/^[[:space:]]*$/d' | \
  awk '/^0.0.0.0/ { print $2 }' &amp;gt;&amp;gt; $_tmpfile

# Parse hpHosts
[[ -n ${_hostfiles+x} ]] &amp;amp;&amp;amp; \
  ftp -VMo - $_hostfiles | \
  sed -n '/START/,$p' | tr -d '^M$' | \
  sed -e 's/#.*$//' -e '/^[[:space:]]*$/d' -e 's/^M$//' | \
  awk '/^127.0.0.1/ { print $2 }' &amp;gt;&amp;gt; $_tmpfile

# Create unbound(8) local zone file
sort -fu $_tmpfile | grep -v &amp;quot;^[[:space:]]*$&amp;quot; | \
awk '{
  print &amp;quot;local-zone: \&amp;quot;&amp;quot; $1 &amp;quot;\&amp;quot; redirect&amp;quot;
  print &amp;quot;local-data: \&amp;quot;&amp;quot; $1 &amp;quot; A 0.0.0.0\&amp;quot;&amp;quot;
}' &amp;gt; $_unboundconf &amp;amp;&amp;amp; rm -f $_tmpfile

/usr/sbin/rcctl reload unbound 1&amp;gt;/dev/null

exit 0
#EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Similarly, make the script executable and run it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;chmod a+rx /usr/local/sbin/unbound-adhosts.sh
/usr/local/sbin/unbound-adhosts.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, the Unbound configuration file in /var/unbound/etc/unbound.conf can be modified as follows:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;# $OpenBSD: unbound.conf,v 1.21 2020/10/28 11:35:58 sthen Exp $

server:
        verbosity: 1
        log-queries: no
        num-threads: 4
        num-queries-per-thread: 1024
        interface: 127.0.0.1
        #interface: 127.0.0.1@5353      # listen on alternative port
        interface: 172.16.0.1
    interface: 2001:db8:cafe:cafe:100::1
        interface: ::1
        outgoing-range: 64
        chroot: &amp;quot;&amp;quot;
        #do-ip6: yes

        # override the default &amp;quot;any&amp;quot; address to send queries; if multiple
        # addresses are available, they are used randomly to counter spoofing
        #outgoing-interface: 192.0.2.1
        #outgoing-interface: 2001:db8::53

        access-control: 0.0.0.0/0 refuse
        access-control: 127.0.0.0/8 allow
        access-control: ::0/0 refuse
        access-control: ::1 allow
        access-control: 172.16.0.0/24 allow
        access-control: 2001:db8:cafe:cafe:100::/72 allow

        hide-identity: yes
        hide-version: yes

        # Perform DNSSEC validation.
        #
        auto-trust-anchor-file: &amp;quot;/var/unbound/db/root.key&amp;quot;
        val-log-level: 2

        # Synthesize NXDOMAINs from DNSSEC NSEC chains.
        # https://tools.ietf.org/html/rfc8198
        #
        aggressive-nsec: yes
        prefetch: yes
        username: &amp;quot;nobody&amp;quot;
        directory: &amp;quot;/var/unbound/etc&amp;quot;
        logfile: &amp;quot;/var/unbound/unbound.log&amp;quot;
        use-syslog: no
        pidfile: &amp;quot;/var/unbound/unbound.pid&amp;quot;
        include: /var/unbound/etc/unbound-adhosts.conf

remote-control:
        control-enable: yes
        control-interface: /var/run/unbound.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Before launching unbound, it is necessary to give the appropriate permissions:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;chown -R nobody:nobody /var/unbound
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now it is possible to enable and start unbound. Since it needs to load the (long) blocklist, it will take a few seconds:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;rcctl enable unbound
rcctl start unbound
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything has been done correctly, unbound will be able to respond to requests made on 172.16.0.1 and 2001:db8:cafe:cafe:100::1, from their respective LANs.&lt;/p&gt;
&lt;p&gt;Now it is possible to configure the Wireguard client. Each implementation has its own procedure (Android, iOS, MikroTik, Linux, etc.) but essentially it is sufficient to create the right configuration both on the server and on the client. For example, the server's public key (visible by typing "&lt;em&gt;ifconfig wg0&lt;/em&gt;" on the OpenBSD server) should be inserted into the "peer" that will be created on the client, while the client's public key will be used on the server in this way:&lt;/p&gt;
&lt;p&gt;Reopen the file /etc/hostname.wg0 and add:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;172.16.0.1/24 wgport 51820 wgkey YUkS6cNTyPbXmtVf/23ppVW3gX2hZIBzlHtXNFRp80w=
inet6 2001:db8:cafe:cafe:100::1 72
wgpeer *client's public key* wgaip 172.16.0.2/32 wgaip 2001:db8:cafe:cafe:100::2/128
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Reload the configuration:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-sh"&gt;sh /etc/netstart wg0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On the client, create a new configuration by inserting "172.16.0.2/32, 2001:db8:cafe:cafe:100::2/128" (the ones that were entered in the peer configuration in the hostname.wg0 file) in the local IP addresses. Set the DNS server address to "172.16.0.1" and/or its corresponding IPv6 address (in the example, 2001:db8:cafe:cafe:100::1 - yours will be different). In the peer, insert the server's data, including its public key, IP address:port (in the example, the port is 51820), and allowed addresses (setting "0.0.0.0/0, ::0/0" means "all connections will be sent via Wireguard" - all the traffic will pass through the VPN for both IPv4 and IPv6).&lt;/p&gt;
&lt;p&gt;It is also possible to use the VPN only as an ad-blocker, by only routing DNS traffic through it. To achieve this result, it is sufficient to configure the client so that the only allowed address is the one of the just-configured unbound (in this example, 172.16.0.1 or 2001:db8:cafe:cafe:100::1) - DNS resolution will occur via VPN, but browsing will continue to work through the main provider.&lt;/p&gt;
&lt;p&gt;If you want the spamhaus and ad-block lists to be updated automatically, create the /etc/daily.local file and add the following lines:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;#!/bin/ksh

/usr/local/sbin/unbound-adhosts.sh
/usr/local/sbin/spamhaus.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All of this can be achieved simply with a basic installation of OpenBSD, without the need to install any additional packages. This is an advantage both in terms of update management and security.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Mon, 03 Apr 2023 04:16:11 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2023/04/03/make-your-own-vpn-wireguard-ipv6-and-ad-blocking-included/</guid><category>openbsd</category><category>server</category><category>tutorial</category><category>vpn</category><category>wireguard</category><category>ipv6</category><category>networking</category><category>security</category><category>hosting</category><category>ownyourdata</category><category>series</category></item></channel></rss>