Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

SkyOS :: Sk7Str1p3's NixOS configuration

Note

This hosts system and home configurations are public for your own learning and research. They are not meant to be used with any hardware other than mine. Trying to build and deploy them to other systems without appropriate changes can render your machines unbootable and damage data.

Noticable features

  • 🛡️ Secure Boot (with custom keys)
  • 🧽 Impermanence
  • 🔐 Full disk encryption
  • 🥸 Secrets management for both evaluation and activation time
  • 🎨 Stylix colorscheme
  • 🗃️ Documentation

Hosts Preview

<\images here>

Evaluation time secrets

Some secrets cannot be left in cleartext (e.g time zone, user’s real names), but are required at evaluation time, and in some cases using sops-nix’s template is really inconvenient. To handle this, currently i use strange approach: I manually encrypt files with sops, commit them and manually decrypt. git-agecrypt wasn’t suitable for me. In future, i will replace it with my own implementation of transparent git encryption based on sops.

Also, this used only for secrets which may be safely left in world-readable store. For more sensitive secrets I use sops-nix, which decrypts secrets only at runtime.

Documentation

Docs are generated from comments in .nix files. This results in kind of weird config format, but makes it easier to track configuration changes and add/remove docs as required.

How docs are generated

nixdoc utility enables us to generate documentation from comments in .nix file, like doxygen and rustdoc do.

nixdoc requires this flags:

  • category (derived from file’s path)
  • description (derived from file’s first line if it’s commented)

most hard part is to generate SUMMARY.md. generator uses orderKey of type {num}|{mdPath} and derives indentation from path’s depth, so chapters have proper order.

run nix build .#docBuild to build documentation. run nix run .#docServe to serve documentation site

Flake

Entry point of NixOS configuration

  • Defines external sources and locking their commit, which gives us purity.
  • Declares ready-to-use configurations (e.g. development shells, packages, etc.)

Essentially, flake.nix is like Cargo.toml in Rust or package.json in Node.js, but for an entire operating system.

Flake inputs

Declares configuration’s dependencies. Inputs are sorted by their purpose and functionality. See sub chapters to learn which inputs are intended for.

Warning

Because nix doesn’t support splitting flake inputs into several files, flake.nix is generated via flake-file. Then adding new input, remember running nix run .#write-flake to apply changes!

In next chapters, you’ll see attributes of type flake.inputs.{class}.{input}. Then accessing inputs in repl, remove {class}, so instead of calling e.g. flake.inputs.core.nixpkgs, you call flake.inputs.nixpkgs.

Core Inputs

Essential inputs that form the foundation of the NixOS configuration

flake.inputs.core.nixpkgs

The Core of NixOS, providing packages and modules. Points to nixos-unstable branch for latest features an updates

flake.inputs.core.flake-parts

A modular flake framework that simplifies flake organizing and reduces boilerplate code.

flake.inputs.core.flake-file

Like flake-parts, but for flake inputs

flake.inputs.core.sops-nix

Runtime secrets management.

User inputs

Inputs providing modules or packages for user configurations. Check next chapters to learn more.

flake.inputs.home.home-manager

System for managing a user environment. Allows declarative configuration of user specific (non-global) packages and dotfiles.

flake.inputs.home.stylix

Theming framework for NixOS

User inputs :: Sk7Str1p3

Inputs used by user Sk7Str1p3

flake.inputs.home.Sk7Str1p3.niri

Flake for configuring Niri. Used because home-manager does not support Niri yet.

flake.inputs.home.Sk7Str1p3.spotify

Spotify wrapper (spicetify) with better customization

Development shells

Isolated environments for convenient software development. Provides shells for all languages I use:

  • ❄️ Nix
  • 🦀 Rust (not yet)
  • 🐍 Python (not yet)

Also provides separate shell for configuration development (not yet).

devShells/{name}/default.nix files contain package list (as attrset for documentation comments) and, for some shells, shell hooks. It usually looks like this:

# {language name}
/**
  Some info on shell
* /
pkgs:
{
  /**
    description on foo
  * /
  packages.foo = pkgs.foo;
  /**
    description on bar
  * /
  packages.bar = pkgs.bar

  /**
    comments on shell hook
  * /
  shellHook = ''
    ...
  '';
}

Also, it has templates, so you can use development shell for projects which don’t have their own.

Nix

Basic shell for nix-only projects. Many nix projects have their own devshell, but they don’t install most necessary tools.

devShells.nix.packages.nixd

nix language server

devShells.nix.packages.nil

another one nix language server

devShells.nix.packages.nixfmt

nix formatter

devShells.nix.packages.statix

nix linter

SkyOS

Development shell with tools needed for configuration editing

devShells.nixos.packages.sops

tool for managing runtime secrets. See sops-nix for more info

devShells.nixos.packages.git-agecrypt

tool for managing eval time secrets.

In near future, it’s going to be replaced by my own project which uses sops instead of bare age

devShells.nixos.packages.nixdoc

tool for generating documentation from comments in .nix files

devShells.nixos.packages.mdbook

tool for generating book from md files made by nixdoc

Hosts

Entry point for machines’ configurations.

Each host forder must has the following structure:

└── {hostname}
    ├── about.nix
    ├── configuration.nix
    └── hardware.nix

configuration.nix can be used to override default values, and hardware.nix is used to store hardware-related stuff.

About file

File which keep some info about host. It can have these fiels (may be extended in future):

name

used as networking.hostName value

users

sets machine users. Users must have their configuration defined at users/

Edit this configuration file to define what should be installed on

about

Edit this configuration file to define what should be installed on

Do not modify this file! It was generated by ‘nixos-generate-config’

default

about

Edit this configuration file to define what should be installed on

Do not modify this file! It was generated by ‘nixos-generate-config’

default

default

module

plan

service

stalwart

stalwartM

Users

This module contains users’ configuration which is declared on system level. It includes user’s password, shell, etc. Parameters is imported from about.json in user’s folder. File can have these keys (may be expanded in future):

  • realName: User’s real name (optionally)
  • extraGroups: groups (optionally)
  • shell: User’s shell
  • session: User’s default graphical session (optionally)
  • sshKeys: User’s authorized SSH keys (optionally)

Session must have format of “{type}:{session}” where type is one of co (short for “compositor”) and de (short for “desktop environment”). This type is actually important, because it depends where nix will search corresponding option for enabling your session. If co, it will search it in programs.*, and if de, in services.desktopManager.*

User’s face (optionally)

  • if any, should be located at users/{user}/face.png
  • i prefer store this encrypted, but you can keep it in clear text

User’s password must be stored at users/{user}/password.yaml and encrypted with sops. Format of unencrypted file:

# {your password}
{username}:
  userPassword: {hash}

where {hash} is result of echo {your password} | mkpasswd -s

Wallpapers can be png or jpg format, and must be stored at users/{user}/wallpaper.{ext}