It’s been a while since I’ve posted on this series, but a lot has changed in that time. I’ve managed to learn more Nix and become more comfortable with the ecosystem, which has allowed me to make more changes to my system.
While these changes are less NixOS-specific, it seems much harder to me to be able to do and more importantly, maintain them without Nix.
This post will just be a brief list of all the changes I’ve ended up implementing. If you want to follow along at home and copy my configs, you can get my NixOS config, clone and search for the required settings.
zram is a nifty feature which requires the sacrifice of some RAM and then using this RAM to create a compressed swap device in memory. In my current config, I have given 1 gigabyte of RAM in exchange for 20 gigabytes of zram, which helps mitigate OOM freezes, and helps speed up some big compilations.
Speaking of OOM, rather than using systemd-oomd
, which
didn’t seem to have much of an effect for me, I switched to earlyoom, which ended up
solving the “system freezes under load” problem for me. The worst I see
now is that my system becomes a bit less responsive, especially during
linking.
I also decided to embrace Nix dev shells and removed almost all of my development tools from my user install, instead using per-project flakes to install stuff like the Rust toolchain, C compilers, debuggers, LSPs etc. This also allowed me to configure mold as the default linker for C/C++/Rust projects, which gives me a nice speedup during linking.
In the future, I would like to have these per-project flakes serve as
an easy way to sandbox my developer environments, such that as soon as I
enter these directories and the flake loads, I can enter a less
privileged environment. One of the flaws with the way code-sandbox
does it is that it is a very rigid shell script. A Nix module that can
be applied and adjusted per flake would be much better (for example,
does it require IPC access? does it need Wayland or sound?)
I’ve replaced some of the GNU coreutils with Rust rewrites for
getting a faster, more modern equivalent. Some of these are also aliased
so typing ls
actually triggers eza
, for
example.
This includes:
bat
instead of cat
(I liked it so much I now use
bat
as my pager instead of less)eza
instead of ls
dust
instead of du
(this runs much faster than the normal
du
)delta
instead of diff
for rendering pretty diffs with colorsrg
instead of grep
(I earlier had this aliased but now I never
type grep
, rg
is smaller to type anyways)sk
, which is a
Rust replacement for fzf
.I have an alias called scanfor
which allows me to use
sk
and ripgrep to search in all text files contained in a
folder recursively and open that file up in Helix. This means if I’m not
sure about where I have services.syncthing
defined in my
Nix config repo, I can type scanfor
and search for
services.syncthing
. A press of the Enter key will open the
required file in Helix. This has served me well a lot, and its
usefulness scales with the size of the project I would work on.
Similar to this, I also have the .
alias, which just
runs hx .
. This opens up the Helix file picker at the
current folder, allowing me to search by file name and open that
file.
There are also some aliases which shorten nixos-rebuild
commands, so I can execute them from anywhere in my filesystem and have
easy commands for switching to a new NixOS config, or updating my
system.
I also have my prompt configured using starship, which looks better than the bash default.
magit
was also added
(via an opinionated config with Vim keybindings) via an overlay. Though
I don’t use magit
much in daily practice, it has come in
handy for speeding up some more complicated git operations.
I’ve switched to using doas
instead of sudo
for commands that need elevated permissions. From my simple uses (and
for the majority of single user Linux desktop users) doas
is more than enough, and it has a much smaller codebase, with a lot less
attack surface, which makes it a more secure utility.
I finally enabled the firewall on my system, and have ports open for KDE Connect, Syncthing etc.
I have a custom KeepassXC overlay (basically, an overlay is a way you can modify a Nix function) which disables X11 and networking support, so it can only run as a Wayland program and only make Unix sockets (for communication with browser extension).
I replaced the default NTP daemon on my system
(systemd-timesyncd
) with chrony
, since chrony
has support for NTS (Network Time Security), which reduces the chances
that an attacker can manipulate the time on my system by spoofing NTP
packets.
I also took this time to learn a bit more about systemd service hardening, and used that knowledge (and a ton of trial and error) to sandbox some services, such as Tailscale, such that they don’t have access to my private files and any permissions that they don’t really need.
I’ve also restarted using Home Manager for config file management. I had removed Home Manager from my config earlier since it wasn’t working properly when I moved my NixOS system config to flakes, but now I’ve added it as a NixOS module, which means that whenever I need to make a change in Home Manager, I have to rebuild my system.
I’ve ended up moving most, if not all of my configs to Home Manager, including ones for:
I’ve also been able to house my KDE Plasma config in Nix as well,
thanks to the excellent plasma-manager
module. This, combined with creating immutable config files for certain
Plasma/KDE programs not covered by plasma-manager
, has led
me to have virtually my entire desktop config within Nix. I even have
two Plasma plugins as git submodules within my Nix config repo.
Anything not in Home Manager is covered by Impermanence, and if some data isn’t covered by either of these, it is either non-config personal data, like pictures and personal files, or it doesn’t matter ;)
I tried out keyd
, which is a
pretty simple program that helps you remap keys for custom shortcuts
etc.
I simply swap the Caps Lock and Escape keys, and the difference is truly night and day. It took me maybe a week or two to fully train my fingers to not instinctively press the actual Escape key in Helix and instead go for the Caps Lock key.
I also have a layer that activates when Caps Lock is held, and this has let me map the h, j, k and l keys to be arrow keys. For example, Caps Lock + h is equivalent to the left arrow key. This is a gamechanger and lets me bring a little bit of Vim to every program.
Truly “the last word in filesystems”, I decided to try out ZFS on my machine, since I was becoming more concerned about the future of btrfs, given that Red Hat dropped it from RHEL and the new kid on the block seems to be bcachefs. ZFS also has native encryption, which seemed intriguing, even if some metadata about the subvolumes (datasets in ZFS parlance) is leaked. Using native encryption seemed to be the more reliable option, since ZFS’ error correction can work with it, and there is one less layer that can bork things. NixOS is also one of the few Linux distros that has first-class ZFS support (ZFS is harder to set up on other distros due to the complicated licensing issues preventing ZFS’ inclusion in the Linux kernel, but NixOS hand waves this away for you and gives you ZFS support even in its default USB install media).
I don’t really use the advanced features of btrfs or ZFS outside of creating subvolumes and enabling zstd compression on them, so I am a poor judge of which filesystem is better. However, I feel more comfortable with a ZFS install due to the above mentioned reasons.
After porting my installnix.sh
script to create ZFS
partitions and use native encryption instead of LUKS, I ended up
reinstalling my system. Before reinstallation, I opted to only back up
my /persist
and select parts of my home folder. I opted not
to back up any dotfile that wasn’t in /persist
.
When the reinstall had been completed, I was only missing one or two things, which was solved by getting the Nix repo back on my system and rebooting (Plasma was missing the two plugins I have stored in my repo as submodules)
There were a couple refactors in my Nix config repo to help organize the code. I now try to have each service have its own file and import that separately, which makes it super easy to make a service disappear entirely from my system, simply by commenting it out. It also makes it easy to paste snippets from others’ configs or let others copy my code for their configs, as well as share some configs between different NixOS configurations. This is how my Raspberry Pi config lives off a lot of the same config as my main machine’s config.
I’ve ended up making quite a lot of changes in my system, and the best part is that these are stable changes; an OS update isn’t going to wipe them out, or have me tweak a new setting. Even if something like this is required, it will go inside a git repo and not an undocumented, obscure path in the traditional FHS where I will forget all about it.
I also feel far more comfortable trying out experimental software or
new tools in my workflow, like keyd
, on NixOS since I know
I can always rollback to the old method by reverting some commits or
rebooting.
This website was made using Markdown, Pandoc, and a custom program to automatically add headers and footers (including this one) to any document that’s published here.
Copyright © 2024 Saksham Mittal. All rights reserved. Unless otherwise stated, all content on this website is licensed under the CC BY-SA 4.0 International License