summaryrefslogtreecommitdiffstats
path: root/blog/3-advantages-nixos.html
blob: d836a3c1365a1c466a99b914f2861991777faf60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>3 Advantages of Using NixOS | Skullheadx</title>
		<meta name="description" content="This blog post explores how Nix lets me do fearless deployments, manage configs in one place, and solve reproducibility.">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" type="text/css" href="../blog.css">

		<script>

			// By Oskar Wickström
			// Licensed under the MIT License (https://github.com/owickstrom/the-proportional-web/blob/main/LICENSE.md)
			
			window.addEventListener("load", () => {
				const asides = [...document.querySelectorAll("aside")];
				asides.forEach((aside, i) => {
					const anchor = aside.previousElementSibling;
					const name = `--paragraph-before-aside-${i}`;
					anchor.style.anchorName = name;
					aside.style.positionAnchor = name;
					});
					});
		</script>

		<link rel="icon" href="../favicon.ico">
	</head>
	<body>
		<nav class="main-nav">
			<a href="../index.html">Main Page</a>
			<a href="./index.html">All Posts</a>
			<a href="../tech/index.html">Technology Posts</a>
		</nav>
		<main class="blog">
			<header id="top">
				<h1 class="title">3 Advantages of using NixOS</h1>
				<p class="subtitle">Authored by <cite><a href="../about.html">Skullheadx</a></cite>
					on <time datetime="2026-08-04">August 4, 2026</time>.</p>
				<!-- <p>Updated: <time datetime="2026-08-27">August 27, 2026</time>.</p> -->
			</header>
			<!-- <nav id="TOC" role="doc-toc"> -->
			<!-- 	<h2 id="toc-title">Contents</h2> -->
			<!-- 	<ul class="incremental"></ul> -->
			<!-- </nav> -->

			<!-- <h1 id="foreword" class="unnumbered">Foreword</h1> -->
			<p>I was hanging out on <code>#lobsters</code>
				on IRC (<a href="https://libera.chat">Libera Chat</a>), and people were discussing different flavours of Linux which prompted me to reflect whether Nix solves the problems I encounter from day to day.</p>

			<h1>Fearless Upgrades</h1>
			<p>On non declarative systems, there is a lot of manual maintenance to ensure the system runs smoothly. Double or triple that effort if you have more than one machine. When I first got into Linux, I put <a href="https://archlinux.org/">Arch Linux</a>
				on my laptop. The install went smoothly and I was off to the races, until I received an email explaining that I need to update the package manager, Pacman. So I followed the instructions, and I broke something and I couldn't access the mirrors. Given my general inexperience, I just reinstalled the whole thing because I wasn't sure how to fix it.</p>
			<p>My experience with Arch left an impression on me that my system should reliable and not break when I'm doing routine maintenance. Luckily, I found out about NixOS and its declarative setup so I never have to feel scared to upgrade my system because I know that I can always rollback to a previous change.</p>
			<p>This allows me to easily bisect issues to find the exact version where it broke. For example on <a href="https://github.com/nix-darwin/nix-darwin">Nix Darwin (Nix for MacOS)</a>, there was a linker error when I tried to update <code>audacity</code>
				because it was built for newer MacOS versions than my system. My first solution was to add another input for <code>nixos-26.05</code>, and rebuild an older version of <code>audacity</code>
				which didn't have the issue. This upgrade strategy lets me update everything else to the bleeding edge while simultaneously pinning certain packages, that haven't caught up, to a stable version. This kind of reproducibility issue is inherent to MacOS not being designed with the same guarantees of Nix in mind.</p>
			<aside>As of August 27th, I've been able to update <code>audacity</code>
				to the latest on unstable.</aside>
			<p>With the assurance that I can easily roll back a disastrous update, I've had great success managing a fast update cycle on my desktop and production server. I believe that a good way to manage updates is with small frequent changes that let you easily pinpoint the issue, rather than deal with them all at once during one upgrade. That's why the guarantee of <em>fearless</em>
				upgrades is so appealing to my sensibilities.</p>

			<h1>Configuration All in One Place</h1>
			<p>Dotfiles and config files are usually all over the place, which is why I find Nix incredibly useful for organizing and deploying them to my server and desktop PC. For instance, I manage SSH authorized keys and configuration, a myriad of system users with varying permissions, Git, <a href="https://git.zx2c4.com/cgit/">cgit</a>, <a href="https://soju.im">soju</a>
				(IRC bouncer), <a href="https://github.com/aristanetworks/nix-serve-ng">nix-serve-ng</a>
				(Nix bin cache), NFS, <a href="https://www.wireguard.com/">WireGuard</a>, GnuPG, CDN, and <a href="https://thekelleys.org.uk/dnsmasq/doc.html">split-horizon DNS</a>.</p>
			<p>Recently, I was experimenting with split-horizon DNS, which routes DNS queries like <code>git.skullheadx.com</code>
				directly to my homelab if I'm on my local network, otherwise it routes through my public VPS to my homelab over WireGuard. It turns out adding split-horizon DNS had an unintended side effect on my git ssh autotunnel from my homelab to VPS causing an incident leading to degraded service on git over ssh operations. In other words, it broke because the ssh autotunnel relied on the routing for <code>git.skullheadx.com</code>
				to route to the VPS, but since the homelab is on my local network, the DNS resolver just told my homelab to look at its own local IP. I was able to hone in on the issue because I can turn off certain services, like <code>dnsmasq</code>, to test my entire server configuration. Moreover, thanks to being tracked in Git history, I bisected the changelog, and was able to find when the issue started to occur, and I resolved it by telling the git auto ssh tunnel to use the IP of the VPS directly, rather than relying on the faulty assumption that it would get routed where I wanted it to.</p>
			<p>I strongly prefer this style of system administration because I have specifically designed my flake to be <a href="../blog/suckless_nix.html#clarity">abundantly clear</a>, following the <a href="https://suckless.org/philosophy">suckless philosophy</a>. Since my configuration is deployed on real hardware (not some nebulous cloud), I explicitly define the services and programs that I need for each host all in one place, which allows me to see what's deployed there at a glance.</p>

			<h1>Actually Solving the Reproducibility Problem</h1>
			<p>I did a nix store optimise which deletes identical files and replaces them with hard links to a single copy. I ran it on my laptop which cleared 40 GB of duplicates. It made me reflect on the problem that Nix is trying to solve: how can we reproduce a package exactly the same on everyone's computer?</p>

			<p>This is a really hard problem to solve and has given rise to many solutions like containers. Yes they can work, but Nix solves the problem <em>better</em>
				than containers because it lockfiles and reproduces only the exactly dependencies required, meanwhile the containers will install a whole OS image so that the packages used can be reproduced.</p>

			<p>In my opinion, it's pretty overkill to download and install a whole new image for every single deploy. If you were engineering a proper solution, you should make <em>only</em>
				the things you are trying to deploy reproducible, including all its dependencies. Take this to the scale of an entire OS, and Nix becomes the obvious answer since it tracks all those dependencies.</p>

			<p>But taking a step even further back, why is this a problem in the first place? The whole philosophy of UNIX and Linux systems is that it's intended for any developer to come and add programs, and build off of the community's work. Because there are so many contributors, many anonymous, that makes it extremely difficult to standardize an environment that everyone should use. Some may say that the culture of replacing the existing programs with any of your choice is a selling point of Linux, but this approach is not fully without downsides, since we now have no idea what libraries and dependencies exist on the user's system. I've recently started using OpenBSD as as a router for all my internet traffic towards my servers. Most of the programs that I use are first party, and they all just integrate seamlessly with each other. Moreover, the general attitude towards system upgrades is to update everything to the next release altogether. It's a completely different approach to the goal of achieving a stable operating system, which works with significantly less complexity.</p>

			<h1>To Conclude This Reflection</h1>
			<p>I still think that NixOS and OpenBSD have their places. For everything that needs to be rock solid, low resource, and highly secure I've opted for OpenBSD. My BSD router handles TLS termination, relayd, firewall to the public internet and static web hosting (my business).</p>
			<p>Nix is invaluable for trying out new, and 3rd party code. For example, I'm running <a href="https://git.zx2c4.com/cgit/">cgit</a>, <a href="https://soju.im">soju</a>
				IRC bouncer, <a href="https://thekelleys.org.uk/dnsmasq/doc.html">Dnsmasq</a>
				split horizon DNS, <a href="https://github.com/aristanetworks/nix-serve-ng">Nix bin cache</a>, and NFS. The flexibility and power from the three advantages we've explored make NixOS a joy to quickly deploy new services, and debug when if they go wrong.</p>
		</main>
		<footer class="blog-footer">
			<p>Return to <a href="#top">top?</a></p>
			<a href="https://skullheadx.com">https://skullheadx.com</a>
		</footer>
	</body>
</html>