NixOS and Me: 1 week later
Published: 2024-09-26
Originally posted 2024-05-28 on cohost
Don’t expect high-caliber writing here… The ramblings of an adhd girl on stimulant meds in the middle of a workday. Hopefully I address some topics which other people are confused by so that they don’t have to go through the gauntlet quite so badly. You’ve been warned though.
I recently switched to NixOS, because the appeal of a configuration which exists independent of your individual machine is a really compelling one, and on the face it seems like a win-win: In the time that it would take me to configure an OS to my liking I’ll have also made a .nix
configuration which can be carried to any machine. In turn, I can get more into the things which I have always been too lazy to figure out like having a fancy-pants nvim
setup or a cool terminal emulator config with the cute themes and things. The idea of being able to switch whole desktop environments with a one-liner and not having it break everything gives you flexibility on another level!
About me
I am a 25 year old software developer and I’ve always been kind of a nerd, but from the sidelines. Growing up, I had a PSP and I followed the console hacking scene with a lot of interest. I thought it was so cool that Total_N00B was cooking up exploit chains and HEN and they were only 15! I saw that and I wished I could be like them, but never really tried to learn programming outside of script kiddie stuff until school. My first laptop I got when I was probably 12 or 13. I had one of those Dell Mini 10v, the tiny little laptop with these huge bezels on it. I even upgraded the ram from 1GB to 2GB, which was an enormous chore that required reassembling the whole insides of the thing. I ran Windows XP on it until it got to frustrating me, and then I ventured into the world of Ubuntu flavors. I grew to like LXDE and XFCE. Later on I got a Dell Latitude E6400 that I used for the majority of high school, and I’d have fun mucking about with Arch Linux on it. I’ll never forget the first trip through the Arch Installation Manual and being blown away at how good yaourt
and the AUR were. I also remember having to fight with those accursed broadcom wireless chipsets, and how setting up the NVidia drivers were such a nightmare!! It was the best of times, and the worst of times.
All that to say, I wouldn’t call myself a linux expert per se, but I definitely have been a user, and I know what I like and don’t like in a distribution to some degree. As a software developer now, that has grown outwards as well.
What I like about Nix:
I do think that the configurations moving with you are super cool! I have my own setup (you’re in the repository now) and I have had a lot of fun putting it together, and the thrill of running the installer off the liveusb and then doing sudo nixos-rebuild switch --flake .
on my laptop, and watching it instantly become exactly how I like it! I think it’s awesome that you can bundle up packages to have a completely encapsulated dev environment and how that makes cross-compiling super easy. On a lark, because I recently picked up one of those little emulation handhelds recently I tried my hand at trying to build one of the distributions for it, and while it took a bit of head-banging, it was no more than it would have been elsewhere, and the end result is a huge mess of packages being handled super tidily! All the benefits of that trickle down too: being able to roll back generations of your configuration while keeping your files in place means unlike arch, when you fuck something up, it’s not a colossal mess in the same way. It has enabled me to go further in my configuration than I usually care to in most linux distributions, and in that sense it’s great fun. Ephemeral shells are great in theory, and usually in practice. They allow you to have a mucked-up messy package environment without the worries of “oh god, what all did I have to install for this? It’s going to live on my computer forever now”.
Problems I have had with Nix:
1. There are 15 ways to do everything, and it’s hard to figure out how to even find the answers.
First off, you get your links to:
- The Install Manual
- Wiki #1
- Wiki #2
- Package Search (Hold on to this!!)
So, you’re dropped in cold turkey: You power through the manual and figure out how to get a basic configuration.nix
file going, and skip all the random shit about how to configure servers for a bunch of applications you have no interest in. Configuring a .nix
file on the surface is vary straightforward: everything has attributes, and it’s more or less like doing any kind of object reference in Java or something. The {}
bundles at the top don’t make a ton of sense, the manual says that it denotes this is actually a function that takes at least two arguments config and pkgs
. I get what pkgs
is, but I don’t know what config
is and I certainly don’t know where it comes from. Very quickly you find yourself going down rabbit holes:
- How come firefox that comes in configuration.nix uses
programs.enable.firefox
and everything I’m doing usesenvironments.systemPackages = [ xyz ];
? Modules for NixOS are completely separate to packages, even though notionally what a module is doing is installing a package? There is no configuration that gets applied to firefox outside of being set toenable = true
? How come you can still apply anoverride
to a package which is somehow different than a module? The manual will at this point point you to a mile-long Appendix which is a totally seperate page to the regular manual and lists every module in the operating system. Scrolling through a bunch ofboot.*
options and it looks like junk. It does how a module can take in arguments, and then provides you a huge list of options you can pass, but doesn’t seem very useful. So let’s take to google!
That clears things up! Someone even says, wow, we should add this to the manual! Oh, what they added to the manual is that little box which was a source of confusion that led us here:
But apparently, there’s an Option search which is next to the package search. That’s far more useful.
How can I configure my gnome settings? Well, the manual will tell you, by default, you can install gnome extensions but not enable them; you can override some of the
gsettings
but you cannot actually set updconf
without getting home-manager, which comes with it’s own manual of equal length. Yikes, I don’t have the patience for this. Come to find out later, this isn’t exactly true, but there is no documentation on the wiki, manual, or really anywhere beyond random forum posts and github PR comments to how to configure it that way. So, we have to set uphome-manager
, but we’ll put that on the shelf for now, and just do some overrides.I’m getting a little comfortable with the syntax of this configuration, but why is everything in
/etc/nixos/
and requiring root access? I guess I can make a symlink from/etc/nixos
to/home/user/.nix
or something, but that seems like a weird oversight? Better yet, I’m thinking even bigger! I’ll just have the mainconfiguration.nix
call acommon.nix
module in a repository I can track with git, so that I can do the version control for it, and I don’t have to have root access! That’s still not super portable, though, so what are other people doing?
2. WTF is a flake, and why does everyone want to use them?
My understanding, which composes the entirety of this document, and which I’m sure is definitively incorrect in some sense, is that a flake is more or less a “bundle” for a stack of .nix
files, which allows you to define meta information about the use cases for them, and pull in external packages in a way which reads more cleanly. As with most things in nix, there’s an absolute ton of hay written about this, but a lot of it ends up being mental overload. I ended up just having to ape someone’s own process, and when applying them to individual repositories, I feel like my understanding has started over from scratch a lot of times.
A nice piece of writing ( ty @leftpaddotpy ) which finally cut through the noise somewhat, but my ADHD eyes glazed over about halfway through (sorry) and I still don’t understand overlays fully.
The manual does NO explaining of this, I suppose because they’re an experimental feature still. Oh well, back to google and we’re hit with another, third party manual of equal length on flakes alone. aughhh.
I feel the headache coming on, but at least this will make the whole thing generic. So, you put in your inputs and your outputs, and your mess of closing brackets and you can spit something out:
{
description = "NixOS configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
};
outputs = inputs@{ nixpkgs, home-manager, ... }: {
nixosConfigurations = {
hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./default.nix
];
};
};
};
}
Can I at least pass in like my desired hostname and username as a parameter so it doesn’t feel like I’m hard-coding everything? Apparently, flakes just can’t take arguments? That seems kind of fucking weird.
home-manager
, or, start your understanding of configuration files over again from scratch now idiot
3. OK so home-manager
gives you a flake example, How do I put it into the system configuration?
Turns out, it manages it’s entire own state in the way that nixos-rebuild
does, so basically: I have to start my understanding of how the configuration.nix
works from scratch, but this time it applies to the home directory, and NOT the system. Ergo, you shouldn’t mix them at all because they are totally seperate, and require different definitions of users despite living in one big repository, but it also clarifies that homeConfigurations
in the flake is not in any way connected to your nixpkgs.lib.nixosSystem
configuration, and you have to just pull it in to your modules like so:
{
description = "NixOS configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { nixpkgs, home-manager, ... }: {
nixosConfigurations = {
suletta = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./default.nix
./devices/desktop/desktop.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.lain = import ./home/lain/home.nix;
}
];
};
homeConfigurations = {
"lain" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
modules = [
./home/lain/home.nix
];
};
};
};
}
Now I have to duplicate those gnome settings, but at least I can change them to something useful, if I go and figure out where the home manager options live… Back to google, there’s another fucking mile-long appendix and some third-party person took it on themselves to write up a search tool thank god.
4. Python is fucking hell??
Look, Python is not the best to work with for dependencies on the best of days, but this one will lead you into a special layer of python hell this is heretofore unseen. I have a repo of simple scripts that I wanted to use, but I am dependent on a package py7zr
which is not included in the nixpkgs
database; down the rabbit hole I go:
Solutions I tried for this:
- https://nixos.wiki/wiki/Python (All of these are outdated, so you have to go to wiki #2)
- https://wiki.nixos.org/wiki/Python
I tried to create a
shell.nix
file which pulls in a package, which you have to go look up the hash for on PyPI manually and insert. OK, but as it turns out, that package is dependent on other packages which are not in, so I manually have to go insert ALL of their information as well? Thankfully, the wiki includes a link to a script that can generate all that crap for you, so lets do that!
Well, for whatever reason, trying to use (pkgs.callPackage ./python-packages)
just doesn’t work?? Back to google:
Great question dude! 2 posts deep and here’s the eventual answer, a virtual shell script in another mile long piece about python which just doesn’t try do do everything, so you can use pip
as normal, but it’s cheating technically. I’m content to leave it at that.
5. All the little stuff.
I want to search for a package.
There’s a wiki article for how to do this that gives you five ways to do it:
- the website, i.e. not in a shell.
nix search
is locked behind experimental features, and it takes 20 seconds to find firefox in their example. Helpfully, they let you knowIt may be slow the first time
, but how often am I searching for the same package over and over? This is a non-starter.nix-env -qaP
which comes with the caveatvery slow and requires a lot of memory
: searching for firefox gives me a result after 12 seconds. Another non-starter.nix repl
which is again locked behind experimental features and requires you to drop whatever you were doing, and then you can tab-complete for a package. This works, but this is no replacement for likeapt-cache search
.- Reverse search for a file.
Back to google, and again someone is asking for the REAL answer, and with 24 responses: https://www.reddit.com/r/NixOS/comments/199ocj8/so_how_do_i_really_search_for_packages/
They point to nix-search-cli
, which seems to be the best option in practicality, but is itself a package which doesn’t come shipped with the distribution, and doesn’t actually use the package cache. This really seems like missing the forest for the trees. I know it is best practice to put things in your .nix
files and not to fetch packages manually, but it is a real thing that you have to do sometimes, and any distro alive can provide you this feature. What makes this far more perplexing is, if I try to call a program I don’t have installed, I will be presented with the options very quickly…
Everything is so stop-start I want to get a plugin for vscode.
Yes, sadly I’m not cool enough to use neovim, because I’ve never had the time and energy to sit down and figure out all the plugins, themes, shell, terminal emulators, and dotfiles to use in order to get it working right. I’d love to, but I don’t want it to be temporary, and I don’t want to pull in some giant pack with a million hotkeys I don’t understand, which is half the reason I switched!
I get vscode set up via vscode-with-extensions.override
and it’s sweet! You get all your extensions thrown in on install and it’s awesome. But I decide, I need to go get this nix stuff, so I go to the extensions store and wow it will just not allow me to install any:
I want to go install some random package, I go to do a nix-env -iA
. I forgot to put nixos.
in front of it, doh. Try again and now I get the inexplicable error this derivation has bad meta.outputsToInstall
. I have no clue what this means. Back to google.
https://discourse.nixos.org/t/error-this-derivation-has-bad-meta-outputstoinstall/20019
??? Why does it work this way? No clue. But it gets to the core, which is that you kind of have to plan for everything. My earlier python example was something I wanted to touch up quickly because it was mostly there when I had last touched them a year ago, and I end up taking a 90 minute detour trying to figure out how to install a singular pip package because it would be wrong to have system packages. I understand why this is, but it can be really fucking frustrating when you don’t know that you’re about to walk straight into a wall like that, and it turns using this operating system into a sine wave that looks like this:
Conclusions
In this process, I went through:
- 3 manuals
- 2 manual appendices
- 3 wiki pages
- 6 google searches
- 4 nixos forum posts
- 2 well-constructed and thoughtful blogs: first and second
I think there is something to be said for the quality of the arch wiki here, and I am really missing that level of clarity and conciseness from all of the texts here. I have a few suggestions for improvement here:
- Cut all the crap about server hosting out of the NixOS manual. Those are niche things and don’t have anything to do directly with the installation of the operating system, and would be great as wiki articles. Again, the arch linux installation guide is a great template here, and the “general recommendations” page for arch, while long, keeps it concise and allows all of the tools to have some space to breathe on their own pages.
- Break the manual into several smaller wiki pages, with links between them. This will mean that the table of contents for each section is not nearly as scary, but give an opportunity to explore those server configurations which are otherwise cluttering the configuration guide.
- Break the appendix laying out every possible option for the operating system into chunks too so it is easier to parse and people (me) don’t immediately skim the first 5 entries and go “this is useless”
- (It’s possible this is coming in the next one) Pull the information about flakes from the other wiki pages and put them into the manual.
- I know it is a third party feature, but roll the home manager installation instructions into the main wiki parallel to the explanation about flakes. It will centralize the information and help the user flow into a better setup. I know it is a third party module, but so are all of the other servers listed in the
Configuration
section, and it’s arguably functionally a feature of the operating system to most users. - Get a better way to search the package cache, and don’t tell the user to just use
nix-env -qaP
if you acknowledge in the wiki article for this that it is slow. - I understand the intention of the auto-generated configuration.nix file existing in
/etc/nixos
but I really believe most people are getting invested in Nix to roll their own configuration. At least dedicate some words to the idea that you shouldn’t commit to that setup as it is.
I’m gonna stick with it, I think. Every time I run face-first into a wall it is frustrating as all get out, but after you climb over a problem once, you can pretty soundly say “this is fixed forever” after you put it in your config. I like having a way to iterate my setup, it makes learning new tools and trying to configure them way less intimidating because if it works, it’s locked in, and if not, it can get tossed instantly.
I love that it’s portable between my desktop and my laptop, so when I go get in the bed I can pick up where I was even if I have been fucking around in weird gnome configs for an hour.
For all of it’s idiosyncracies, nix really is like no other, and I think it’s really cool. I would love to see an OS which has a more approachable language for it’s configuration, but I’m fine to settle with this for now. I think if I was to recommend it to other people, I’d suggest installing nix on fedora or something first to get used to it though.