<?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 - netbsd</title><link>https://it-notes.dragas.net/categories/netbsd/</link><description>Articles in category netbsd</description><language>en</language><lastBuildDate>Wed, 19 Nov 2025 09:16:00 +0100</lastBuildDate><atom:link href="https://it-notes.dragas.net/categories/netbsd/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>The Server That Wasn't Meant to Exist</title><link>https://it-notes.dragas.net/2025/05/13/the_server_that_wasnt_meant_to_exist/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/server_rack.webp" alt="A server, cables and lights"&gt;&lt;/p&gt;&lt;p&gt;Yesterday I read a piece of news that brought back an important - and painful - episode from my career.&lt;br /&gt;
A story about trust, technology... and the kind of problems that can't always be solved.&lt;/p&gt;
&lt;p&gt;About 16 years ago, I was contacted by an old friend. He was worried about a situation involving some mutual acquaintances.&lt;br /&gt;
To keep it short: an entrepreneur - administrator and owner of several companies - had died suddenly.&lt;br /&gt;
He was the kind of man who centralized everything, and his wife and children found themselves struggling to manage things.&lt;br /&gt;
One of the sons decided to cash out and leave the family business (focusing on his own career), while the others chose to stay involved in day-to-day operations.&lt;br /&gt;
The wife, elderly and retired for years, ended up at the helm, but she was clearly out of her depth.&lt;/p&gt;
&lt;p&gt;The main issue was the complete lack of information flow: no digital systems of any kind were in place.&lt;br /&gt;
Employees had their own PCs (sometimes even personal laptops), and there was zero control over anything.&lt;br /&gt;
All the accounting and administrative data were scattered across individual machines, often taken home at the end of the day.&lt;br /&gt;
From the owners’ perspective, all they saw was a huge cash flow coming in - yet the accounts were always in the red.&lt;/p&gt;
&lt;p&gt;"If we keep going like this, we’ll be bankrupt in just a few years", I was told.&lt;br /&gt;
What I could do was set up a proper IT system, structured to make data management transparent and traceable.&lt;/p&gt;
&lt;p&gt;I planned - and got immediate approval for - the purchase of routers, switches, various networking devices and a server with several disks.&lt;br /&gt;
&lt;a href="https://it-notes.dragas.net/2023/08/27/that-old-netbsd-server-running-since-2010/"&gt;The OS of choice, as was my habit at the time, was NetBSD&lt;/a&gt;. Thanks to XEN, I set up multiple VMs.&lt;br /&gt;
One handled the NAS duties (using Samba, so PCs could connect and store files directly there), another ran &lt;a href="https://archivista.ch/"&gt;Archivista&lt;/a&gt;.&lt;br /&gt;
I even worked on translating Archivista’s interface into Italian, since it wasn’t yet localized, just to make it easier for users.&lt;/p&gt;
&lt;p&gt;As usual in those days, I added a caching proxy (Squid) and a content filter (DansGuardian), to ensure proper usage.&lt;br /&gt;
The internet connection was very slow and often collapsed under heavy load - mostly recreational use, as logs revealed.&lt;br /&gt;
There was no supervision, and many people were downloading movies and such on company time.&lt;/p&gt;
&lt;p&gt;As often happens, not everyone was happy.  &lt;/p&gt;
&lt;p&gt;One figure in particular - the late owner's former right-hand man - opposed the new system in every possible way.&lt;br /&gt;
According to him, none of this was necessary. But the real alarm bell had been his sudden change in lifestyle.&lt;br /&gt;
He’d made purchases that didn’t remotely align with his salary.&lt;br /&gt;
At the time, the company had no oversight and dealt with a lot of cash. It was all technically legal, especially given the nature of the business. I won’t go into detail - privacy matters.&lt;/p&gt;
&lt;p&gt;Once everything was up and running, we trained the employees to use the new system.&lt;br /&gt;
Most were thrilled - finally able to work properly, with files in the right place and centralized document management.&lt;br /&gt;
OCR, archiving, etc. were all seen as major time-savers and a big boost in efficiency.&lt;br /&gt;
Some of the accounting staff remained skeptical, of course.&lt;/p&gt;
&lt;p&gt;Since all of this was far from where I lived at the time, I went back to my life once the system was stable and everything in place.&lt;br /&gt;
A few quiet days passed - then one morning, my phone rang:&lt;/p&gt;
&lt;p&gt;"Good morning, this is XYZ - I handle some technical aspects of a software suite used by the company where you've just installed everything.&lt;br /&gt;
We need to install our software, and I understand you set up the server. I’ll need the full server diagram and all the admin passwords".&lt;/p&gt;
&lt;p&gt;I explained that it wasn’t a Windows machine, as he assumed (without even having seen it), but NetBSD, running NetBSD and Linux VMs.&lt;/p&gt;
&lt;p&gt;A few seconds of silence.&lt;/p&gt;
&lt;p&gt;"I see. Then I’ll have to wipe it and install Windows. I need Windows, and I don’t have time to wait for a new server - I’ll proceed tomorrow morning".&lt;/p&gt;
&lt;p&gt;I froze. I told him that was not possible - the entire workflow now depended on that machine, and erasing it would be catastrophic.&lt;/p&gt;
&lt;p&gt;"I’ll speak with the owners", I said, "and I’m sure they’ll provide you with a separate server within hours".&lt;/p&gt;
&lt;p&gt;No use. He started to backpedal.&lt;br /&gt;
To my (young) eyes, the goal was now obvious: that server had to disappear, and fast.&lt;br /&gt;
He said he would "restore the previous situation", and claimed the server couldn’t remain as-is because &lt;em&gt;he&lt;/em&gt; needed it.&lt;/p&gt;
&lt;p&gt;I immediately called the owners. Sadly, due to inexperience and inability to handle the situation, they panicked.&lt;br /&gt;
They asked me to consider letting him do it, and then redoing the setup later, covering the cost of new hardware and my time.&lt;br /&gt;
I refused. I was young, but I already had this mindset: do what’s right, even at the cost of profit.&lt;br /&gt;
This was clearly a maneuver to eliminate controls - the server, the centralized filesystem.&lt;br /&gt;
The goal was to hide the real accounting data from owners and auditors. Thousands of euros vanished every day through "transactions".&lt;br /&gt;
The owners had started to understand, and this new pressure confirmed just how rotten things really were.&lt;/p&gt;
&lt;p&gt;I called that man back and told him clearly: the server I’d built wasn’t to be shut down.&lt;br /&gt;
If he needed one, I’d deliver a new server by that evening, just for him.&lt;/p&gt;
&lt;p&gt;At that point, he finally spoke more openly:&lt;/p&gt;
&lt;p&gt;"You don’t get it, do you? I need &lt;em&gt;that&lt;/em&gt; server. Not &lt;em&gt;a&lt;/em&gt; server.&lt;br /&gt;
You’d better go along with this — or you’ll have serious trouble working in this area again".&lt;/p&gt;
&lt;p&gt;And other similar, "nice" sentences. I replied calmly:&lt;br /&gt;
"Look, I’m just doing a favor for some friends. I don’t have clients in your area — and I don’t want any.&lt;br /&gt;
I’d rather do a good job for them than gain new clients".&lt;/p&gt;
&lt;p&gt;No way through. He kept pushing - confident in his own sense of "power" - until I said what I had been trying to avoid.&lt;/p&gt;
&lt;p&gt;Because I had recognized who he was.&lt;br /&gt;
And the disappointment hit me twice as hard - I used to admire him.&lt;br /&gt;
He, however, had not recognized me.&lt;/p&gt;
&lt;p&gt;"Excuse me, but why are you talking to me like this? You’ve known me since I was a child. Don’t you remember? I’m the nephew of..."&lt;/p&gt;
&lt;p&gt;He froze.&lt;br /&gt;
He understood immediately.&lt;br /&gt;
He connected the dots and knew full well that a single phone call to someone extremely close to me - someone he owed a great deal, both personally and professionally - would have the opposite effect he was aiming for.&lt;/p&gt;
&lt;p&gt;That person had helped him greatly over the years. So much so that he folded:&lt;/p&gt;
&lt;p&gt;"Oh... I’m so sorry... I didn’t recognize you. I’ll find another solution. Sorry again".&lt;/p&gt;
&lt;p&gt;He hung up.&lt;br /&gt;
Never heard from him again.&lt;/p&gt;
&lt;p&gt;I informed the owners that the issue was resolved (leaving out most of the details), but it didn’t last long.&lt;br /&gt;
Within days, a series of "unfortunate events" hit the server: the UPS failed, the server was "accidentally" unplugged and plugged back in incorrectly, and finally... it stopped responding on the network.&lt;/p&gt;
&lt;p&gt;It was dead.&lt;br /&gt;
And when we opened it, the hard disks were just... gone.&lt;/p&gt;
&lt;p&gt;But there was one thing nobody (but the owners) knew.&lt;br /&gt;
The server - slowly but surely - had been backing up externally.&lt;br /&gt;
All the data up to that point had been copied to a device we’d quietly installed at the owners’ home: a tiny PCEngines Alix, running NetBSD with two USB drives.&lt;br /&gt;
It was slow, yes - slow hardware, slow disks - but reliable.&lt;br /&gt;
That very device still works today (with FreeBSD) and provides services elsewhere.&lt;/p&gt;
&lt;p&gt;I handed all the data to the owners and asked what they intended to do.&lt;br /&gt;
They took some time - days, then weeks.&lt;br /&gt;
Eventually, they said they’d probably investigate whether there were grounds for a theft report.&lt;/p&gt;
&lt;p&gt;I never heard more about it.&lt;/p&gt;
&lt;p&gt;But then came a tempting offer:&lt;/p&gt;
&lt;p&gt;"Come work for us. Manage our network infrastructure and help us overhaul our internal procedures.&lt;br /&gt;
Even if you’ve just bought a house far from here, even if you’d have to leave your other clients -&lt;br /&gt;
we’ll pay you enough to forget everything else. Name your price".&lt;/p&gt;
&lt;p&gt;They would’ve done it, too.&lt;br /&gt;
Our mutual friend urged me:&lt;br /&gt;
"They’ve got a huge cash flow, but too many people are taking advantage of them due to lack of control.&lt;br /&gt;
Take the job - they’ll treat you like gold, and you’ll really help them".&lt;/p&gt;
&lt;p&gt;I didn’t think twice. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I turned it down&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I like my work.&lt;br /&gt;
I like doing what I do - and the income is a consequence, not the cause.&lt;br /&gt;
I would’ve had to give up my life, my path, to fight battles I don’t enjoy - and that I might not even win.&lt;/p&gt;
&lt;p&gt;Because sometimes, dishonest people &lt;em&gt;do&lt;/em&gt; win.&lt;/p&gt;
&lt;p&gt;I’ve never regretted declining that offer.&lt;br /&gt;
I lost touch with all of them years ago, but I later heard things went as I predicted:&lt;br /&gt;
the owners gradually backed out. &lt;/p&gt;
&lt;p&gt;They made another request later on, which I tried to fulfill — but even that was blocked, just when everything was ready.&lt;/p&gt;
&lt;p&gt;At some point, I had to walk away.&lt;br /&gt;
Not because I wanted to abandon them in a time of need, but because they weren’t giving me the tools to do what was necessary.&lt;br /&gt;
They were so overwhelmed, so unprepared, that they ended up yielding to pressure - often from the very people who were hurting them.&lt;/p&gt;
&lt;p&gt;And of course, I’ve left out the worst parts of the story.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Author's note: Many readers, understandably struck by the severity of the events, have speculated about the involvement of organized crime. I want to clarify that, while the situation was extremely problematic and dishonest, that wasn't the case. The "worst parts" I alluded to referred to other internal dynamics, abuses of trust, and improprieties that I prefer not to detail further for privacy reasons and to avoid weighing down the narrative.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That’s when I realized:&lt;br /&gt;
Some situations are so rotten, they simply can’t be salvaged.&lt;/p&gt;
&lt;p&gt;And that’s okay.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://it-notes.dragas.net/2024/10/03/i-solve-problems-eurobsdcon/"&gt;I solve problems&lt;/a&gt; - it’s what I do best.&lt;/p&gt;
&lt;p&gt;But I can’t solve &lt;strong&gt;every&lt;/strong&gt; problem.&lt;br /&gt;
Especially not when those involved choose to protect the problem instead of fixing it.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 13 May 2025 16:13:36 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/05/13/the_server_that_wasnt_meant_to_exist/</guid><category>server</category><category>horrorstories</category><category>ownyourdata</category><category>data</category><category>netbsd</category></item><item><title>Make Your Own Internet Presence with NetBSD and a 1 euro VPS – Part 1: Your Blog</title><link>https://it-notes.dragas.net/2025/04/22/make-your-own-internet-presence-with-netbsd-and-a-1-euro-vps-part-1-your-blog/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/terminal_htop.webp" alt="Photo: Terminal screen with htop"&gt;&lt;/p&gt;&lt;h2&gt;Why NetBSD?&lt;/h2&gt;
&lt;p&gt;For many years, I've been using (and appreciating) &lt;a href="https://www.netbsd.org/"&gt;NetBSD&lt;/a&gt; because it's stable, efficient, and reliable. The codebase has proven its reliability, &lt;a href="https://it-notes.dragas.net/2023/08/27/that-old-netbsd-server-running-since-2010/"&gt;running without reboots for years without issues&lt;/a&gt;. It supports ZFS (though differently than FreeBSD), LVM (useful for those accustomed to it on Linux), the ability to take filesystem snapshots (UFS2, making ZFS less crucial), and it's an &lt;a href="https://www.netbsd.org/docs/guide/en/chap-virt.html"&gt;excellent virtualization platform&lt;/a&gt;. Installation and updates are easy (including via &lt;a href="https://www.netbsd.org/docs/guide/en/chap-upgrading.html#using-sysupgrade"&gt;sysupgrade&lt;/a&gt; - which I'll cover in a future article). Since it focuses on portable and optimized code (running on ancient architectures requires cleanliness and correctness), it's particularly efficient on low-power devices, like embedded systems or cheap VMs. Therefore, it's one of the best solutions for a small personal setup that can still deliver excellent results and simple management.&lt;/p&gt;
&lt;p&gt;Indeed, the market offers very cheap VPS, often with just a single core and little RAM. But a modern single core packs power that a multi-core from just a few years ago could only dream of, and often, the I/O of these machines (a bottleneck for many services) is still decent. I personally use 1 euro per month VPS (VAT included - for those not subject to it, that's less than one euro per month!) with a public IPv4 address and (often) a /64 IPv6 block, ensuring full reachability across the entire network.
I'm not providing direct links as I have no affiliations, but netcup's "piko" VPS are among the types I use most often (&lt;a href="https://it-notes.dragas.net/2025/02/26/fedimeteo-how-a-tiny-freebsd-vps-became-a-global-weather-service-for-thousands/"&gt;a 4 euro/month netcup VM handles the entire FediMeteo project&lt;/a&gt;), and this type of VM is ideal for our purpose because some providers (like netcup) allow you to upload your own ISO and install your preferred operating system. On VPS like these, I've installed everything - including &lt;a href="https://omnios.org/"&gt;OmniOS&lt;/a&gt; and &lt;a href="https://www.tritondatacenter.com/smartos"&gt;SmartOS&lt;/a&gt; - without problems. And even such a small VPS, with an efficient operating system, can be extremely satisfying.&lt;/p&gt;
&lt;h2&gt;Why BSSG?&lt;/h2&gt;
&lt;p&gt;In this article, I'll describe how to create and publish a blog using &lt;a href="https://bssg.dragas.net"&gt;BSSG&lt;/a&gt; as it exemplifies my concept of portability and minimalism. BSSG on NetBSD currently doesn't leverage parallelism provided by tools like GNU Parallel, but for small to medium-sized blogs, this won't be an issue, especially considering these small VMs only have 1 core. Obviously, you can use any Static Site Generator (SSG) (like Hugo, Nikola, 11ty, Pelican, Zola, etc.) - the important thing is to have a static site served by a simple web server.&lt;/p&gt;
&lt;h2&gt;Let's Start with the Installation&lt;/h2&gt;
&lt;p&gt;Installing NetBSD is quite straightforward and is clearly covered, complete with explanatory screenshots, in the &lt;a href="https://www.netbsd.org/docs/guide/en/chap-exinst.html"&gt;excellent official NetBSD documentation&lt;/a&gt;, which I recommend using as a reference during the process, especially if it's your first time.&lt;/p&gt;
&lt;p&gt;In my case, I made sure to use the proposed disk geometry, use the standard automatic partitioning, but &lt;strong&gt;enable the "log" and "noatime" options for the filesystem&lt;/strong&gt;.
Both these options will provide a huge advantage in I/O operations, especially with BSSG, as the first enables journaling and the second prevents updating file metadata on every access. BSSG is more I/O bound than CPU bound, so any optimization is beneficial.&lt;/p&gt;
&lt;p&gt;Moving forward, I also recommend configuring the network (although installation can be done from packages on the installation ISO). For netcup, you can use DHCPv4 (even though it's a bit slow and sometimes seems to fail, the DHCP client will continue running in the background and eventually work).&lt;/p&gt;
&lt;p&gt;For IPv6, I usually configure it manually later, so I'll describe that further down.&lt;/p&gt;
&lt;p&gt;I also recommend enabling SSH, adding a regular user (and adding them to the &lt;code&gt;wheel&lt;/code&gt; group so they can gain root privileges) - in this case, I'll call the user &lt;em&gt;blog&lt;/em&gt;. Also, enable the installation of binary packages, as it will be convenient later to use &lt;code&gt;pkgin&lt;/code&gt; to install and update all necessary packages. All these steps are described clearly and in detail in the &lt;a href="https://www.netbsd.org/docs/guide/en/chap-exinst.html"&gt;guide&lt;/a&gt;, so I won't detail them here. But they are simple and logical, like all operations on BSD systems.&lt;/p&gt;
&lt;p&gt;After installation, reboot. If everything went correctly, you should be able to log in via console or SSH using the "blog" user (or whatever you named it).&lt;/p&gt;
&lt;p&gt;First, I suggest configuring the IPv6 address and installing the necessary packages.&lt;/p&gt;
&lt;p&gt;For IPv6, in the case of netcup, simply add one of the assigned addresses to the interface. In NetBSD, &lt;a href="https://www.netbsd.org/docs/guide/en/chap-net-practice.html"&gt;network interface configurations are stored (similar to OpenBSD) in specific files&lt;/a&gt;. For the first virtio interface, the file will be &lt;code&gt;/etc/ifconfig.vioif0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You need to elevate your privileges to root, open that file with your preferred editor, and add the configuration to the file itself:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ su -l
nb1euro# vi /etc/ifconfig.vioif0

inet6 your-ipv6-addr/64
up
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To test everything, perform a reboot and try pinging an IPv6 address (I often use &lt;code&gt;ping6 google.com&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;If all goes well, after a few seconds, you should see ping replies, confirming everything is configured correctly.&lt;/p&gt;
&lt;p&gt;Regarding packages, the only two strictly necessary ones are &lt;code&gt;bash&lt;/code&gt; and a markdown processor (by default, BSSG will use &lt;code&gt;commonmark&lt;/code&gt;; otherwise, it can be configured to use &lt;code&gt;pandoc&lt;/code&gt; or &lt;code&gt;Markdown.pl&lt;/code&gt;). &lt;code&gt;rsync&lt;/code&gt; can be useful for deployment. &lt;code&gt;sudo&lt;/code&gt; (or &lt;code&gt;doas&lt;/code&gt;) can be useful for elevating privileges for certain operations, at least at this stage.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ su -l
nb1euro# pkgin in bash cmark rsync sudo
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you're used to Linux, you can also install the "nano" editor:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro# pkgin in nano
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If &lt;code&gt;sudo&lt;/code&gt; was installed, it's now appropriate to grant users in the "wheel" group (like the regular user created during installation) the ability to elevate privileges. Edit the &lt;code&gt;sudoers&lt;/code&gt; file (I suggest using the &lt;code&gt;visudo&lt;/code&gt; command) and uncomment this line:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;## Uncomment to allow members of group wheel to execute any command
%wheel ALL=(ALL:ALL) ALL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, you can switch back to operating as the regular user, downloading and unpacking BSSG:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ ftp https://brew.bsd.cafe/stefano/BSSG/archive/0.15.1.tar.gz
nb1euro$ tar zxfv 0.15.1.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now that BSSG is ready, just initialize a directory with the structure for the new site:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ cd bssg
nb1euro$ ./bssg.sh init /home/blog/myblog
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Everything is set to start generating your blog. I recommend reading BSSG's &lt;code&gt;README.md&lt;/code&gt;. There are many options, themes, etc., but to get started, you just need to set the site's public URL. For example, if the site will be published as &lt;em&gt;myblog.example.com&lt;/em&gt; - just create a file at &lt;code&gt;/home/blog/myblog/config.sh.local&lt;/code&gt; (the path defined by the init command) and set the public URL:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;SITE_URL=&amp;quot;https://myblog.example.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This way, all URLs will be absolute URLs, which is necessary to ensure the correct functioning of RSS feeds, sitemaps, etc. This setting assumes HTTPS - if you just want to test the site over HTTP, simply use &lt;code&gt;http&lt;/code&gt; and then, optionally, change it to &lt;code&gt;https&lt;/code&gt; and regenerate the site later.&lt;/p&gt;
&lt;p&gt;You can already create your first test post, directly from the BSSG directory:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ ./bssg.sh post
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The system will use &lt;code&gt;nano&lt;/code&gt; if it's installed, otherwise it will use &lt;code&gt;vi&lt;/code&gt;. Don't worry, in the latter case, BSSG will write the procedure for exiting &lt;code&gt;vi&lt;/code&gt; as the post's text 🙂&lt;/p&gt;
&lt;p&gt;Once you save the post, BSSG will automatically generate the site. If everything went well, the &lt;code&gt;/home/blog/myblog/output&lt;/code&gt; directory will contain the final result. We are therefore ready for the first deployment, which can be done in many different ways. I will cover three:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Using &lt;a href="http://www.eterna23.net/bozohttpd/"&gt;bozohttpd&lt;/a&gt;, present &lt;a href="https://man.netbsd.org/httpd.8"&gt;by default in NetBSD's base system&lt;/a&gt;. It can be used via &lt;code&gt;inetd&lt;/code&gt; (launching an httpd process for each connection) or as a daemon. I'll describe the first option, showing in the final benchmarks how, even when used as a daemon, it remains a less performant solution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using nginx&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using Caddy&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, it's advisable to obtain a certificate to configure and use HTTPS. If you only want to test using HTTP, this part can be safely bypassed. For solutions 1 and 2, I'll use &lt;code&gt;certbot&lt;/code&gt;, which is well-known to many users with Linux experience. Caddy, on the other hand, manages certificates automatically, so there's no need for other solutions and thus no need to install &lt;code&gt;certbot&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo pkgin in py313-certbot
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To use &lt;code&gt;bozohttpd&lt;/code&gt;, no further installation is necessary. At this point, the options diverge.&lt;/p&gt;
&lt;h2&gt;Using NetBSD's Integrated httpd&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;bozohttpd&lt;/code&gt; is integrated into NetBSD and, by default, can be launched directly via &lt;code&gt;inetd&lt;/code&gt;. This solution, while not extremely efficient or scalable, is simple and requires few resources. It's fine if you expect only a few visits per day, but when used via &lt;code&gt;inetd&lt;/code&gt;, the initial latency for each connection is tangible. It can still be useful for some tests or small deployments.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;/etc/inetd.conf&lt;/code&gt; file already contains the options to handle this situation:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;#http           stream  tcp     nowait:600      _httpd  /usr/libexec/httpd      httpd /var/www
#http           stream  tcp6    nowait:600      _httpd  /usr/libexec/httpd      httpd /var/www
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By uncommenting these two lines and restarting &lt;code&gt;inetd&lt;/code&gt; (&lt;code&gt;service inetd restart&lt;/code&gt;), the server will start responding to HTTP requests on both IPv4 and IPv6.&lt;/p&gt;
&lt;p&gt;If you want to add HTTPS support, no problem. Just request a certificate via &lt;code&gt;certbot&lt;/code&gt; and specify the webroot.&lt;/p&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo certbot-3.13 certonly
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Choose option 2 - the one where you specify the webroot - enter the domain, and when prompted, provide &lt;code&gt;/var/www/&lt;/code&gt; as the webroot.&lt;/p&gt;
&lt;p&gt;The certificate will be created. Then, modify the &lt;code&gt;/etc/inetd.conf&lt;/code&gt; file to also include support for HTTPS, adding two lines similar to these (obviously, change the certificate paths):&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;https            stream  tcp     nowait:600      _httpd  /usr/libexec/httpd      httpd -Z /usr/pkg/etc/letsencrypt/live/myblog.example.com/fullchain.pem /usr/pkg/etc/letsencrypt/live/myblog.example.com/privkey.pem /var/www
https            stream  tcp6    nowait:600      _httpd  /usr/libexec/httpd      httpd -Z /usr/pkg/etc/letsencrypt/live/myblog.example.com/fullchain.pem /usr/pkg/etc/letsencrypt/live/myblog.example.com/privkey.pem /var/www
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: &lt;code&gt;httpd&lt;/code&gt; will run with the permissions of the &lt;code&gt;_httpd&lt;/code&gt; user, so make sure all certificates are readable by that user:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro# chown -R _httpd /usr/pkg/etc/letsencrypt/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Restart &lt;code&gt;inetd&lt;/code&gt;, and the server will also respond over HTTPS.&lt;/p&gt;
&lt;p&gt;To make your blog public, simply copy the files from the site's output directory to &lt;code&gt;/var/www/&lt;/code&gt; - this time using &lt;code&gt;sudo&lt;/code&gt; to bypass permission issues:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo rsync -avhHPx /home/blog/myblog/output/ /var/www/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The site will be immediately visible.&lt;/p&gt;
&lt;h2&gt;Using nginx&lt;/h2&gt;
&lt;p&gt;Nginx is fast and efficient, and the performance difference is noticeable (some benchmarks follow below). For an efficient setup ready for a high number of visits, it's advisable to use a web server suited for the purpose, just like nginx.&lt;/p&gt;
&lt;p&gt;First, install nginx and the certbot plugin for nginx. This will simplify the installation and renewal of certificates:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo pkgin in py313-certbot-nginx nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Copy the startup script to &lt;code&gt;/etc/rc.d&lt;/code&gt; - as indicated by the post-installation message. In NetBSD, this operation must be done manually, but it's always pointed out:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo cp /usr/pkg/share/examples/rc.d/nginx /etc/rc.d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: If you previously used &lt;code&gt;httpd&lt;/code&gt; from &lt;code&gt;inetd&lt;/code&gt; following the previous solution, you must disable it in &lt;code&gt;inetd.conf&lt;/code&gt; and restart &lt;code&gt;inetd&lt;/code&gt; to free up ports 80 and 443.&lt;/p&gt;
&lt;p&gt;Now you can create a virtual host for our new site.&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo vi /usr/pkg/etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and add, at the end of the file and before the final closing curly brace:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;server {
        listen 80;
        # If you also have configured IPv6 support
        listen [::]:80;

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

        server_name myblog.example.com;

        # If you want a long cache for media and css - be careful, this means that if you change to a new theme, it might not be visible immediately as the browser might still use the old cached one
        location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
            expires 30d;
            add_header Cache-Control &amp;quot;public, no-transform&amp;quot;;
        }

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

&lt;p&gt;Now, it's time to configure the system to enable nginx. Just edit &lt;code&gt;/etc/rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo vi /etc/rc.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and add:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nginx=YES
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, you can start nginx:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo service nginx start
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nginx will start listening on port 80. Generating and installing the certificate is very simple:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo certbot-3.13 --nginx -d myblog.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This command will request the certificate and install it, so nginx will already be configured to use it.&lt;/p&gt;
&lt;p&gt;As with the previous method, to make your blog public, simply copy the files from the site's output directory to &lt;code&gt;/var/www/&lt;/code&gt; - using &lt;code&gt;sudo&lt;/code&gt; to bypass permission issues:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo rsync -avhHPx /home/blog/myblog/output/ /var/www/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The site will be immediately visible.&lt;/p&gt;
&lt;h2&gt;Using Caddy&lt;/h2&gt;
&lt;p&gt;Caddy is a convenient and all-in-one solution, efficient and fast. It's packaged for NetBSD and allows you to go online in a flash. I won't delve into the configuration because there are many tutorials (&lt;a href="https://caddyserver.com/docs/getting-started"&gt;including the official ones&lt;/a&gt;), but you just need to install it and run it:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo pkgin in caddy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once installed, go to the directory you want to serve (e.g., &lt;code&gt;/var/www&lt;/code&gt; or directly &lt;code&gt;/home/blog/myblog/output&lt;/code&gt;) and run:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;nb1euro$ sudo caddy file-server --domain myblog.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Caddy will start, request the certificate, and begin serving your blog over HTTPS as well. To install Caddy as a service (i.e., with a configuration file, etc.), you can proceed similarly to how it's done on Linux. The NetBSD Caddy package doesn't include the &lt;code&gt;rc.d&lt;/code&gt; script, but you can copy and paste one (into &lt;code&gt;/etc/rc.d/caddy&lt;/code&gt;) from &lt;a href="https://www.unitedbsd.com/d/1406-caddy-service/4"&gt;a thread posted on UnitedBSD&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Performance Comparison&lt;/h2&gt;
&lt;p&gt;I performed some performance tests on these solutions. Here are the results, on a single-core 1 euro/month VPS, from my home connection (which also has its own limitations):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NetBSD httpd via inetd:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;Running 10s test @ https://myblog.example.com/
  4 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   213.52ms  173.10ms   1.11s    76.01%
    Req/Sec    12.92      9.19    50.00     75.91%
  371 requests in 10.10s, 1.39MB read
Requests/sec:     36.72
Transfer/sec:    140.65KB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These numbers are quite poor, linked to high latency caused by having to launch &lt;code&gt;bozohttpd&lt;/code&gt; for each incoming connection.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NetBSD httpd as a daemon:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;Running 10s test @ https://myblog.example.com/
  4 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    35.74ms    6.96ms 108.80ms   81.36%
    Req/Sec    18.29      9.45    50.00     70.88%
  676 requests in 10.10s, 2.53MB read
Requests/sec:     66.92
Transfer/sec:    256.32KB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here the situation is decidedly better, but not exceptional. &lt;code&gt;httpd&lt;/code&gt; isn't designed for high loads or performance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nginx as a daemon, 1 worker:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;Running 10s test @ https://myblog.example.com/
  4 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    30.69ms    4.87ms  64.14ms   66.01%
    Req/Sec   379.39     65.94   464.00     90.91%
  15026 requests in 10.04s, 56.50MB read
Requests/sec:   1496.65
Transfer/sec:      5.63MB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we are on another level, showing truly solid performance. This type of result can handle significantly high loads without particular difficulty. The efficiency of both NetBSD and nginx pays off.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Caddy:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-plaintext"&gt;Running 10s test @ https://myblog.example.net/
  4 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    32.10ms    5.75ms  95.04ms   87.44%
    Req/Sec   362.74     64.29   434.00     91.67%
  14374 requests in 10.05s, 54.63MB read
Requests/sec:   1430.82
Transfer/sec:      5.44MB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Caddy shows results comparable to nginx, so the choice between them depends solely on the type of configuration you want to achieve and the experience each person has with the specific platforms.&lt;/p&gt;
&lt;h2&gt;Conclusion: Efficient Minimalism&lt;/h2&gt;
&lt;p&gt;We've seen how it's possible to create a personal, professional, and performant online presence with minimal investment. This solution, based on NetBSD and a 1€/month VPS, offers several advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Negligible Cost&lt;/strong&gt;: For 12€ per year, you can have a website (and more!) completely under your control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Surprising Performance&lt;/strong&gt;: As demonstrated by the benchmarks, excellent performance can be achieved even with limited resources (up to 1400-1500 requests/second with nginx or Caddy).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security and Stability&lt;/strong&gt;: NetBSD is renowned for its reliability and security, fundamental characteristics for any online service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total Control&lt;/strong&gt;: Unlike free blogging platforms, you have full control over every aspect of your site.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning Experience&lt;/strong&gt;: Managing a BSD system allows you to acquire valuable system administration skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This minimalist configuration demonstrates that you don't need to invest in expensive cloud solutions or oversized VPS to have a quality online presence. In an era where the tendency is to think "moooar powaaaar = better results", NetBSD reminds us that efficiency and good design can yield excellent results even with limited resources.&lt;/p&gt;
&lt;p&gt;After all, you don't need a thousand-node cloud to write something worth reading.&lt;/p&gt;
&lt;p&gt;In the upcoming articles in this series, we will explore how to expand this basic installation with other useful services and how to keep the system updated and secure over time.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 22 Apr 2025 07:30:36 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2025/04/22/make-your-own-internet-presence-with-netbsd-and-a-1-euro-vps-part-1-your-blog/</guid><category>netbsd</category><category>bssg</category><category>ssg</category><category>ownyourdata</category><category>server</category><category>web</category><category>blogging</category><category>tutorial</category><category>series</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 Read-Only Device with NetBSD</title><link>https://it-notes.dragas.net/2024/09/10/make-your-own-readonly-device-with-netbsd/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/embedded2.webp" alt="Make your own Read-Only Device with NetBSD"&gt;&lt;/p&gt;&lt;p&gt;One detail that is often overlooked when dealing with embedded (or remote) devices is a key point of vulnerability: the file system.&lt;/p&gt;
&lt;p&gt;For non-COW file systems (like ext4 on Linux, FFS, etc.), there are situations where a crash or a power outage could cause corruption, requiring manual intervention. This risk is especially present when using root on SD cards or similar storage media in embedded systems. Over time, these media are destined to fail due to numerous writes.&lt;/p&gt;
&lt;p&gt;For certain use cases, it's advisable to set up a read-only root file system, which ensures better reliability in case of system issues. Think of scenarios like a router (critical for network access) or a caching reverse-proxy, such as the one described in my series &lt;a href="https://it-notes.dragas.net/2024/09/03/make-your-own-cdn-netbsd/"&gt;"Make your own CDN"&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While &lt;a href="https://it-notes.dragas.net/2024/05/31/freebsd-tips-and-tricks-native-ro-rootfs/"&gt;FreeBSD natively supports this configuration&lt;/a&gt; and some Linux distributions offer custom solutions (e.g., &lt;a href="https://wiki.alpinelinux.org/wiki/Alpine_local_backup"&gt;Alpine Linux&lt;/a&gt;), &lt;strong&gt;NetBSD&lt;/strong&gt; stands out as an excellent choice for such devices. It supports nearly all embedded devices, is lightweight, and its stability minimizes the need for frequent updates.&lt;/p&gt;
&lt;h3&gt;The Key Idea&lt;/h3&gt;
&lt;p&gt;Although NetBSD doesn't provide native read-only support, it's flexible enough to allow for this configuration. Many years ago, I followed &lt;a href="https://www.netbsd.org/~jschauma/netbsd-solidstate.html"&gt;a howto&lt;/a&gt; to set up a read-only system, and the idea remains simple and effective: &lt;strong&gt;NetBSD writes primarily to specific locations&lt;/strong&gt;, unlike some Linux distributions that attempt to write to various parts of the file system. On NetBSD, the main write targets are the &lt;code&gt;/tmp&lt;/code&gt; directory and &lt;code&gt;/var&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With this in mind, we can configure these directories to reside in memory file systems (mfs) and ensure that &lt;code&gt;/var&lt;/code&gt; contains everything necessary for the system to function correctly.&lt;/p&gt;
&lt;h3&gt;1. Prepare the Environment&lt;/h3&gt;
&lt;p&gt;Start with a basic NetBSD installation (I'll skip the installation steps as there are many tutorials available, and it's straightforward).&lt;/p&gt;
&lt;p&gt;As a first step, clean up the &lt;code&gt;/var&lt;/code&gt; directory. After each reboot, its contents will be extracted into the mfs and occupy RAM.&lt;/p&gt;
&lt;h4&gt;Disable &lt;code&gt;man.db&lt;/code&gt; generation and swap usage:&lt;/h4&gt;
&lt;p&gt;Edit the following configuration files:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;# /etc/rc.conf
makemandb=NO
no_swap=YES
&lt;/code&gt;&lt;/pre&gt;

&lt;pre class="highlight"&gt;&lt;code&gt;# /etc/daily.conf
run_makemandb=NO
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, remove the current &lt;code&gt;man.db&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;rm /var/db/man.db
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once this is done, create a compressed archive of the current &lt;code&gt;/var&lt;/code&gt; contents to be replicated at every boot:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;cd /
tar -cvzf var-image.tar.gz var
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;2. Create a Custom Startup Script&lt;/h3&gt;
&lt;p&gt;Next, create a file called &lt;code&gt;/etc/rc.d/mount_mfs_fs&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;#!/bin/sh
#
# mount_mfs_fs: mount memory file system for /var
# by roby, 23 jun 2003 - adapted by Stefano - 01 Sep 2024

# PROVIDE: mount_mfs_fs
# REQUIRE: root

. /etc/rc.subr

name=&amp;quot;mount_mfs_fs&amp;quot;
start_cmd=&amp;quot;mount_mfs_fs_start&amp;quot;
stop_cmd=&amp;quot;:&amp;quot;

mount_mfs_fs_start()
{
    # Check if the /var entry is present and uncommented in /etc/fstab
    if grep -q '^tmpfs[[:space:]]\+/var[[:space:]]\+tmpfs[[:space:]]\+rw,-m1777,-sram%25' /etc/fstab; then
        echo &amp;quot;Mounting memory file system: /var&amp;quot;

        # Mount the file system for /var
        mount /var

        # Extract the contents of the tar file into /var
        tar -xvzpf /var-image.tar.gz -C /

        echo &amp;quot;Mounting memory file systems: Done.&amp;quot;
    else
        echo &amp;quot;The tmpfs entry for /var is not present or is commented out in /etc/fstab. Skipping mount and extraction.&amp;quot;
    fi
    sleep 5
}

load_rc_config $name
run_rc_command &amp;quot;$1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Make the script executable:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;chmod a+rx /etc/rc.d/mount_mfs_fs
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;3. Modify Boot Process&lt;/h3&gt;
&lt;p&gt;Now, modify the &lt;code&gt;/etc/rc.d/mountcritlocal&lt;/code&gt; file to require this script to run before its execution:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;#!/bin/sh
#
# $NetBSD: mountcritlocal,v 1.17 2022/02/20 14:42:07 alnsn Exp $
#

# PROVIDE: mountcritlocal
# REQUIRE: mount_mfs_fs

$_rc_subr_loaded . /etc/rc.subr

name=&amp;quot;mountcritlocal&amp;quot;
start_cmd=&amp;quot;mountcritlocal_start&amp;quot;
stop_cmd=&amp;quot;:&amp;quot;

mountcritlocal_start()
{
    #       Mount critical file systems that are `local'
    #       (as specified in $critical_filesystems_local)
    #       This usually includes /var.
    #
    mount_critical_filesystems local || return $?
    if checkyesno zfs; then
        mount_critical_filesystems_zfs || return $?
    fi
    return 0
}

load_rc_config $name
load_rc_config_var zfs zfs
run_rc_command &amp;quot;$1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;4. Configure &lt;code&gt;/etc/fstab&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Edit the &lt;code&gt;/etc/fstab&lt;/code&gt; file to mount &lt;code&gt;/tmp&lt;/code&gt; and &lt;code&gt;/var&lt;/code&gt; in memory:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;tmpfs           /tmp        tmpfs   rw,-m1777,-sram%25
tmpfs           /var        tmpfs   rw,-m1777,-sram%25
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;5. Test the Configuration&lt;/h3&gt;
&lt;p&gt;You can now reboot the system and check if everything works correctly. Once logged in, the &lt;code&gt;df&lt;/code&gt; command should show something like this:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;Filesystem      1K-blocks         Used        Avail %Cap Mounted on
/dev/ld0a        18298254       393938     16989404   2% /
tmpfs              524192         4224       519968   0% /var
kernfs                  1            1            0 100% /kern
ptyfs                   1            1            0 100% /dev/pts
procfs                  4            4            0 100% /proc
tmpfs              524192            4       524188   0% /var/shm
tmpfs              524192            4       524188   0% /tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;6. Set Root to Read-Only&lt;/h3&gt;
&lt;p&gt;Currently, the system is still running in read-write mode, but &lt;code&gt;/var&lt;/code&gt; and &lt;code&gt;/tmp&lt;/code&gt; are in memory disks. To switch the root file system to read-only, edit the &lt;code&gt;/etc/fstab&lt;/code&gt; file like this:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;/dev/ld0a               /       ffs     ro               1 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On the next reboot, the system will be in pure read-only mode.&lt;/p&gt;
&lt;h3&gt;7. Perform Updates&lt;/h3&gt;
&lt;p&gt;To install packages, update the system, or make any changes, you'll need to temporarily switch back to read-write mode. Comment out &lt;code&gt;/var&lt;/code&gt; in mfs, change the root file system back to read-write, and reboot:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;mount -uw /
vi /etc/fstab
/dev/ld0a               /       ffs     rw               1 1
[...]
#tmpfs           /var    tmpfs   rw,-m1777,-sram%25
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After making the necessary changes, regenerate the &lt;code&gt;/var&lt;/code&gt; tarball as done in step 1.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 10 Sep 2024 01:41:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/09/10/make-your-own-readonly-device-with-netbsd/</guid><category>netbsd</category><category>server</category><category>hosting</category><category>tutorial</category><category>ownyourdata</category></item><item><title>Make Your Own CDN with NetBSD</title><link>https://it-notes.dragas.net/2024/09/03/make-your-own-cdn-netbsd/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/embedded.jpg" alt="Make Your Own CDN with NetBSD"&gt;&lt;/p&gt;&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This article is a spin-off from &lt;a href="https://it-notes.dragas.net/2024/08/29/make-your-own-cdn-openbsd/"&gt;a previous post on how to create a self-hosted CDN&lt;/a&gt;, based on OpenBSD, but this time we'll focus on using &lt;a href="https://www.netbsd.org/"&gt;NetBSD&lt;/a&gt;. The idea is to &lt;a href="https://it-notes.dragas.net/2024/08/26/building-a-self-hosted-cdn-for-bsd-cafe-media/"&gt;create reverse proxies with local caching&lt;/a&gt;. These proxies would cache the content on the first request and serve it directly afterward. The proxies would be distributed across different regions, and the DNS would route requests to the nearest proxy based on the caller’s location. All this is achieved without relying on external CDNs, using self-managed tools instead. &lt;/p&gt;
&lt;p&gt;NetBSD is a lightweight, stable, and secure operating system that supports a wide range of hardware, making it an excellent choice for a caching reverse proxy. Devices that other operating systems may soon abandon, such as early Raspberry Pi models or i386 architecture, are still fully supported by NetBSD and will continue to be so. Additionally, NetBSD is an outstanding platform for virtualization (using &lt;a href="https://wiki.netbsd.org/ports/xen/howto/"&gt;Xen&lt;/a&gt; or &lt;a href="https://www.netbsd.org/docs/guide/en/chap-virt.html"&gt;qemu/nvmm&lt;/a&gt;) and deserves more attention than it currently receives.&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;While I won't detail the installation process for NetBSD, as it depends heavily on the hardware you have available, I will guide you through setting up a self-hosted CDN using NetBSD, Varnish, nginx, and the acme.sh or lego tool for SSL certificate management.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;During the installation of NetBSD, ensure that you enable support for binary package management. This will install &lt;code&gt;pkgin&lt;/code&gt;, &lt;a href="https://pkgin.net/"&gt;a tool that simplifies package management&lt;/a&gt; on NetBSD. If you skip this step during installation, you can still install pkgin later, but it's easier to let the installer handle it.&lt;/p&gt;
&lt;p&gt;Once your system is up and running, use pkgin to install the necessary packages: Varnish, nginx, and, depending on your preference, either acme.sh or Go (if you plan to compile lego). Although lego is not available as a precompiled package, you can easily compile it locally using Go, but for simplicity, I recommend using acme.sh.&lt;/p&gt;
&lt;p&gt;For this setup, I will present two methods for generating and renewing certificates: using acme.sh or compiling lego - to reach the same final outcome as the &lt;a href="https://it-notes.dragas.net/2024/08/29/make-your-own-cdn-openbsd/"&gt;OpenBSD article&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Option 1: Using acme.sh (Recommended)&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/acmesh-official/acme.sh"&gt;acme.sh&lt;/a&gt; is a simple, yet powerful, shell script that handles certificate generation and renewal with ease. To install acme.sh:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;pkgin in acmesh varnish nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once acme.sh is installed, you can proceed to configure it for certificate management. It supports DNS authentication and integrates with many DNS providers, making it a flexible choice.&lt;/p&gt;
&lt;h3&gt;Option 2: Compiling Lego&lt;/h3&gt;
&lt;p&gt;If you prefer to use lego, you will need to compile it manually, as it is not available as a precompiled package for NetBSD. First, install Go and other necessary packages:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;pkgin in go varnish nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To compile lego, you’ll need some disk space. Since the &lt;code&gt;/tmp&lt;/code&gt; directory in NetBSD is often mounted as &lt;code&gt;tmpfs&lt;/code&gt; (using RAM), you may run out of space during compilation if your system has limited memory. You can temporarily disable &lt;code&gt;tmpfs&lt;/code&gt; by editing &lt;code&gt;/etc/fstab&lt;/code&gt; and commenting out the relevant line:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;#tmpfs           /tmp    tmpfs   rw,-m=1777,-s=ram%25
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After rebooting, compile lego:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;export GO111MODULE=on
go122 install github.com/go-acme/lego/v4/cmd/lego@latest

cp go/bin/lego /usr/pkg/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once lego is compiled and installed, you can uncomment the &lt;code&gt;/tmp&lt;/code&gt; line in &lt;code&gt;/etc/fstab&lt;/code&gt; and reboot again.&lt;/p&gt;
&lt;h2&gt;Configuring Varnish and nginx&lt;/h2&gt;
&lt;p&gt;First, copy the necessary &lt;code&gt;rc.d&lt;/code&gt; scripts for nginx and Varnish:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;cp /usr/pkg/share/examples/rc.d/nginx /etc/rc.d/
cp /usr/pkg/share/examples/rc.d/varnishd /etc/rc.d/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, add the following to &lt;code&gt;/etc/rc.conf&lt;/code&gt; to enable and configure nginx and Varnish:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;nginx=YES
varnishd=YES
varnishd_flags=&amp;quot;-f /usr/pkg/etc/varnish/default.vcl -T localhost:9999 -a &amp;quot;/var/run/varnish.sock&amp;quot;,user=nginx,group=varnish,mode=660 -s default,500m&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this configuration, Varnish listens on a Unix socket, and nginx connects to it. This approach is more efficient and helps avoid some issues that may arise when exposing Varnish over an IP/port.&lt;/p&gt;
&lt;h3&gt;Creating the Varnish VCL Configuration&lt;/h3&gt;
&lt;p&gt;Next, create the VCL configuration file for Varnish at &lt;code&gt;/usr/pkg/etc/varnish/default.vcl&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;vcl 4.1;
import std;

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

# ACL - purge - it-notes.dragas.net
acl purge_it_notes {
    &amp;quot;allowedToPurge_IP&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;h3&gt;Configuring nginx&lt;/h3&gt;
&lt;p&gt;Now, modify the nginx configuration file at &lt;code&gt;/usr/pkg/etc/nginx/nginx.conf&lt;/code&gt;. Set the number of worker processes to "auto" to take advantage of all server cores, and configure the reverse proxy for your site(s). Here's an example configuration:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code&gt;[...]
worker_processes  auto;
[...]

server {
    server_name it-notes.dragas.net;

    location / {
        proxy_method $request_method;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://unix:/var/run/varnish.sock;
    }

    access_log /var/log/nginx/access.it-notes.dragas.net.log;
    error_log /var/log/nginx/error.it-notes.dragas.net.log;

    listen [::]:443 ssl;
    listen 443 ssl;
    http2 on;
    # If you're using acme.sh, just change the location of the certificates
    ssl_certificate /root/.lego/certificates/it-notes.dragas.net.crt;
    ssl_certificate_key /root/.lego/certificates/it-notes.dragas.net.key;
}

server {
    if ($host = it-notes.dragas.net) {
        return 301 https://$host$request_uri;
    }
    server_name it-notes.dragas.net;
    listen 80;
    listen [::]:80;
    return 404;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Starting Varnish and nginx&lt;/h3&gt;
&lt;p&gt;Finally, start the Varnish and nginx services:&lt;/p&gt;
&lt;pre class="highlight"&gt;&lt;code class="language-bash"&gt;service varnishd start
service nginx start
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything is configured correctly, both Varnish and nginx will be up and running, ready to handle incoming connections.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations, you have successfully set up your own CDN on NetBSD. This solution is lightweight, stable, and fully under your control, allowing you to break free from the constraints of major service providers. With NetBSD's broad hardware support and minimal overhead, this setup can run on a wide variety of devices, making it a versatile choice for self-hosted solutions.&lt;/p&gt;
&lt;p&gt;I'm using it as a test and as a read-only root filesystem with a RAM-only local cache for my blog on a &lt;a href="https://www.raspberrypi.com/products/raspberry-pi-zero-w/"&gt;Raspberry Pi Zero W (first edition)&lt;/a&gt;, and as soon as I get the new FTTH, I'll probably make it accessible via IPv6 for Italy, putting it physically into production.&lt;/p&gt;
&lt;p&gt;If your goal is geo-replication, you can use DNS providers that offer location-based routing or set up your own DNS infrastructure to manage and resolve requests according to the user’s location. With multiple reverse proxies, separate DNS servers, and a well-configured cache, you can achieve a highly resilient system with minimal risk of a single point of failure.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Tue, 03 Sep 2024 01:41:00 +0200</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2024/09/03/make-your-own-cdn-netbsd/</guid><category>netbsd</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>That Old NetBSD Server, Running Since 2010</title><link>https://it-notes.dragas.net/2023/08/27/that-old-netbsd-server-running-since-2010/</link><description>&lt;p&gt;&lt;img src="https://it-notes.dragas.net/featured/terminal_htop.webp" alt="That Old NetBSD Server, Running Since 2010"&gt;&lt;/p&gt;&lt;p&gt;As 2010 was drawing to a close, I found myself on more flights than coffee breaks, constantly testing technical solutions, in search of stability and reliability.&lt;/p&gt;
&lt;p&gt;One morning, a client called. They needed to operate various services on their internal network, which essentially meant reconfiguring the entire network behind their firewall. They required a dhcp, an internal DNS, an Apache + PHP server for some internal (and a couple of external) websites, a file server accessible via both NFS and Samba (as Windows PCs needed access), an internal SMTP connecting to an external relay to ensure faster email dispatches for employees given their unstable connectivity, and a few other nuances. My task was to set all this up within a tight two-day window. Given the constraints, I opted for my top choice of the time for such tasks: NetBSD.&lt;/p&gt;
&lt;p&gt;I suggested the client invest in Enterprise-grade hardware. However, they insisted on using a server they already had, assembled by a local vendor with “gaming-quality” parts. Though they claimed these were high-quality, it was clearly consumer-grade — lacking dual power supply, remote management capability, and fitted with consumer-grade hard drives.&lt;/p&gt;
&lt;p&gt;I always had a feeling that I wasn't their first choice for the job. Perhaps someone had bailed on them, and they had settled for me. They had originally intended to implement everything on Windows 2008 Server, but I persuaded them to try my solution.&lt;/p&gt;
&lt;p&gt;With the hardware in hand and less than 48 hours on the clock, I dived in. The OS, as mentioned, was NetBSD 5.1. I compartmentalized the services using several Xen DomU (my favored solution at that time over the then-nascent KVM on Linux). This involved creating multiple partitions on two disks and setting up a unique RAID for each DomU.&lt;/p&gt;
&lt;p&gt;After successfully setting everything up, including an external connection to my OpenVPN hub, I handed the server back to the client. Checking in a month later, the feedback was mostly positive, save for some SMB latency issues.&lt;/p&gt;
&lt;p&gt;Over the next two to three years, I made occasional adjustments to the machine, but then lost touch with the client. By 2015, my OpenVPN hub was discontinued, taking with it many older or defunct servers, including that NetBSD server.&lt;/p&gt;
&lt;p&gt;Fast forward to February 2021, the phone rang. It was that same client, seeking to integrate a new network configuration because of a new firewall. The fact that they were calling meant that the NetBSD server was still alive! Curious, I accepted the task.&lt;/p&gt;
&lt;p&gt;To my astonishment, the server was still up &amp;amp; running perfectly. The external services were active but inaccessible, wisely kept hidden from potential threats, while the internal ones were functioning smoothly. NFS was working, as were SMB, the internal DNS, and the SMTP relay. The server was executing about 80% of its original tasks.&lt;/p&gt;
&lt;p&gt;What surprised me the most was its uptime. Sadly, I didn't take note, but the last restart had been in 2012 after the Emilia Romagna earthquake. They had a backup generator, so the server always had an efficient uninterrupted power supply.&lt;/p&gt;
&lt;p&gt;Nine years of uptime for a server set up in a few hours, on consumer-grade hardware, and left largely unattended for years.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://my-notes.dragas.net/2025/05/02/being-a-bad-salesperson-by-choice/"&gt;I now understand why I'm not – and will never be – rich&lt;/a&gt;. My first (and last) employer complained about my preference for stable and reliable solutions, equating it with lesser profits. According to him, unstable solutions requiring frequent maintenance meant more revenue. To me, a job is well-done when it works consistently, not when it demands constant fixes.&lt;/p&gt;
&lt;p&gt;I'm unsure if the server is still operational, but I'll certainly check when I get a chance. Nonetheless, I'm grateful for having trusted NetBSD, a lightweight, stable, secure, and efficient operating system, which, in my view, still doesn't receive the acclaim it truly deserves.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Stefano Marinelli</dc:creator><pubDate>Sun, 27 Aug 2023 05:17:49 +0000</pubDate><guid isPermaLink="false">https://it-notes.dragas.net/2023/08/27/that-old-netbsd-server-running-since-2010/</guid><category>netbsd</category><category>virtualization</category><category>xen</category><category>hardware</category><category>container</category><category>server</category></item></channel></rss>