Знаєте це відчуття: сервер «працює здебільшого», але ніхто не може пояснити чому. Правило фаєрволу «тимчасово» змінили у минулому кварталі, параметр ядра відредагували о 2:00 ночі, а розмітка диска — це оскаржувана несподіванка під час наступного збою.
NixOS — це протиотрута, якщо ви ставитесь до нього як до операційної системи, а не як до хобі. Це інсталяція NixOS 25.11 для продакшену, орієнтована на відтворюваність, мінімальний дрейф та той рівень контролю, який ви оціните лише після налагодження зламаного завантажувача в холодному дата-центрі.
Що ви будуєте (і що — ні)
Ви будуєте машину, яку можна перебудувати. Не «перевстановити з нотатками». Перебудувати. З репозиторію. За вимогою. З аудиторським слідом.
Це означає три непорушні принципи:
- Декларативний стан системи: служби, користувачі, пакунки, мережа, файлові системи, параметри ядра.
- Атомарні зміни: ви не «накладаєте патчі», ви будуєте нову генерацію системи і перемикаєтесь на неї.
- Відкат як базова функція: бо продакшен любить сюрпризи, а NixOS їх не шанує.
Чого ви не будуєте: унікальну «сніжинку» з ручними правками в /etc і купою shell-історії. Якщо ви прагнете такого життя — будь-який інший дистрибутив Linux із задоволенням вам його надасть.
Також виправимо одне: NixOS не врятує вас від поганих рішень. Він, натомість, збереже їх і робитиме це відтворювано. Це — риса, а не загроза.
Цікаві факти та контекст (чому це існує)
NixOS не з’явився тому, що хтось хотів ще одну систему ініціалізації для суперечок. Це практичний результат підходу до розгортання програм як задачі функціонального збірного процесу.
8 коротких фактів, які варто знати
- Nix передував контейнерам як інструменту для опсів. Ідеї менеджера пакетів Nix сягають досліджень початку 2000-х про чисто функціональне розгортання.
- /nix/store має властивості, схожі на адресацію за вмістом. Шляхи в сховищі містять хеші, тож можна встановлювати кілька версій та варіантів поруч без конфліктів файлів.
- NixOS робить оновлення системи транзакційними. Нові конфіги будують новий «замкнений набір системи», а для кожної генерації генеруються записи завантаження.
- Відкат вбудований у меню завантаження. Можна завантажити останній відомо-робочий стан навіть коли мережа мертва, а SSH — спогад.
- Конфігурації — це код, а не купа файлів, які складно порівнювати. Ось чому NixOS чудово підходить для узгодженості флоту машин.
- Nixpkgs — одна з найбільших колекцій пакетів. Не тому що це модно, а тому що ізольоване будування Nix масштабується керовано.
- Ідея «декларативної ОС» не була винайдена NixOS, але NixOS її реалізував. Відголоски можна знайти в cfengine/puppet/chef, але NixOS робить саму ОС декларативною.
- Генерації дешевші за традиційні образи. Ви зберігаєте кілька станів системи без клонування дисків, бо сховище дедуплікує вміст.
Цитата (парафразована ідея): Робота над надійністю за Gene Kim неодноразово повторює принцип: робіть зміни малими, зворотними й рутинними. NixOS закладає це у робочий процес ОС.
Рішення, що мають значення: диски, завантаження, секрети, оновлення
Виберіть файлову систему так, ніби ви будете на виклику
Для серверів ви хочете передбачуваного відновлення, зрілих інструментів і моделі відмов, яку ви розумієте. Обирайте за комфортом команди, а не за балами в інтернеті.
- ext4: нудно, стабільно, достатньо швидко. Якщо вам не потрібні снапшоти на рівні ФС, ext4 — «безпечний» вибір.
- Btrfs: снапшоти і субтоми корисні; send/receive допомагає; може бути прекрасним. Але: поважайте його операційні особливості.
- ZFS: найкраще в класі за контрольними сумами, снапшотами та реплікаціями. Також: ви підписуєтеся на дисципліну ZFS (пам’ять, поведінка ARC, здоров’я пулу).
У цьому посібнику використовується корінь на ZFS як шлях «максимального контролю», з примітками для ext4/Btrfs там, де це змінює рішення.
Тільки UEFI, тільки GPT, і без «хитромудрої» розмітки
Використовуйте UEFI + GPT. Створіть розділ EFI System Partition. Тримайте все просто. На хитрощі буде час пізніше, коли у вас з’явиться моніторинг, бекапи й тестова лабораторія.
Flakes: так, якщо немає вагоючої причини не використовувати
Використовуйте flakes для нових інсталяцій. Вони не ідеальні, але стандартизують pinning і композицію. Альтернатива — «канали», що по суті означає «довірся мені, там найновіше».
Секрети: вирішіть зараз, а не потім
Якщо ви розгортаєте щось більше за особистий ноутбук, у вас будуть секрети: SSH host keys, TLS сертифікати, токени, Wi‑Fi PSK, API-ключі. Визначте стратегію секретів до релізу:
- Для невеликих налаштувань: зашифровані файли в git + інструменти на базі age (поширений патерн), розшифровуються під час деплою.
- Для корпоративних налаштувань: інтеграція з реальним бекендом секретів і підключення NixOS-конфігу для отримання під час runtime.
Не зберігайте секрети в загальнодоступних шляхах Nix store. Сховище призначене для відтворюваності, а не для конфіденційності.
Оновлення: оберіть ритм і зафіксуйте його
NixOS спрощує оновлення. Це не означає, що вони безпечні. Вам потрібен ритм:
- Зафіксуйте входи (flake.lock) і оновлюйте свідомо.
- Тестуйте збірки (навіть на хості) перед перемиканням.
- Завжди майте шлях відкату (записи в завантажувачі + попередні генерації).
Жарт №1: Дрейф конфігурації — як ентропія: з нею не посперечаєшся, лише потрібно планувати теплову смерть вашого /etc.
Чеклісти / покроковий план
Передпольотний чекліст (перед завантаженням ISO)
- Визначте файлову систему: ext4, Btrfs чи ZFS. Якщо обираєте ZFS — вирішіть ім’я пулу та структуру датасетів.
- Вирішіть завантаження: UEFI + systemd-boot підходить для більшості. Якщо потрібен Secure Boot — заплануйте це зараз.
- Визначте ідентичність: hostname, статична IP чи DHCP, модель доступу по SSH, адміністративні користувачі та де зберігатимете конфіг (git).
- Визначте канал оновлень: стабільна гілка релізу чи відстеження. Для серверів краще стабільне + планові оновлення.
- Визначте секрети: зашифрований репо, зовнішній менеджер секретів чи ручне забезпечення (як крайній захід).
- Вирішіть віддалене управління: будете встановлювати локально чи через SSH з build-хоста?
Чекліст інсталяції (високорівневий)
- Завантажте ISO NixOS, підтвердіть роботу мережі.
- Розмітьте диски (GPT + EFI + розділ для ZFS).
- Створіть ZFS пул та датасети (або еквіваленти для ext4/Btrfs).
- Змонтуйте файлові системи в /mnt.
- Згенеруйте початкову конфігурацію NixOS.
- Перетворіть структуру на flake-орієнтовану.
- Налаштуйте завантажувач, мережу, користувачів, sshd, час, локаль.
- Встановіть NixOS, встановіть пароль root (або вимкніть пароль і покладіться на SSH-ключі).
- Перезавантажте, перевірте записи завантаження, імпорт ZFS, доступ по SSH.
- Закомітьте конфіг у git. Ставтесь до нього як до інфраструктури.
Постінсталяційний чекліст (перша година)
- Підтвердіть, що записи для відкату існують у меню завантаження.
- Переконайтеся, що ви можете перебудувати та переключитися без помилок.
- Налаштуйте базовий моніторинг (диск, пам’ять, навантаження, здоров’я ZFS).
- Налаштуйте резервне копіювання (снапшоти + реплікація або бекапи файлів).
- Вирішіть, як запускатимуться оновлення (ручний режим, таймер чи CI).
Практичні завдання: команди, очікуваний вивід і рішення
Ось завдання, які я справді виконую. Кожне включає, що означає вивід і яке рішення прийняти далі. Припускаємо, що ви в середовищі інсталятора NixOS, якщо не вказано інше.
Завдання 1: Підтвердити, що ви завантажились у режимі UEFI
cr0x@server:~$ ls /sys/firmware/efi
efivars fw_platform_size
Що це означає: Якщо такий каталог існує — ви в режимі UEFI. Якщо ні — ви завантажилися в режимі legacy BIOS.
Рішення: Якщо UEFI відсутній, перезавантажтеся та виправте налаштування прошивки. Не встановлюйте в режимі legacy, якщо немає дуже вагомого обмеження.
Завдання 2: Ідентифікувати диски та їхню топологію
cr0x@server:~$ lsblk -o NAME,SIZE,TYPE,MODEL,SERIAL,FSTYPE,MOUNTPOINTS
NAME SIZE TYPE MODEL SERIAL FSTYPE MOUNTPOINTS
nvme0n1 953.9G disk Samsung SSD S6ABC123
├─nvme0n1p1 1G part vfat /mnt/boot
└─nvme0n1p2 952.9G part zfs_member
sda 3.6T disk ST4000NM Z4XYZ789
Що це означає: Ви бачите імена пристроїв, розміри і чи існує вже файлова система. Також: перевірте, щоб не збити не той диск.
Рішення: Оберіть ціль установки. Якщо у вас дзеркальна конфігурація для завантаження — потрібні два диски. Якщо це VM — одного достатньо.
Завдання 3: Перевірити таблицю розділів (і очистити при потребі)
cr0x@server:~$ sudo sgdisk -p /dev/nvme0n1
Disk /dev/nvme0n1: 2000409264 sectors, 953.9 GiB
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): 4A5F0B45-7E62-4C6D-A3D2-8D5F7E0C1A1B
Partition table holds up to 128 entries
Number Start (sector) End (sector) Size Code Name
1 2048 2099199 1024.0 MiB EF00 EFI System
2 2099200 2000408575 952.9 GiB BF01 ZFS
Що це означає: GPT присутній. Коди розділів EF00 (EFI) і BF01 (ZFS) — саме те, що нам потрібно.
Рішення: Якщо бачите стару безладну розмітку і ви перевстановлюєте, очистіть мітку диска акуратно (не варто частково використовувати старі розділи, хіба ви не пишете доктрину для майбутнього себе).
Завдання 4: Розмітити диск (приклад для одного диска)
cr0x@server:~$ sudo sgdisk --zap-all /dev/nvme0n1
Creating new GPT entries in memory.
GPT data structures destroyed! You may now partition the disk using fdisk or other utilities.
Що це означає: Старі GPT/MBR дані видалені.
Рішення: Виконуйте лише якщо ви абсолютно впевнені, що вибрали правильний диск.
cr0x@server:~$ sudo sgdisk -n1:1M:+1G -t1:EF00 -c1:"EFI System" /dev/nvme0n1
The operation has completed successfully.
cr0x@server:~$ sudo sgdisk -n2:0:0 -t2:BF01 -c2:"ZFS" /dev/nvme0n1
The operation has completed successfully.
Що це означає: Ви створили 1 ГіБ ESP і розділ ZFS на решту місця.
Рішення: Якщо плануєте гібернацію або спеціальні вимоги до swap — сплануйте відповідний розділ зараз. Інакше тримайте простоту і робіть swap у вигляді файлу пізніше (або не використовуйте його, залежно від навантаження).
Завдання 5: Відформатувати EFI System Partition
cr0x@server:~$ sudo mkfs.fat -F 32 -n EFI /dev/nvme0n1p1
mkfs.fat 4.2 (2021-01-31)
Що це означає: ESP відформатовано як FAT32 з міткою EFI.
Рішення: Якщо робите дзеркальний завантажувальний набір, відформатуйте ESP на кожному диску і змонтуйте обидва (або використайте підхід синхронізації). Один диск простіший.
Завдання 6: Створити ZFS пул (root на ZFS)
cr0x@server:~$ sudo zpool create -f -o ashift=12 \
-O atime=off -O compression=zstd -O xattr=sa -O normalization=formD \
-O mountpoint=none -O acltype=posixacl \
rpool /dev/nvme0n1p2
cr0x@server:~$ sudo zpool status
pool: rpool
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
nvme0n1p2 ONLINE 0 0 0
errors: No known data errors
Що це означає: Пул створено і здоровий.
Рішення: Якщо бачите щось інше, ніж ONLINE з нульовими помилками — зупиніться. Перевірте кабелі, стан дисків або шляхи до пристроїв. Не «продовжуйте й надійтесь».
Завдання 7: Створити датасети (окремий root, nix store і постійний стан)
cr0x@server:~$ sudo zfs create -o mountpoint=none rpool/local
cr0x@server:~$ sudo zfs create -o mountpoint=none rpool/safe
cr0x@server:~$ sudo zfs create -o mountpoint=legacy rpool/local/root
cr0x@server:~$ sudo zfs create -o mountpoint=legacy -o compression=zstd rpool/local/nix
cr0x@server:~$ sudo zfs create -o mountpoint=legacy rpool/safe/persist
cr0x@server:~$ sudo zfs list -o name,mountpoint,compression
NAME MOUNTPOINT COMPRESSION
rpool none zstd
rpool/local none zstd
rpool/local/nix legacy zstd
rpool/local/root legacy zstd
rpool/safe none zstd
rpool/safe/persist legacy zstd
Що це означає: Ви розділили датасети за принципом «можна перебудувати» (local) проти «треба зберегти при переустановленні» (safe/persist).
Рішення: Розмістіть /nix на окремому датасеті. Він росте. Він часто змінюється. Ви хочете інші правила знімків для нього, ніж для постійного стану.
Завдання 8: Змонтувати файлові системи для інсталяції
cr0x@server:~$ sudo mount -t zfs rpool/local/root /mnt
cr0x@server:~$ sudo mkdir -p /mnt/nix /mnt/persist /mnt/boot
cr0x@server:~$ sudo mount -t zfs rpool/local/nix /mnt/nix
cr0x@server:~$ sudo mount -t zfs rpool/safe/persist /mnt/persist
cr0x@server:~$ sudo mount /dev/nvme0n1p1 /mnt/boot
cr0x@server:~$ mount | head -n 5
rpool/local/root on /mnt type zfs (rw,xattr,posixacl)
rpool/local/nix on /mnt/nix type zfs (rw,xattr,posixacl)
rpool/safe/persist on /mnt/persist type zfs (rw,xattr,posixacl)
/dev/nvme0n1p1 on /mnt/boot type vfat (rw,relatime,fmask=0022,dmask=0022)
Що це означає: Цільовий root знаходиться в /mnt, з окремими монтажами для /nix, /persist і /boot.
Рішення: Якщо /mnt/boot не змонтовано, інсталяція systemd-boot тихо призведе до системи, яка не завантажиться. Виправте це зараз.
Завдання 9: Згенерувати початкову конфігурацію
cr0x@server:~$ sudo nixos-generate-config --root /mnt
writing /mnt/etc/nixos/hardware-configuration.nix...
writing /mnt/etc/nixos/configuration.nix...
Що це означає: NixOS виявив апаратне забезпечення і записав базову конфігурацію.
Рішення: Ставтесь до hardware-configuration.nix як до машинозгенерованого і стабільного файлу; людські наміри тримайте в окремих модулях, коли це можливо.
Завдання 10: Перевірити, що ZFS-монти відображені в hardware config
cr0x@server:~$ sudo sed -n '1,200p' /mnt/etc/nixos/hardware-configuration.nix
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot.supportedFilesystems = [ "zfs" ];
fileSystems."/" = {
device = "rpool/local/root";
fsType = "zfs";
};
fileSystems."/nix" = {
device = "rpool/local/nix";
fsType = "zfs";
};
fileSystems."/persist" = {
device = "rpool/safe/persist";
fsType = "zfs";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/ABCD-EF01";
fsType = "vfat";
};
}
Що це означає: Інсталятор правильно закодував монтажі. ESP використовує UUID, ZFS — імена датасетів.
Рішення: Тримайте імена датасетів ZFS стабільними. Не покладайтеся на /dev/nvme0n1p2 у довгострокових конфігах, якщо вам не подобаються несподіванки після перезавантаження.
Завдання 11: Передбачити збірку перед інсталяцією (зловити очевидні помилки)
cr0x@server:~$ sudo nixos-install --root /mnt --no-root-passwd --dry-run
building the system configuration...
warning: Git tree '/mnt/etc/nixos' is dirty
dry-run succeeded
Що це означає: Конфіг обчислюється і збирається. «dirty» наразі — нормально.
Рішення: Якщо збірка не вдається — виправте це ще в середовищі ISO. Не «встановлюйте і надiйтеся».
Завдання 12: Встановити та налаштувати систему
cr0x@server:~$ sudo nixos-install --root /mnt --no-root-passwd
building the system configuration...
installing the boot loader...
setting up /etc...
updating GRUB 2 menu...
installation finished!
Що це означає: NixOS встановлено і записи завантаження записано. (Залежно від конфігурації, ви можете побачити рядки systemd-boot замість GRUB.)
Рішення: Якщо інсталяція завантажувача провалилася — не перезавантажуйтесь. Перевірте /mnt/boot і налаштування завантажувача перш ніж робити наступні кроки.
Завдання 13: Перед перезавантаженням перевірити наявність записів завантаження (шлях UEFI/systemd-boot)
cr0x@server:~$ sudo ls -la /mnt/boot/loader/entries | head
total 16
drwxr-xr-x 2 root root 4096 Jan 1 00:10 .
drwxr-xr-x 3 root root 4096 Jan 1 00:10 ..
-rwxr-xr-x 1 root root 420 Jan 1 00:10 nixos-generation-1.conf
Що це означає: Записи systemd-boot існують на ESP.
Рішення: Якщо директорія порожня — ESP не була змонтована під час інсталяції. Змонтуйте її і перевстановіть завантажувач через chroot (nixos-enter) або обережно перезапустіть інсталяцію.
Завдання 14: Після перезавантаження підтвердити, що запущено потрібну генерацію
cr0x@server:~$ sudo nix-env -p /nix/var/nix/profiles/system --list-generations
1 2026-02-05 00:12:33 (current)
Що це означає: У вас є як мінімум одна генерація і вона є поточною.
Рішення: Якщо генерації відсутні або перемикання не вдається пізніше — ймовірно, у вас зламаний запис завантажувача або проблема з монтажем файлових систем.
Завдання 15: Підтвердити, що ZFS пул імпортується коректно при завантаженні
cr0x@server:~$ sudo zpool status -x
all pools are healthy
Що це означає: Немає відомих проблем з пулами.
Рішення: Якщо повідомляється про деградований пул, несправні пристрої або помилки контрольних сум — ставте це в пріоритет. ZFS каже правду; люди зазвичай намагаються торгуватися з нею.
Завдання 16: Швидко перевірити сервіси та час завантаження
cr0x@server:~$ systemd-analyze time
Startup finished in 3.221s (kernel) + 6.483s (userspace) = 9.704s
graphical.target reached after 6.439s in userspace
Що це означає: Короткий зведений час завантаження, розділений між ядром і userspace.
Рішення: Якщо userspace займає багато часу, перевірте одиниці, що блокують. Якщо ядро довго завантажується — часто це прошивка, ініціалізація сховища або складність initrd.
cr0x@server:~$ systemd-analyze blame | head
3.812s zfs-import-cache.service
2.104s network-online.target
1.442s nix-daemon.service
1.015s systemd-journald.service
Що це означає: Які одиниці зайняли найбільше часу.
Рішення: Не «оптимізуйте» поки не зрозумієте, чи це має значення. Якщо network-online.target повільний — перевірте DHCP або видаліть непотрібні залежності.
Завдання 17: Підтвердити доступність SSH і наявність ключів
cr0x@server:~$ sudo systemctl status sshd --no-pager
● sshd.service - OpenSSH Daemon
Loaded: loaded (/etc/systemd/system/sshd.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-02-05 00:20:14 UTC; 1min ago
Docs: man:sshd(8)
man:sshd_config(5)
Що це означає: sshd ввімкнено і працює.
Рішення: Якщо служба не активна — не покладайтеся на віддалене адміністрування. Виправте мережу/sshd зараз, поки у вас є доступ до консолі.
Завдання 18: Перевірити розмір closure і зростання store (планування ємності)
cr0x@server:~$ nix path-info -Sh /run/current-system
/nix/store/2h3...-nixos-system-server-25.11.20260201 1.8G
Що це означає: Орієнтовний розмір поточної системної closure.
Рішення: Якщо місця на диску мало — плануйте збірку сміття і тримайте /nix на окремому датасеті або розділі.
Здорова структура конфігурації NixOS 25.11
Тримайте конфіг читабельним. Майбутній ви буде втомленим і трохи роздратованим. Не ускладнюйте життя.
Мінімальна flake-структура, що масштабується на кілька хостів
Рекомендована структура:
flake.nixіflake.lockв корені репозиторіюhosts/server/configuration.nixдля намірів хостаmodules/для повторно використовуваних компонентів (ssh, моніторинг, zfs, користувачі)secrets/для зашифрованих матеріалів (не зберігайте в Nix store у відкритому вигляді)
Приклад flake (скорочено до суті):
cr0x@server:~$ cat /etc/nixos/flake.nix
{
description = "NixOS fleet";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
};
outputs = { self, nixpkgs, ... }:
let
system = "x86_64-linux";
in {
nixosConfigurations.server = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
./hosts/server/configuration.nix
];
};
};
}
Тоді конфіг хоста імпортує модулі і чітко фіксує наміри:
cr0x@server:~$ sed -n '1,220p' /etc/nixos/hosts/server/configuration.nix
{ config, pkgs, ... }:
{
imports = [
../../hardware-configuration.nix
../../modules/base.nix
../../modules/ssh.nix
../../modules/zfs.nix
];
networking.hostName = "server";
time.timeZone = "UTC";
users.users.cr0x = {
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... cr0x@laptop"
];
};
services.openssh.enable = true;
services.openssh.settings = {
PasswordAuthentication = false;
PermitRootLogin = "no";
};
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
system.stateVersion = "25.11";
}
Чого уникати: гігантської монолітної configuration.nix з усім від nginx до шрифтів і експериментальних параметрів ядра. Розбивайте. Ви будете відлагоджувати швидше.
Постійність: вирішіть, що має пережити перебудову
Якщо ви створили /persist, використовуйте його. Зберігайте там те, що важливо: SSH host keys, стратегія machine-id, дані служб, можливо логи та обов’язково стан застосунків. Точне підключення залежить від уподобань, але принцип простий: відокремлюйте «перебудовуване» від «повинно вижити».
Практичний підхід — прив’язувати окремі директорії до /persist (або використовувати патерни impermanence). Перевага — зрозумілість під час інциденту: ви можете видалити root-датасет і зберегти стан.
Налаштування Nix, які запобігають самонанесенню шкоди
- Увімкніть демон (за замовчуванням) і використовуйте sandboxed builds, де можливо.
- Віддавайте перевагу зафіксованим inputs nixpkgs і переглядайте оновлення.
- Заплануйте збірку сміття та політику збереження генерацій явно.
cr0x@server:~$ sudo nixos-option nix.gc.automatic
nix.gc.automatic = false
Що це означає: GC не увімкнено за замовчуванням у багатьох налаштуваннях.
Рішення: Для серверів з невеликою ємністю диска увімкніть GC з політикою збереження, яка не видалить ваш останній відомо-робочий стан перед тим, як він знадобиться.
Оновлення, відкати та контроль дрейфу в реальному світі
NixOS надає багато ременів безпеки. Вам все ще треба їх правильно використовувати, ніби ви перевозите скло.
Як насправді працює «нульовий дрейф конфігурації»
Дрейф виникає, коли реальність змінюється без змін в джерелі істини. NixOS бореться з цим двома шляхами:
- Перебудова перезаписує файли, що керуються конфігом. Це блокує випадкові правки в /etc, що залишаються назавжди.
- Система — це артефакт збірки. Ви не «налаштовуєте живий стан», ви переключаєтесь на нову генерацію.
Але дрейф все ще може з’являтись у директоріях стану (бази даних, кеші, логи), у ручних змінах фаєрволу, у «тимчасових» завантажених модулях ядра та в змінах поза конфігом, як-от налаштування прошивки. Ваше завдання — мінімізувати позаконфігураційні шляхи і документувати ті, що лишаються.
Безпечний патерн оновлень
Ось патерн, який я хочу бачити в продакшені:
- Оновити inputs (flake.lock) свідомо.
- Зібрати систему.
- Переключитись на неї.
- Перевірити критичні сервіси.
- Тримати відкат доступним і не збирати сміття негайно.
cr0x@server:~$ sudo nixos-rebuild build --flake /etc/nixos#server
building the system configuration...
/nix/store/8m7...-nixos-system-server-25.11.20260205
Що це означає: Ви зібрали нову closure системи, не активуючи її.
Рішення: Якщо збірка не вдається — ви не торкнулися робочої системи. Виправте перед переключенням.
cr0x@server:~$ sudo nixos-rebuild switch --flake /etc/nixos#server
building the system configuration...
activating the configuration...
setting up /etc...
reloading user units for cr0x...
Що це означає: Нова генерація активна. Служби могли перезапуститись.
Рішення: Перевірте конкретні речі, що важливі для бізнесу (порти, здоров’я API, монтування сховищ). Не довіряйте тільки тому, що «switch пройшов успішно».
Відкат, який можна виконати під тиском
Є два шляхи відкату:
- Під час завантаження: оберіть старішу генерацію в меню завантажувача.
- На працюючій системі: переключіться на старішу генерацію на місці.
cr0x@server:~$ sudo nix-env -p /nix/var/nix/profiles/system --list-generations
1 2026-02-05 00:12:33
2 2026-02-05 01:05:10 (current)
Що це означає: У вас є принаймні дві генерації для вибору.
Рішення: Якщо зберігається тільки одна генерація — ви перетворили NixOS на просто крутий пакетний менеджер. Зберігайте кілька.
cr0x@server:~$ sudo /nix/var/nix/profiles/system-1-link/bin/switch-to-configuration switch
setting up /etc...
reloading user units for cr0x...
Що це означає: Ви переключились назад на генерацію 1.
Рішення: Якщо система в поганому стані, віддавайте перевагу відкату через завантаження. Це скидає більше припущень.
Збирання сміття без самознищення
Тиск простору реальний, особливо на невеликих root-дисках. Але агресивний GC — це як видалити єдине робоче ядро перед перезавантаженням.
cr0x@server:~$ sudo nix-collect-garbage -d
finding garbage collector roots...
deleting old generations of profile /nix/var/nix/profiles/system
deleting unused links...
0 store paths deleted, 0.00 MiB freed
Що це означає: У цьому прикладі нічого не звільнено (ймовірно, генерації зафіксовані).
Рішення: Перед увімкненням автоматичного GC встановіть політику скількох генерацій зберігати і як довго. Диск дешевий; простої немає.
Жарт №2: «Увімкнімо щоденний GC» — це як шлях дізнатися, що ваш план відкату був танцем інтерпретацій.
Поради з інженерії сховища: ZFS, Btrfs, ext4 і реальність
Сховище — те місце, де «все працювало в стейджингу» помирає. Хороша новина: NixOS робить конфіг сховища відтворюваним, отже ви можете про нього думати.
Корінь на ZFS: що ви отримуєте і що платите
Переваги: контрольні суми end-to-end, снапшоти, властивості датасетів для піддерев, робочі процеси реплікації і відмінна спостережуваність (scrub, лічильники помилок, чіткі сигнали відмов).
Витрати: Потрібно планувати використання пам’яті, scrubs, моніторинг і поведінку імпорту. ZFS стабільний, але також чесний: він скаже вам, що диск помирає, раніше ніж RAID-контролер.
Макет датасетів: не ускладнюйте, зробіть корисним
Попередній макет датасетів (rpool/local/root, rpool/local/nix, rpool/safe/persist) спрямований на операційну контрольованість:
- Різні інтервали знімків: частіші для persist, менше для nix, можливо відсутні для root.
- Різні правила реплікації: persist реплікується поза хостом; nix — відтворюваний і опційний.
- Чітке поле ураження: можна відкотити persist без відкату ОС і навпаки.
ARC і пам’ять: на що звертати увагу
ZFS використовує пам’ять для ARC-кешу. Зазвичай це добре. Але може створювати проблеми на віртуалках з малою пам’яттю або при змішаних навантаженнях, де page cache і ARC конкурують за простір.
cr0x@server:~$ cat /proc/meminfo | head
MemTotal: 16342132 kB
MemFree: 2145320 kB
MemAvailable: 8021444 kB
Buffers: 212344 kB
Cached: 4219072 kB
Що це означає: «MemAvailable» — ваш реальний запас. «Cached» включає файлові кеші.
Рішення: Якщо мало RAM і є тиск OOM під навантаженням, подумайте про обмеження ARC. Робіть це свідомо, на підставі вимірювань, а не забобонів.
Scrub-и: плануйте їх як бекапи — бо це їхній вид
Scrub читає всі дані і перевіряє контрольні суми. Вони не заміняють бекапи, але вчасно перетворюють тиху корупцію на голосні алерти.
cr0x@server:~$ sudo zpool scrub rpool
cr0x@server:~$ sudo zpool status
pool: rpool
state: ONLINE
scan: scrub in progress since Thu Feb 5 02:11:33 2026
32.1G scanned at 1.20G/s, 1.02G issued at 39.1M/s, 120G total
0B repaired, 0.85% done, 0:01:39 to go
Що це означає: Scrub запущено; видно прогрес і пропускну здатність.
Рішення: Якщо scrub виявляє відремонтовані байти або помилки контрольних сум — це сигнал перевірити диски і кабелі. Не просто очищуйте помилку і рухайтеся далі.
Відмінності ext4/Btrfs (якщо ви не використовуєте ZFS)
Якщо оберете ext4, ваш «максимальний контроль» зрушиться вгору по стеку: ви більше покладатиметесь на бекапи, снапшоти LVM (можливо) і ретельні апдейти.
Якщо оберете Btrfs, отримаєте снапшоти і send/receive. Операційна дисципліна інша: слідкуйте за вільним простором, балансуванням і правильним макетом субтомів.
Частина NixOS незмінна: стан ОС декларативний, відкати існують, а дрейф мінімізований. Ваша стратегія сховища доповнює історію надійності.
Плейбук швидкої діагностики
Це порядок триажу «повільно / не завантажується / хитається», який заощаджує час. Мета — не повнота, а швидкість і сигнал.
Перше: підтвердити, що змінилися
- Ви переключали генерації? Змінювались inputs?
- Чи та система працює, яку ви думаєте?
cr0x@server:~$ readlink /run/current-system
/nix/store/8m7...-nixos-system-server-25.11.20260205
Рішення: Якщо шлях в store не той, що очікували — зупиніться з гаданнями. Узгодьте команду щодо «що зараз запущено».
Друге: це проблема завантаження, сховища, мережі чи сервісу?
Виберіть категорію швидко. Більшість відмов — нудні.
Проблеми з завантаженням і initrd
cr0x@server:~$ journalctl -b -p err --no-pager | tail -n 20
Feb 05 02:20:31 server kernel: zfs: module license 'CDDL' taints kernel.
Feb 05 02:20:33 server systemd[1]: Failed to mount /persist.
Feb 05 02:20:33 server systemd[1]: Dependency failed for Local File Systems.
Рішення: Якщо монтажі падають — у вас проблема з файловими системами/датасетами/порядком монтажів. Не слід ганятися за логами застосунків поки це не вирішено.
Стан сховища
cr0x@server:~$ sudo zpool status
pool: rpool
state: DEGRADED
status: One or more devices could not be opened.
action: Attach the missing device and online it using 'zpool online'.
config:
NAME STATE READ WRITE CKSUM
rpool DEGRADED 0 0 0
nvme0n1p2 ONLINE 0 0 0
nvme1n1p2 UNAVAIL 0 0 0 cannot open
Рішення: Якщо ZFS деградований — пріоритетом є доступність пристроїв і безпека даних. Налагодження продуктивності почекає.
Доступність мережі
cr0x@server:~$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
enp1s0 UP 10.20.30.40/24 fe80::a00:27ff:fe4e:66a1/64
Рішення: Якщо інтерфейс не UP або не має адреси — виправте мережеву конфігурацію, перш ніж звинувачувати DNS, TLS чи застосунки.
Стан служб
cr0x@server:~$ systemctl --failed --no-pager
UNIT LOAD ACTIVE SUB DESCRIPTION
● nginx.service loaded failed failed Nginx Web Server
1 loaded units listed.
Рішення: Невдалі одиниці показують, куди дивитись. Читайте логи одиниці; не перезапускайте наосліп.
Третє: знайдіть вузьке місце (CPU, IO, пам’ять чи блокування)
cr0x@server:~$ top -b -n 1 | head -n 12
top - 02:31:10 up 12 min, 1 user, load average: 7.12, 6.80, 4.21
Tasks: 168 total, 2 running, 166 sleeping, 0 stopped, 0 zombie
%Cpu(s): 12.4 us, 3.1 sy, 0.0 ni, 82.9 id, 1.4 wa, 0.0 hi, 0.2 si, 0.0 st
MiB Mem : 15959.1 total, 2210.5 free, 5300.8 used, 8447.8 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 8658.3 avail Mem
Рішення: Якщо IO wait високий — дивіться диск. Якщо пам’яті мало і swap відсутній — ймовірний OOM. Якщо CPU завантажено — профілюйте сервіс або масштабуйтесь.
Поширені помилки: симптом → причина → виправлення
1) Система не завантажується після «успішної» інсталяції
Симптом: Завантаження переходить у меню прошивки або «немає завантажувального пристрою».
Причина: ESP не була змонтована в /mnt/boot під час інсталяції, тож записи завантажувача записані не туди (або не записані зовсім).
Виправлення: Завантажте ISO, змонтуйте root в /mnt, змонтуйте ESP в /mnt/boot, потім перевстановіть завантажувач через nixos-enter або повторіть кроки інсталяції уважно.
2) ZFS пул не імпортується при завантаженні
Симптом: Рятувальна оболонка; помилки про монтування root або відсутній пул.
Причина: Відсутній рядок boot.supportedFilesystems = [ "zfs" ];, неправильні імена датасетів або initrd не містить ZFS-складових.
Виправлення: Переконайтесь, що hardware config включає підтримку ZFS; перебудуйте; якщо вже зламано — завантажтеся в старішу генерацію або використайте ISO, щоб імпортувати пул і виправити конфіг.
3) «Працювало, а після перезавантаження SSH мертвий»
Симптом: Після перебудови не можете зайти по SSH; на консолі система працює.
Причина: Дрейф мережевої конфігурації (DHCP vs статична), декларативне ужорсточення фаєрволу або налаштування sshd змінені без ключів у місці.
Виправлення: На консолі перевірте ip -br a, systemctl status sshd і journalctl -u sshd. Відкатіть генерацію при потребі, потім виправте конфіг з авторизованими ключами і зробіть поетапний реліз.
4) Диск несподівано заповнюється на NixOS
Симптом: /nix росте до тих пір, поки система не починає падати в дивні способи.
Причина: Накопичуються старі генерації і шляхи в store; GC не налаштований; артефакти збірок залишаються.
Виправлення: Встановіть політику GC і збереження генерацій; перемістіть /nix на окремий датасет/розділ; моніторьте вільне місце.
5) «nixos-rebuild switch» триває вічно
Симптом: Перебудови повільні; CPU і диск навантажені.
Причина: Часті збірки з джерел, відсутність доступу до бінарних кешів або надмірно великий конфіг, що тягне багато залежностей.
Виправлення: Переконайтеся, що використовуєте бінарні кещі, віддавайте перевагу стабільним пакункам і уникайте компіляції всього світу на продуктивних вузлах.
6) Секрети витекли в Nix store
Симптом: Токен з’явився в /nix/store або його можуть прочитати небажані користувачі.
Причина: Ви поклали секрети безпосередньо в Nix вираження або створили файли під час збірки, які опинилися в store.
Виправлення: Перенесіть секрети у runtime-постачання (activation scripts, tmpfiles), або використайте зовнішній менеджер секретів; змініть скомпрометовані облікові дані.
Три корпоративні міні-історії (біль, смирення, результати)
Інцидент через неправильне припущення: «Ім’я інтерфейсу буде eth0»
У середній компанії команда мігрувала невеликий флот з традиційного управління конфігурацією на NixOS. Вони зробили все правильно: все декларативно, збірки зафіксовані, відкати працювали. Чисто.
Потім вони купили нове залізо. NIC змінився. Призначення передбачуваних імен інтерфейсів спрацювало, і інтерфейс став чимось на кшталт enp129s0f0, а не eth0. Їх конфіг NixOS мав статичний блок мережі з посиланням на старе ім’я. На столі хтось протестував з одним хостом і виправив вручну «щоб його підняти». Та ручна правка ніколи не потрапила в git.
Під час розгортання половина серверів піднялася без мережі. Моніторинг показав частковий збій. Інженер на виклику не міг підключитися по SSH — це й була вся суть відмови. Консольний доступ був, але не швидко — це були віддалені майданчики.
Корінь проблеми не в NixOS; це було припущення, що імена інтерфейсів стабільні між обладнанням. Справжній операційний гріх — ручна виправа на стенді, яка обійшла джерело істини. Саме так дрейф краде систему: через терміновість і добрі наміри.
Виправлення було простим і нудним: співставляти інтерфейси за MAC-адресою в конфігурації і припинити писати конфіги, що залежать від імен пристроїв. Постмортем не наказував «тестувати більше». Він наказував «жодних локальних ручних правок без коміту» і «мережеву конфігурацію ідентифікувати за стабільними індикаторами».
Оптимізація, що обернулась проти: «Агресивний збір сміття тримає диски чистими»
Інша організація працювала на NixOS на билд-вузлах і кількох внутрішніх сервісах. Хтось помітив, що /nix пожирає простір. Справедливо. Вони включили автоматичний GC щодня з агресивною політикою видалення. Граф вільного місця виглядав чудово.
Через тижні безпеки оновлення вимагало перезавантаження кількох вузлів. Один вузол не піднявся нормально — несуміжна апаратна проблема уповільнила нумерацію пристроїв і найновіша генерація мала гонку завантаження, пов’язану з мережею. Виправлення — завантажити попередню генерацію. Але попередня closure вже була зібрана GC.
Іронія була гостра: ОС, спроектована для відкатів, опинилася без шляху відкату, бо її оптимізували як тимчасове сховище.
Відновлення вимагало запустити rescue media, відновити частини store з бекапу, достатні для завантаження, а далі — рухатися вперед з виправленим конфігом. Після цього політика змінилася: зберігати кілька генерацій протягом певного вікна часу і робити GC тільки після успішного тестового перезавантаження. Використання диска зросло. Інциденти впали.
Нудна, але правильна практика, що врятувала день: «Збирай, потім переключайся, потім перевіряй»
Фінтех-команда використовувала NixOS для набору внутрішніх API. Вони не кричали про це; просто їм подобалося, що продакшен можна перебудувати з git і що деплєїти передбачувані. У їхньому рукописі була нудна правило: завжди запускати nixos-rebuild build спочатку, потім switch, і завжди прогін невеликого набору перевірок після. Нікому це не подобалось, але правило прижилось.
Одного разу інженер оновив зафіксовані inputs, щоб взяти виправлення бібліотеки. Збірка пройшла, але активація зазнала поразки, бо у systemd unit змінилась назва опції в апстримі. Та помилка сталася під час switch, а не після перезавантаження, і була відразу видима в консолі і логах деплою.
Оскільки вони збирали спочатку, вони вже знали, що це не проблема компіляції. Оскільки переключали в контрольоване вікно, радіус ураження був обмежений. Завдяки перевіркам вони не випустили напівпрацюючий стан, де деякі служби використовували старі бібліотеки, а інші — нові.
Відкат був швидким: вони повернулись до попередньої генерації, виправили unit у коді, перебудували, переключилися, перевірили і пішли далі. Ніякої драми. Ніхто не отримав нагороди. Ось у чому суть.
Поширені запитання
1) Чи справді NixOS — «нульовий дрейф»?
Для декларативно керованих частин — так: перебудова примушує дотримуватися заявленого стану. Дрейф усе ще може існувати в постійному стані застосунків, в налаштуваннях прошивки і в усьому, що змінюється поза конфігом.
2) Чи варто використовувати flakes на серверах?
Так. Pinning і відтворюваність — це суть. Flakes ускладнюють випадкове оновлення всього світу через зрушення каналу.
3) Чи можна керувати кількома машинами з одного репозиторію?
Це одне з найкращих застосувань NixOS. Тримайте модулі для кожного хоста і спільні модулі. Уникайте копіпасту, факторизуючи загальні ролі.
4) Чи потрібен ZFS, щоб NixOS був відтворюваним?
Ні. Відтворюваність NixOS про конфігурацію системи і Nix store. ZFS додає сильні семантики сховища і снапшоти, що дуже корисно, але це необов’язково.
5) Який найпростіший безпечний вибір завантажувача?
UEFI + systemd-boot простий варіант для багатьох систем. Якщо у вас складний мультизавантажувальний сценарій або старі вимоги — GRUB підходить. Оберіть один варіант, протестуйте записи відкату і задокументуйте процедуру.
6) Як запобігти витоку секретів у Nix store?
Не вбудовуйте секрети в Nix-деривації. Постачайте їх під час runtime (activation scripts, tmpfiles) або отримуйте з менеджера секретів. Поверніть будь-який секрет, що можливо опинився в store.
7) Як правильно робити відкати в продакшені?
Тримайте кілька генерацій, переконайтесь, що записи завантажувача існують, і тестуйте завантаження старішої генерації після значної зміни. Відкат має бути м’язовою пам’яттю, а не теорією.
8) Як налагоджувати падіння служби після перемикання генерації?
Почніть з systemctl --failed, потім journalctl -u service. Якщо причина — конфіг, відкатіть негайно і виправте в коді.
9) Чи можна робити віддалені деплєїти?
Так, і варто це зробити, коли довіряєте конвеєру. Ключ — мати консольний доступ для відмов і не переключати генерації без кроку верифікації.
10) Який мінімальний моніторинг варто мати?
Простір диска (особливо /nix), пам’ять, навантаження, стан служб і для ZFS: стан пулу і результати scrub. Якщо ви цього не бачите — вам згодом подзвонять.
Наступні кроки, які варто виконати
Ви встановили NixOS 25.11. Це була легка частина. Тепер зробіть систему операційною.
- Закомітіть репозиторій конфігурації (включно з flake.lock) і ставте його джерелом істини.
- Напишіть runbook відкату з точними командами та кроками в меню завантаження для вашого обладнання.
- Встановіть політику збереження генерацій і GC, яка забезпечує безпеку, а не тільки звільнення місця.
- Вирішіть і реалізуйте обробку секретів перед додаванням додаткових сервісів.
- Додайте базовий моніторинг: диск, пам’ять, стан служб і статус ZFS, якщо застосовано.
- Протестуйте повну перебудову у VM або на резервному вузлі. Якщо ви не можете відтворити — ви не володієте системою.
Відтворюваність — це не стиль. Це звичка, підкріплена інструментами. NixOS дає інструменти. Звичка — за вами.