Linux Day Prato 2025: NixOS spiegato ammiocuggino - NixOS for Human Beings

bittner 12 views 36 slides Oct 25, 2025
Slide 1
Slide 1 of 36
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36

About This Presentation

NixOS è una bellissima distribuzione che ti permette di ricreare il tuo sistema configurato come attualmente da zero entro solo minuti. È 'Linux with configuration management', tutto integrato. È utile per noi privati ma anche per le aziende. Perché non lo usano ancora tutti? Eh, già!

...


Slide Content

NixOS for Human
Beings

Image stolen from:
bmcgee.ie

1. You know The Language
2. You know Your Use Case

·
@peterbittner @bittner @bittner@bittner
Peter Bittner. Developer.
Of People, Companies and Code. Painless Software

Source:  (p. 81)Nix: A Safe and Policy-Free System for Software Deployment

6 lambdas that form
a snowflake
Source:  (2025)NixOS Logo and Branding Update

_ _ _ _ _ _
_ _
_ _ _
_

NixOS for the Impatient
??????

$ tree /etc/nixos
/etc/nixos
|-- configuration.nix
`-- hardware-configuration.nix # Edit this configuration file to define what should
{ config, pkgs, ... }:

{
imports = [
./hardware-configuration.nix
];

boot.loader.systemd-boot. enable = true;

networking.hostName = "nixos";
networking.networkmanager. enable = true;

time.timeZone = "Europe/Rome";
i18n.defaultLocale = "en_US.UTF-8";

programs.firefox.enable = true;

environment.systemPackages = with pkgs; [
vim
];
}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# Do not modify this file! It was generated by ‘nixo
{ config, lib, pkgs, modulesPath, ... }:

{
boot.kernelModules = [ "kvm-intel" ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/5a42e090-37b7" ;
fsType = "ext4";
};
networking.useDHCP = lib.mkDefault true;
}1 2 3 4 5 6 7 8 9 10 11 How strict are you in not editing
`hardware-configuration.nix`?
??????

$ nixos-rebuild --sudo {switch|boot| test} [--file ...|--flake ...]
...
Done. The new configuration is /nix/store/j6a42... Add more systemPackages
Configure more programs (system-wide)
Add more users and set their (initial) passwords
Manage user-specific config & programs ( )
Move config away from /etc/nixos/ (e.g. your home directory)
Split up config file when it gets too big
Start using Git, maybe ... m
Home Manager

$ ls -lAF --color /nix/store
total 7355364
dr-xr-xr-x 1 root root 6 1 Jan 1970 000bmy9k246z4bdywjkdi6hbybah9z0j-user/
dr-xr-xr-x 1 root root 0 1 Jan 1970 000fdw5ijqc8nhgnnawfy11vxf1hi8rw-system-generators/
-r--r--r-- 2 root root 3599 1 Jan 1970 000hxqh70ck7sjhdvcn66zdsyp2yprpb-source.drv
-r--r--r-- 2 root root 2221 1 Jan 1970 000hy9cqahi1rwy2mx3yak8dq02pa5ih-gst-devtools-1.26.5-vendor.drv
-r--r--r-- 2 root root 3146 1 Jan 1970 000nzak0hrcsl7d2kf3l6d544p7kyrf2-crate-num_threads-0.1.7.tar.gz.drv
-r--r--r-- 2 root root 2223 1 Jan 1970 000skmmf43a4vnxnc775s78psjr96d54-001-fix-rpath.patch.drv
-r--r--r-- 2 root root 4493 1 Jan 1970 000x39hj0g61mkp15xgkz27j7fkzkh8h-CVE-2022-48174.patch.drv
-r--r--r-- 2 root root 3615 1 Jan 1970 0010xx2b5k2kxq0c5b3pwq3bby9rdk94-source.drv
-r--r--r-- 2 root root 3314 1 Jan 1970 0015pxy9jsaxgq729bfc5ikn9n1wssbi-gnome-font-viewer-48.0.drv
... Folders = package data (build result)
.drv files = package build actions (derivation)

All packages are uniquely kept in the Nix Store.
There are no /bin, /sbin, /usr, etc. directories!
??????

Derive(
[
("debug", "/nix/store/hichgz37f1327dfi0saqll0lpbimvfw0-coreutils-9.7-debug" , "", ""),
("info", "/nix/store/x13fzfc1lv1nbmszq25kajhsxzwzyd6r-coreutils-9.7-info" , "", ""),
("out", "/nix/store/psy9v2asypgl9ylg8cnzkixc7fv0snj0-coreutils-9.7" , "", ""),
],
[
("/nix/store/05q48dcd4lgk4vh7wyk330gr2fr082i2-bootstrap-tools.drv" , ["out"]),
("/nix/store/6wnz883nsn7hz72yqbjzj0pg4zlqcfza-xz-5.8.1.drv" , ["bin"]),
("/nix/store/ayrji7q39s4z0vnx6ksryxp2jvl5dl20-attr-2.5.2.drv" , ["dev"]),
...
],
...
[
...
("strictDeps", ""),
("system", "x86_64-linux"),
("version", "9.7"),
],
)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Package build action (generated)
Nix expression ➜ Derivation

technical recipe (build activities)

$ tree /nix/store/00zrahbb32nzawrmv9sjxn36h7qk9vrs-bash-5.2p37/
/nix/store/00zrahbb32nzawrmv9sjxn36h7qk9vrs-bash-5.2p37
├── bin
│   ├── bash
│   └── sh -> bash
└── lib
└── bash
├── accept
├── basename
├── csv
├── cut
├── dirname
...
├── sync
├── tee
├── truefalse
├── tty
├── uname
├── unlink
└── whoami Package (read-only file tree) ??????

$ ls -l /run/current-system/sw
lrwxrwxrwx 2 root root 55 1 Jan 1970 /run/current-system/sw -> /nix/store/1n2l2vz3sdzgxjilhqzndff9lmyvdg8c-system-path

$ ls -l /run/current-system/sw/
bin/ etc/ lib/ sbin/ share/

$ ls -l /run/current-system/sw/bin
...
lrwxrwxrwx 8 root root 70 1. Jan 1970 zstdcat -> /nix/store/n0crcrrdb0jlfmwidnv150vm33611xs3-zstd-1.5.7-bin/bin/zstdcat
lrwxrwxrwx 8 root root 71 1. Jan 1970 zstdgrep -> /nix/store/n0crcrrdb0jlfmwidnv150vm33611xs3-zstd-1.5.7-bin/bin/zstdgrep
lrwxrwxrwx 8 root root 71 1. Jan 1970 zstdless -> /nix/store/n0crcrrdb0jlfmwidnv150vm33611xs3-zstd-1.5.7-bin/bin/zstdless
lrwxrwxrwx 8 root root 69 1. Jan 1970 zstdmt -> /nix/store/n0crcrrdb0jlfmwidnv150vm33611xs3-zstd-1.5.7-bin/bin/zstdmt System Packages $ ls -l /etc/static/profiles/per-user/
lrwxrwxrwx 2 root root 60 1 Jan 1970 peter -> /nix/store/z8h5rbv29p6a7rxdjr31b3z6pwp0giv7-user-environment

$ tree /etc/static/profiles/per-user/peter/bin
/etc/static/profiles/per-user/peter/bin
├── accessdb -> /nix/store/qyiyrbrh1wnpa43w4vqn9r89w4q8b4bb-home-manager-path/bin/accessdb
├── apropos -> /nix/store/qyiyrbrh1wnpa43w4vqn9r89w4q8b4bb-home-manager-path/bin/apropos
├── catman -> /nix/store/qyiyrbrh1wnpa43w4vqn9r89w4q8b4bb-home-manager-path/bin/catman
├── codium -> /nix/store/qyiyrbrh1wnpa43w4vqn9r89w4q8b4bb-home-manager-path/bin/codium
├── ghostty -> /nix/store/qyiyrbrh1wnpa43w4vqn9r89w4q8b4bb-home-manager-path/bin/ghostty
├── git -> /nix/store/qyiyrbrh1wnpa43w4vqn9r89w4q8b4bb-home-manager-path/bin/git
... User Packages

$ nix store gc -v
finding garbage collector roots...
deleting garbage...
deleting '/nix/store/v5cqs341xjgpqsx5c8pc2h8hz9mvwv3b-source'
deleting '/nix/store/zmnlm7rglapnp1mm8mz25jlbjgsckniy-nixos-system-bittner-25.11.20250719.c87b95e.drv'
deleting '/nix/store/x302k0rbgrry7vm94mkzvz1pzj9b2ng2-etc-nix-registry.json'
deleting '/nix/store/i1l6nqcknyzgpg77h3ysf7axspzhqzsl-nixos-system-bittner-25.11.20250719.c87b95e.drv'
deleting '/nix/store/al0hg0j2x9ikrniqxfmrfc0vjg3zxda5-etc.drv'
deleting '/nix/store/2q5svikixkmx7mfh3l1xrx4bm99a8ksr-etc.drv'
deleting '/nix/store/9ndq6wxadmlp85y22pcw92bbmdkf594y-etc-nix-registry.json.drv'
deleting '/nix/store/182c2qj20sfspzxcshd6p051qdx3mx5j-source'
...
deleting '/nix/store/cdirisw2j68pmr3anwvzy43q3zyfks44-plymouth-initrd-themes'
deleting '/nix/store/i69ii1nris373wqnzbl7hgmbns9f3f55-x86_64-unknown-linux-musl-gcc-14.3.0-lib'
deleting '/nix/store/i8zh98ynh9bn3gz244pispp81dzmw8n6-activation-script'
deleting '/nix/store/8q3vz0vk5bllxrqa0v5s1fxp9a0jmdpy-boot.json'
deleting unused links...
note: currently hard linking saves 99903.89 MiB
73449 store paths deleted, 34381.53 MiB freed Cleanup of unreferenced packages (and derivations)

42 number.nix "foo" string.nix true boolean.nix ~/.local/bin path.nix [ "foo" "bar" 42 false ] list.nix { target = /etc/nixos; foo = 42; } attribute-set.nix x: x + 1 function.nix {
x = import ./number.nix;
} imported-value.nix {
# negation
truth = !false;

# string and paths
a_str = "Dirs" + ./.config/user;
a_path = /etc + "/nixos";

# list concatenation
l = [ 1 2 3 ] ++ [ "four" "five"];

# logical and, logical or
m = true && false; n = true || false;

# update attribute set
s = { x = 1; } // { y = 1; x = 2; };

# has attribute (attribute set member)
h = { x = 42; } ? x;
} operators {
# numbers
a = 1; f = 3.14;

# strings
text = "Hello Pi! ${f}";
multi_line = ''
Very long text ... with ${a}
'';

# paths
x = /absolute/path/to
y = ./relative/path
z = ~/.config # path in home dir
} datatype features {
# available = builtins;
yes = true; no = false; nothing = null;
system = builtins.currentSystem;
epoch = builtins.currentTime;
packages = builtins.storeDir;
paths = builtins.nixPath;
language = builtins.langVersion;
version = builtins.nixVersion;
} built-in constants {
d = builtins.readDir;
f = builtins.readFile;
e = builtins.getEnv "HOME";
s = builtins.substring 0 3 "nixos";
...
} built-in functions

{ lib, ... }:
imports = [
];
options = {
};
config = {
};1 2 {3 4 ./file.nix5 6 7 8 magicNumber = lib.mkOption {9 type = lib.types.number;10 default = 3.14;11 };12 13 14 15 boot.loader.grub. enable = true;16 17 }18 module.nix let
preference = "GNOME";
in
default = preference;{ lib, ... }:1 2 3 4 5 {6 imports = [7 ./file.nix8 ];9 10 options = {11 desktop.style = lib.mkOption {12 type = lib.types.enum [ "Windows" "macOS" "GNOME" ];13 14 };15 };16 }17 variables.nix {
console.keyMap = "it";

services.xserver.xkb = {
layout = "it";
variant = "";
};
}1 2 3 4 5 6 7 8 implicit-config.nix

$ nix flake show templates
$ nix flake init -t 'templates#utils-generic'
$ nix flake update
$ nix flake check
$ nix flake show description = "Linux Day flake";
inputs = {
outputs = { self, nixpkgs }: {{1 2 3 4 nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable" ;5 nixos-hardware.url = "github:NixOS/nixos-hardware?ref=master" ;6 };7 8 9 nixosConfigurations = nixpkgs.lib.mapAttrs mkSystem systems;10 };11 }12 flake.nix Recommendation

$ nixos-rebuild --sudo --file ~/.config/nixos/default.nix
...
Done. The new configuration is /nix/store/j6a42... Add more software (systemPackages, programs)
Split up config file when it gets too big
Start using Git, maybe ... m (... after breaking the setup)

$ nix run nixpkgs#git
...
$ nix shell nixpkgs#cowsay nixpkgs#lolcat
$ cowsay 'Hello Linuxday!' | lolcat
_________________
< Hello Linuxday! >
-----------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| || Install and run programs ad-hoc ("because I can!")
Split up config file when it gets too big
Switch to Flake-based NixOS setup (to fight flaky updates)
Maybe put configuration under version control (Git)

$ nixos-rebuild switch --sudo --flake gitlab:painless-software/nixos-config
...
Done. The new configuration is /nix/store/j6a42...

$ nixos-rebuild test --sudo --flake .
building the system configuration...
Place your finger on the fingerprint reader
activating the configuration...

$ nix flake check
$ nix flake show
$ nix flake update Split up config file when it gets too big
Use Flake-based setup (for more control about what is installed)
Manage nixos-config with Git, install using remote URL
Automate system updates (e.g. system.autoUpgrade)

$ nix flake show templates
...
$ nix flake init -t templates #...
...

$ nix develop
...
$ go version
go version go1.25.1 linux/amd64 Python, Ruby, NodeJS, Rust, Golang, LaTeX, ...
Add a Flake file to every (serious) project
Use nix develop to start a development shell {
description = "A simple Go package" ;
inputs.nixpkgs.url = "nixpkgs/nixos-25.11" ;
outputs = { self, nixpkgs }:
{
packages = forAllSystems (system:
let
pkgs = nixpkgsFor. ${system};
in
...
);
};
devShells = forAllSystems (system:
default = pkgs.mkShell {
buildInputs = with pkgs; [ go gopls gotools go-tools ];
};
);
}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 flake.nix

$ uv python install 3.14 --preview --default
$ which python
/home/peter/.local/bin/python
$ uv python upgrade --preview-features python-upgrade
All versions already on latest supported patch release

$ uv tool install pre-commit
$ uv tool install httpie
$ ls ~/.local/bin
http httpie https pre-commit python
$ uv tool list
...
$ uv tool upgrade --all

$ uvx pyclean
$ uvx copier update Install only uv (but not any Python!) via systemPackages
Manage Python versions (and tools) locally using uv
Use nix-ld to fix the dynamic linking problem {
environment = {
localBinInPath = true; # ~/.local/bin in PATH
systemPackages = with pkgs; [
uv # install Pythons in user-space using uv
];
};

programs.nix-ld = {
enable = true;
libraries = with pkgs; [
libelf
libjpg
libpng
];
};
}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 configuration.nix

$ nix shell nixpkgs#nix-init
$ nix-init --url https://github.com/bittner/pyclean
...
$ nix build --file .

$ nix build nixpkgs#hello
$ ls -l
lrwxrwxrwx 1 peter users 56 25 Ott 15:42 result -> /nix/store/9mj...as2fis-hello-2.12.2
$ ./result/bin/hello
Hello, world! Create Nix packages by writing them like a God
Maybe use tooling such as nix-init for "nixification"
Use nix build to build and locally verify a package setup

hosts/ – managed machines
roles/ – classes of machines (abstraction layer)
system/ – system-global configuration
home/ – user configuration
user/ – common user configuration gitlab.com/painless-software/nixos-config

Manage user-specific software and settings ("dotfiles")
standalone vs. NixOS module
has own  (most matching with nixpkgs)configuration options

Declarative disk partitioning

disko-config.nix $ sudo nix run github:nix-community/disko /latest -- \
   --mode destroy,format,mount \
   --flake gitlab:painless-software/nixos-config# example ??????

Flake
Establish execution
entrypoint (e.g.
integrate hosts/).
Consider integrating
QA tools, pre-commit
and CI/CD early.
1.
Home Manager
Allow configuring
settings and installing
software for individual
users.
Consider using LDAP 
for a flexible, host-
independent setup.
3.
Disko
Integrate Disko
configuration. Verify
installation process
end-to-end.
Consider setting up
functional tests with
VMs.
2.
Refine
Delegate host setup to
system/ configuration.
Consider introducing
roles/.
Consolitate home/ 
features in common
user/ modules.
4.
??????

$ copier copy gl:painless-software/cicd/config/nixos nixos-config
...

$ pre-commit install
...

$ git init

$ git add -v .
...

$ pre-commit

$ nix flake check
... gitlab.com/painless-software/cicd/config/nixos Copier template ---
deadnix:
extends: .nix
script: nix run nixpkgs#deadnix -- --fail

statix:
extends: .nix
script: nix run nixpkgs#statix -- check

flake:
extends: .nix
script:
- nix flake check
- nix flake show

disko:
extends: .nix
script: nix run github:nix-community/disko/latest --
--mode destroy,format,mount --dry-run --flake .#generic

tooling:
extends: .megalinter
variables:
FLAVOR: documentation1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .gitlab-ci.yml

Most static backgrounds from Unsplash (CC BY-SA)
Animated backgrounds from GIPHY (CC BY-SA)
Decorative icons are unicode (CC-0)
Less pain, more fun.

Wow!
This presentation
was made entirely
without any AI!