Nix: Language, Nixpkgs, and NixOS
Nix is a functional language and package manager written in C++.
Nix is designed to process/output derivations which define some set of inputs to generate some output. Usually a binary, but it could be anything: docker images, iso’s, websites, and etc.
Nixpkgs is a community maintained mono-repo of all kinds of packages which have derivations written for them which you can use with Nix to build those packages and also use them in your own packages. For instance: gcc, libc, python, jupyter, and etc.
NixOS is essentially a big nix function that takes some configuration from you and combines that with Nixpkgs to create a full Linux Distribution which can be easily built, cached, rebuilt, verified, and etc. all using Nix.
This series by Ian Henry is currently the most in-depth guide I’ve found which helps explain Nix and NixOS. It documents his experience learning and understanding Nix. The docs and community-maintained wiki help a lot but a lot is left unsaid. Especially the needed trivia needed to be able to read through the source code of Nixpkgs for examples of what/how/why things are done.
Flakes Link to heading
Flakes are the newer way of configuring derivations. Much of the Nix ecosystem is still moving to them and they fix a lot of things with how packages and environments are built today.
The latest version of nix
you can install via the
website supports Flakes already. Before you needed to install
nix
and then upgrade to the new version and most
tutorials will cover that, but it’s not needed anymore. At
most,
you’ll need to create a
~/.config/nix/nix.conf
file
to enable the experimental CLI commands and flake support.
What is a flake? Over simplified Link to heading
If a
git repo
has a flake.nix
file then it’s a flake and
can be built. Flakes expect to be inside a git repo and
ignore any file not tracked by git by-default.
-
If you run
nix flake init
it’ll use the default template to create a flake in your current directory. -
nix flake show templates
shows you what other templates you can use.
e.g.
nix flake init -t templates#simpleContainer
.
nix build
for instance looks in
outputs
for
defaultPackage.<system>
. Flakes allow
creating operating system specific changes to how packages are
built right inside the flake file. There is a flake called
flake-utils
which lets you actually loop over all
the default systems (like Linux x86, Linux Arm, macOS x86, macOS
arm) among other things.
nix develop
is the replacement for
nix-shell
and expects
devShell.<system>
to be configured otherwise
it looks at defaultPackage.<system>
.
Jumping ahead a bit: Defining and building a
NixOS configuration in a
flake is a simple as creating a
nixosConfigurtion.<machinename>
in the
outputs
then you using
nixos-rebuild build --flake .#<machinename>
to build that configuration. You can also build configurations
for another machine and switch to it:
nixos-rebuild switch --flake .#remotemachine --target-host
remote-hostname --build-host localhost
Enable Nix Flakes Link to heading
Depending how you’re using Nix there are a few ways to
enable Nix Flakes, but typically you want to set the following
configuration variable in your nix.conf
(it’s
easier to use ~/.config/nix/nix.conf
rather than
edit the system /etc/nix/nix.conf
).
experimental-features = nix-command flakes
If you’re using lnl7/nix-darwin or NixOS there will be options to configure nix like this
({ config, pkgs, ... }: {
imports = [ ./hardware-configuration.nix ];
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# ...
}
If you’re simply using nix + home-manager on a Linux or
macOS machine you can create a
.config/nix/nix.conf
and put the line above into
that file.
NixOS Link to heading
Given a configuration provide the set of boot loader, kernel, and File System Hierarchy you desire and Nix can provide it. Thanks to it having lazy evaluation and smart caching from hashing all the contents of the derivations building a different operating system configuration could take seconds.
NixOS’s minimal ISO is now fully reproducible1
Configuring NixOS Link to heading
Configuring NixOS is a little bit like feast or famine.
Sometimes a very complicated thing is literally one line and
always works and other times you need to dig deeply into the
.nix
files of nixpkgs to figure out how it even
works and how you can, maybe, change it to work for you for now.
Typically you’re changing the
/etc/nixos/configuration.nix
file for system things
and using home-manager
and
~/.config/nixpkgs/home.nix
for things related to
your user.
Basically I use one for things like Chrome, Firefox, my editors,
ssh config and etc related to my user and I use
configuration.nix
for system wide configuration
like the Kernel, networking, essential utils, etc.
Boot Link to heading
Hiding the output while NixOS starts is as simple as adding
boot.plymouth = { enable = true; };
to your
configuration.
Dual Boot Windows Link to heading
On my desktop I have Windows installed on one drive and NixOS installed on another. I use zfs for my NixOS drive. To be able to boot Windows on another Disk you must use GRUB 2 instead of simply using systemd-boot (which is simpler and faster, but again doesn’t support this).
My config looks like this:
{
boot.loader.systemd-boot.enable = false;
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.efi.efiSysMountPoint = "/boot";
boot.supportedFilesystems = [ "zfs" ];
boot.loader.grub = {
devices = [ "nodev" ];
efiSupport = true;
enable = true;
version = 2;
# useOSProber = false;
extraEntries = ''
menuentry "Windows" {
insmod part_gpt
insmod fat
insmod search_fs_uuid
insmod chain
search --fs-uuid --set=root XXXX-XXXX
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
'';
};
}
OS Prober did not work for me so I added an entry manually. When
looking for the values to replace XXXX-XXXX
make
sure to pick the EFI volume (usually around 500MB and at the end
of the drive) because otherwise it won’t work.
You can use something like
lsblk -o name,label,partlabel,uuid,size
to see what
the UUID is for the partition you need.
Warning: I’ve heard that Windows can get confused when doing major updates and screw up the EFI for NixOS instead of updating the one on its drive if it’s not the one which gets tried by the BIOS first. I haven’t run in to this yet, but it’s a known issue. Hopefully I can write some notes about fixing Windows EFI partitions later.
Desktop Link to heading
Some packages and extensions to install:
-
xsel
is a good tool for using clipboard from the terminal likepbcopy
in macOS -
ddcutil
is a great tool for controlling your monitors.-
This doesn’t work yet, but it probably will soon:
Recommended to install
gnomeExtensions.brightness-control-using-ddcutil
to control from Gnome tray
-
This doesn’t work yet, but it probably will soon:
Recommended to install
-
gnomeExtensions.screenshot-tool
is great, but requiresgjs
. Otherwise works really nicely for making screenshots quickly.
Networking Link to heading
While working on my NixOS Router project I’ve learned a lot about setting up networks via NixOS as well as needed Kernel modules to do things.
I will add some notes later on about things I learned trying to
enable tc_cake
, creating multiple IP networks,
setting up NATs, and creating port forwards. There is also some
stuff to write in here about managing BIND and DHCP for internal
networking stuff.
Setup tc_cake
Link to heading
tc_cake
which I used for my NixOS router project to help improve my
internet latency.
Was very difficult because I made my life difficult by configuring NixOS too securely making it hard to test changes without rebooting (and therefore kicking me out of my SSH session).
Configuring Nix for macOS Link to heading
- nix on macOS for new people https://stephank.nl/p/2020-06-01-a-nix-primer-by-a-newcomer.html
Configuring Nix for Hyper-V Link to heading
-
Discussion on NixOS reproducibility https://news.ycombinator.com/item?id=27573393 ↩︎