Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Linux Day Prato 2025: NixOS spiegato ammiocuggi...

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

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à!

NixOS è facile da installare ma il suo linguaggio Nix è oscenamente difficile da capire e gestire. In questo talk cerco di spiegarlo in parole semplici con concetti conosciuti da altre distribuzioni Linux, e dando soluzioni concrete per i problemi comuni.

Vieni a imparare le basi, vedere una demo funzionante, generarne una tu stesso in pochi minuti e portare la configurazione con te da questa conferenza.

Original slides at: https://slides.com/bittner/linuxday-2025-nixos-for-human-beings

Avatar for Peter Bittner

Peter Bittner

October 25, 2025
Tweet

More Decks by Peter Bittner

Other Decks in Technology

Transcript

  1. 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
  2. $ 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`? 👆
  3. $ 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 ... Home Manager
  4. $ 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! 💣
  5. 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)
  6. $ 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) 📦
  7. $ 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
  8. $ 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)
  9. 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
  10. { lib, ... }: imports = [ ]; options =

    { }; config = { }; 1 2 { 3 4 ./file.nix 5 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.nix 8 ]; 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
  11. $ 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
  12. $ 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 ... (... after breaking the setup)
  13. $ 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)
  14. $ 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)
  15. $ 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
  16. $ 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
  17. $ 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
  18. 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
  19. Manage user-specific software and settings ("dotfiles") standalone vs. NixOS module

    has own (most matching with nixpkgs) configuration options
  20. 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 💾
  21. 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. 🚀
  22. $ 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: documentation 1 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
  23. 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!