NixOS: Difference between revisions

From Leo's Notes
This page was last edited on 16 January 2022, at 07:09.
mNo edit summary
No edit summary
Line 1: Line 1:
NixOS is a Linux distribution based upon the Nix package manager. The idea is to build a immutable system from a modular and purely functional specification.  Software, configuration files, scripts, etc. are generated from a specification. This method of creating a system ensures that everything comes up deterministically and reproducibly.  Alterations to configuration files are also defined in this specification, allowing for easy traceability of configuration file changes. Upgrades involve updating the specification file and then rebuilding the system which in essence allows software to update atomically.  
NixOS is a Linux distribution based upon the Nix package manager. The primary feature of NixOS is the ability to configure the entire system (packages, configurations, accounts, etc) using a purely functional specification file. By leveraging the features provided by the Nix package manager, NixOS can also easily roll back to a previous system configuration and specific software versions almost immediately.  


This is in contrast to the conventional way of managing a system: an imperative way where where packages are installed and updated in place and configuration files are created and edited after installation.
== Introduction to Nix ==
The Nix package manager is the primary selling feature of NixOS. To understand how to use NixOS, we first have to understand what the Nix package manager does.


== Nix ==
Unlike a traditional package manager where package files are written directly to the system, Nix writes package files to a central location called the Nix store. Once a package is installed, Nix updates the system environment by building a bunch of symlinks to the appropriate files within the Nix store, thereby 'faking' the system environment.  The benefit to this approach is that different version of the same package can be installed in parallel, allowing for near instantaneous upgrades (since it takes next to no time to update the symlinks) and that a system's environment can be rolled back atomically with ease.
Central to the idea of NixOS is the Nix package manager. Packages (also known as derivations) are stored under {{code|/nix/store/hash-name-version}}, where a cryptographic hash uniquely identifies the derivation.  All files under the Nix store are immutable.  For example, bash would be in {{code|/nix/store/s4zia7hhqkin1di0f187b79sa2srhv6k-bash-4.2-p45/}}, under its own {{code|bin/bash}} directory.  NIX will arrange binaries in your PATH appropriately.


This method of handling software packages allows for multiple versions of the same software package to be installed. Any dependencies are handled by installing the exact version of the dependency and then ensuring the proper link.  This means that you could run mysql 5.2 with glibc-2.18, and mysql 5.5 with glibc-2.19 all in the same system.
=== Packages under the hood ===
Nix packages are also known as '''derivations''' and are stored under {{code|/nix/store/hash-name-version}}. All packages are named with a cryptographic hash that uniquely identifies the package name and version number. All package files are also immutable and should not be changed once it is installed. The Nix package manager will arrange the binaries and libraries in your environment appropriately (by tweaking the PATHs) based on your global system and per-user configuration.  


Package upgrades are handled by installing the newer version on the system and then switching to that newer version.
The Nix database is stored at {{code|/nix/var/nix/db}}.


The Nix database is stored at {{code| /nix/var/nix/db}}
=== Dependencies are called closures ===
Closures of a derivation is a recursive list of all dependencies that are required.
 
You can generate a list by running: {{code|nix-store -qR `which man`}} or {{code|nix-store -q --tree `which man`}}
 
=== Package repositories are called channels ===
If you ever dealt with Anaconda (the software manager), you will be familiar with the concept of channels. You can think of channels as a package repository. Nix has a few channels which you can see at https://nixos.org/channels:
* Stable (eg. nixos-20.03): minor bug fixes, no major kernel changes
* Unstable (eg. nixos-unstable): Main development branch
* Small (nixos-20.03-small, nixos-unsable-small): Contains fewer binary pakages and faster update cycles. Intended for server environments.


== Profile ==
=== Profiles and generations ===
A profile in Nix gathers separate components spread among different paths into a unified path. They are versioned (known as a generation) that allows for easy roll back.
Profiles define what packages and what version of packages should be available in your environment. Based on your selected profile, Nix will gather all the necessary components spread among different paths into a single unified path. When we upgrade a system, we also need to update a profile. In order to facilitate rolling back to a previous version, Nix slaps a version number to a profile and calls it a generation. After a system upgrade, if we ever need to roll back to the system prior to the upgrade, we can reboot into an older generation in the Grub menu.


Profiles are stored under {{code|~/.nix-profile}} which is a symlink to {{code|/nix/var/nix/profiles/default}}. Different generations of the profile are stored {{code|/nix/var/nix/profiles/}}.
Profiles are stored under {{code|~/.nix-profile}} which is a symlink to {{code|/nix/var/nix/profiles/default}}. Different generations of the profile are stored {{code|/nix/var/nix/profiles/}}.
Line 19: Line 29:
nix-env handles the profiles and all the symlinks in this location. paths are also merged by nix-env.
nix-env handles the profiles and all the symlinks in this location. paths are also merged by nix-env.


== Introduction ==
== Cheatsheet ==
Various commands that were introduced in Chapter 3 of the Nix Pills.
Various commands that were introduced in Chapter 3 of the Nix Pills.


Line 56: Line 66:
| Uninstalls everything from the current environment. You can recover this by running nix-env from the nix store and reinstalling the nix-env derivative or roll back the environment generation.
| Uninstalls everything from the current environment. You can recover this by running nix-env from the nix store and reinstalling the nix-env derivative or roll back the environment generation.
|}
|}
Closures of a derivation is a recursive list of all dependencies that are required.
{{code|nix-store -qR `which man`}} or {{code|nix-store -q --tree `which man`}}
Channels are basically like repos. You can see channels at https://nixos.org/channels. There are:
* Stable (eg. nixos-20.03): minor bug fixes, no major kernel changes
* Unstable (eg. nixos-unstable): Main development branch
* Small (nixos-20.03-small, nixos-unsable-small): Contains fewer binary pakages and faster update cycles. Intended for server environments.


{| class="wikitable
{| class="wikitable
Line 85: Line 86:


== Installing NixOS ==
== Installing NixOS ==
The installation steps are listed in section 2.3 of the manual.
The installation steps are listed in [https://nixos.org/manual/nixos/stable/index.html#sec-installation section 2.3 of the manual]. I'll go over the steps to NixOS set up on a non-UEFI system.
 
After downloading the NixOS install ISO and booting it, you will be greeted with a KDE login screen. Log in as nixos without a password. Open a terminal and {{code|sudo su}} into root. From there, configure the primary disk (/dev/sda) with a single partition and format it to ext4. Mount the partition in /mnt and then run:


If you want to use emacs to edit the initial config, run {{code|nix-env -f '<nixpkgs>' -iA emacs}} first.
Download the NixOS ISO and boot it. Start a terminal and become root using <code>sudo su</code>. Format the primary disk with at least one root partition and optionally a swap partition. You may either use fdisk or gparted. Mount the primary root partition as /mnt.


{{highlight|lang=terminal|code=
{{Highlight
# fdisk /dev/sda  # Create a partition for the system, another for swap if desired
| code = # fdisk /dev/sda  # Create a partition for the system, another for swap if desired
# mkfs.ext4 -L nixos /dev/sda1
# mkfs.ext4 -L nixos /dev/sda1
# mount /dev/sda1 /mnt
# mount /dev/sda1 /mnt
# nixos-generate-config --root /mnt  
| lang = terminal
}}{{Info
| title = Change the editor
| message = If you want to use emacs to edit the initial config, run nix-env -f '<nixpkgs>' -iA emacs first.
}}
 
Setup NixOS by generating an initial configuration file. Edit the configuration file and ensure that the boot loader is set up. Run <code>nixos-install</code> to finish the installation.
 
{{highlight
| lang = terminal
| code = # nixos-generate-config --root /mnt  
# cd /mnt  # You can take a look at what's generated
# cd /mnt  # You can take a look at what's generated



Revision as of 07:09, 16 January 2022

NixOS is a Linux distribution based upon the Nix package manager. The primary feature of NixOS is the ability to configure the entire system (packages, configurations, accounts, etc) using a purely functional specification file. By leveraging the features provided by the Nix package manager, NixOS can also easily roll back to a previous system configuration and specific software versions almost immediately.

Introduction to Nix

The Nix package manager is the primary selling feature of NixOS. To understand how to use NixOS, we first have to understand what the Nix package manager does.

Unlike a traditional package manager where package files are written directly to the system, Nix writes package files to a central location called the Nix store. Once a package is installed, Nix updates the system environment by building a bunch of symlinks to the appropriate files within the Nix store, thereby 'faking' the system environment. The benefit to this approach is that different version of the same package can be installed in parallel, allowing for near instantaneous upgrades (since it takes next to no time to update the symlinks) and that a system's environment can be rolled back atomically with ease.

Packages under the hood

Nix packages are also known as derivations and are stored under /nix/store/hash-name-version. All packages are named with a cryptographic hash that uniquely identifies the package name and version number. All package files are also immutable and should not be changed once it is installed. The Nix package manager will arrange the binaries and libraries in your environment appropriately (by tweaking the PATHs) based on your global system and per-user configuration.

The Nix database is stored at /nix/var/nix/db.

Dependencies are called closures

Closures of a derivation is a recursive list of all dependencies that are required.

You can generate a list by running: nix-store -qR `which man` or nix-store -q --tree `which man`

Package repositories are called channels

If you ever dealt with Anaconda (the software manager), you will be familiar with the concept of channels. You can think of channels as a package repository. Nix has a few channels which you can see at https://nixos.org/channels:

  • Stable (eg. nixos-20.03): minor bug fixes, no major kernel changes
  • Unstable (eg. nixos-unstable): Main development branch
  • Small (nixos-20.03-small, nixos-unsable-small): Contains fewer binary pakages and faster update cycles. Intended for server environments.

Profiles and generations

Profiles define what packages and what version of packages should be available in your environment. Based on your selected profile, Nix will gather all the necessary components spread among different paths into a single unified path. When we upgrade a system, we also need to update a profile. In order to facilitate rolling back to a previous version, Nix slaps a version number to a profile and calls it a generation. After a system upgrade, if we ever need to roll back to the system prior to the upgrade, we can reboot into an older generation in the Grub menu.

Profiles are stored under ~/.nix-profile which is a symlink to /nix/var/nix/profiles/default. Different generations of the profile are stored /nix/var/nix/profiles/.

nix-env handles the profiles and all the symlinks in this location. paths are also merged by nix-env.

Cheatsheet

Various commands that were introduced in Chapter 3 of the Nix Pills.

Command Description
nix-env Manages environments, profiles, and their generations
nix-env -i hello installs the hello environment
nix-env --list-generations lists all environment generations
nix-env -q lists all derivations
nix-env -q --references `which hello` shows all derivations that are required by the given binary
nix-env -q --referrers `which hello` shows all derivations that are dependent on the given binary
nix-env --rollback rolls back the generation by one
nix-env -G 3 sets the environment generation to the given generation (3)
nix-env -u upgrades all packages in the environment
nix-env -e '*' Uninstalls everything from the current environment. You can recover this by running nix-env from the nix store and reinstalling the nix-env derivative or roll back the environment generation.
Command Description
nix-channel --list lists all channels. This is configured in ~/.nix-channels
nix-channel --update Synchronizes the channel repo data
nix-channel --add https://nixos.org/channels/nixos-20.03 nixos Adds a channel

To upgrade the system, you can add a new channel and then run nixos-rebuild switch --upgrade. This is equivalent to nix-channel --update nixos ; nixos-rebuild switch.

Remember, users can have their own channels. Only root can update channels that will affect the entire system (and /etc/nixos/configuration.nix).

Installing NixOS

The installation steps are listed in section 2.3 of the manual. I'll go over the steps to NixOS set up on a non-UEFI system.

Download the NixOS ISO and boot it. Start a terminal and become root using sudo su. Format the primary disk with at least one root partition and optionally a swap partition. You may either use fdisk or gparted. Mount the primary root partition as /mnt.

# fdisk /dev/sda  # Create a partition for the system, another for swap if desired
# mkfs.ext4 -L nixos /dev/sda1
# mount /dev/sda1 /mnt
Change the editor
If you want to use emacs to edit the initial config, run nix-env -f '<nixpkgs>' -iA emacs first.


Setup NixOS by generating an initial configuration file. Edit the configuration file and ensure that the boot loader is set up. Run nixos-install to finish the installation.

# nixos-generate-config --root /mnt 
# cd /mnt   # You can take a look at what's generated

## Review the configuration file. 
## BIOS systems: ensure that boot.loader.grub.device is set
## UEFI systems: ensure that boot.loader.systemd-boot.enable is set to true
# vi /mnt/etc/nixos/configuration.nix

## When you're ready, set up the system
# nixos-install

The nixos-install command will download all the required derivations, set up the boot loader, etc. The last step of the command will prompt for a root password. Once complete, you should be able to reboot into the new installation without the ISO image.

After the system comes up, you should be able to log in as root with the password you provided in the installation step. You can change the system by editing the same /etc/nixos/configuration.nix file as you did originally. For changes to apply, run nixos-rebuild switch. Any system services that are affected should be automatically restarted by this rebuild process. If so desired, you can make a separate profile for the rebuild with the -p profile flag so that it shows up as a separate grub option.

You may also use nixos-rebuild test to test the configuration without making it boot by default. You may also use nixos-rebuild boot to do everything as switch did but without switching over until the next reboot.

Administration

All options that can be set are listed in the NixOS Manuel.

Section 5 through 42 covers some of the administration tasks:

Package Installation

For system-wide packages, you can define them in the configuration.nix configuration file.

environment.systemPackages = with pkgs; [ 
   wget vim 
];

## or

environment.systemPackages = [ pkgs.wget pkgs.vim ];

Rerun nixos-rebuild switch to add/remove packages.

Alternatively, packages can be installed or removed using nix-env: Install: nix-env -iA nixos.wget Uninstall: nix-env -e wget

Any changes to the environment is versioned (a new generation for each change) and can be rolled back.

System Upgrade

See channels.

Update the channel first

nix-channel --update nixos

Then upgrade all packages

nix-env -u '*'

Automatic updates can be enabled by adding to configuration.nix:

system.autoUpgrade.enable = true;
system.autoUpgrade.allowReboot = true;


User Management

By default, entries in /etc/passwd and /etc/group are added ad-hoc by the system. You could use useradd/groupadd to modify the system and have them persist (though, this defeats the point of NixOS).

You can ask NixOS to rewrite the /etc/passwd and /etc/group files as required by the system configuration by setting the

users.mutableUsers = false

To have NixOS create the user for you, define the following in the configuration.nix file:

users.users.alice = {
  isNormalUser = true;
  home = "/home/alice";
  description = "Alice Foobar";
  extraGroups = [ "wheel" "networkmanager" ];
  openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ];
};

Re-run nixos-rebuild to apply.

Note: Password is set using passwd and is persistent with the system.

Networking

The default configuration uses dhcpd. A static address can be set for a specific interface.

networking.interfaces.eth0.ipv4.addresses = [ {
  address = "192.168.1.2";
  prefixLength = 24;
} ];

networking.defaultGateway = "192.168.1.1";
networking.nameservers = [ "8.8.8.8" ];