I'm a little...totalitarian.
Self-hosting from a ThinkPad under the bed.
I've always wanted a lot of control over my linux distros.
And in that time, I've realized that maintaing a server--one, two, 30, 50, 300--still feels a lot like this.
Here's how it goes.
We need resilient systems that can be rebuilt from scratch, come already documented, and are version controlled.
There's a lot of attempts at solving this problem, or subsets of it.
Others exist (eg. imaging), but let's focus on these 3.
How many folks have used some funky collection of Bash scripts to manage their machines?
Anyone using Ansible?
Sometimes brings systems from an unknown state to another unknown state.
Because you're not starting from scratch from the bootloader to the userland, drift is inevitable.
Docker is great for apps, not entire systems.
Even bootable containers have some clear limitations.
Dockerfiles are really just imperative sequences compiled into layers.
And, if you're like me, you use NixOS (by the way).
Or, if you're here, you're at least Nix-curious.
Nix - the package manager.
Nix - the language.
Nix - the build system.
NixOS - the linux distro.
nixpkgs - the package repository.
Do this, then that vs. produce this.
Systems are built from immutable derivations stored in the Nix store by hash, symlinked into place.
Upgrades and rollbacks are non-destructive.
Managed by nix, nixos-rebuild, darwin-rebuild, home-manager, etc.
Anyone heard of Flakes?
Meme source: https://fedi.astrid.tech/notice/AS7z9qW0q6SYs9LEsC
Nix typically deployed from Flakes.
Experimental feature, over 80% of Nix users use them.
Declare inputs, declare outputs.
Inputs locked by hash in a flake.lock file.
Nix builds can be intensive, but results are hashed and can be uplaoded to a remote cache.
Subsequent rebuilds are significantly faster.
Modules can be dynamic and configured by-host after import.
Simplified overview of my flake based on its outputs.
Gathered with the `nix flake show` command.
The most trivial flake.
Outputs an x86-64 build of the GNU Hello package
These slides are also built with a flake.
buildPhase
installPhase
build and runtime dependencies
source tree
Nix command line
build
run
test (for evaluation and custom tests)
updating flake inputs
Building one of my servers remotely.
On conference WiFi.
BTW, fortree is aarch64-darwin and slateport is x86_64-linux.
Then, checking the whole flake for eval errors.
Note the trace.
How you switch between generations of your system config.
Unlike other atomic/immutable distributions, you don't need to reboot.
nixos-rebuild brings your running system to the desired state.
(kernel updates require reboots)
Evaluates your flake.
Build the system configuration.
Decrypts my secrets with agenix.
Sets up /etc
Restarts/stops/starts services as-needed.
Prints a store path to the system configuration.
Lets us realize GitOps workflows for our whole system.
Ranges from a beefy Ryzen system to a 10 year old ThinkCentre to a Rapsberry Pi and a t2.micro on AWS.
The same flake defines both my homelab, my cloud servers, and mine and my husband's personal devices, e.g. this laptop.
So what do I host on these machines?
Plex, Ombi, Immich, Vaultwarden, Karakeep, Forgejo (git forge), action runners for my CI, my website, and my Bluesky Personal Data Server.
This sounds like a lot, but it's the result of 3 years of effort.
Any time I need to configure something, I try to do it in the Nix way.
Firefox? Nix. Git? Nix. VS Code? Nix.
A complicated Pipewire filter-chain to make this laptop's speakers sound better than horrible? Nix.
Modules can be dynamic, with their own options and tunings. They don't have to be static blocks of code.
On every push, CI checks for evaluation and formatting errors, then builds every flake output. So we don't waste anything, the results (custom settings, packages, etc.) are cached.
There are many Nix deployment tools, many of which integrate with GitHub Actions and other CI tools.
I've written my own in Go, but I mainly rely on NixOS's built-in auto upgrade module.
Here my module is a wrapper around a module included in nixpkgs, with my complete settings.
Set operation, reboots, etc.
Now, contrary to the title of this presentation, things *will* break. That's a fact of life.
That's why we have backups.
Dynamic backups, if I move where my Forgejo state directory is, this module knows where to find it.
What are the rewards for doing all this?
Get it out of your head.
Write one, deploy forever.
If something changes, you get warnings that make sense.
CppNix development is in an odd place.
NixOS has stayed on a prior version.
Determinate Systems = corporate, defense contractor affiliated.
Lix = lesbian furries, community-led project.
Don't use CppNix on non-NixOS.