Если эта shitpost-like статья выглядит как шиза
Нормальная дока на ангельском: github/scclie/sccl_nix/README.md
тут я просто вываливаю мысли
На*&я Зачем?
Вот мне раньше, после 6 лет юза онли арча - тоже не было понятно.
Мол наплодили ещё какой-то попсовый дистр, аля федоры, манжары и прочих качи.
А потом мне захотелось его установить…
После этого, видимо, мир перевернулся.
Куча проблем, что возникали на обычных дистрах - решились моментами. Мне даже ранее не казалось что это проблемы - за годы использования стандартных дистров ловишь консенсус, просто привыкаешь к тому как над в них работать, чтоб всё было заебись.
Но то заебись и это заебись - это совершенно два разных заебись.
Самое смешное - проблемы, о которых даже не думаешь как о проблемах. Конфиги расползаются по /etc, пакеты ставятся и забываются, systemd-юниты включаются ручками и теряются. Через полгода система - чёрный ящик. Ты понятия не имеешь, как она дошла до жизни такой.
Хуярить ебучий git для /etc? fr
NixOS предлагает обратное: ты описываешь конечный результат. Все пакеты, конфиги, юзеры, сервисы - один билд, одно состояние.
Хочешь вторую машину? Те же конфиги, другой хост. Хочешь откатиться? Въёбываешь предыдущую генерацию. Каждый билд лежит в /nix/store, ничего не раскидывается по /usr и /etc как попало.
Отдельный кайф с шеллами. Часто надо поставить “одноразовые проги” - поставил, юзанул, забыл. А оно лежит в системе ;k
Никс предлагает nix shell - накидал любых прог, поюзал, забыл - само удалится при сборке мусора. Зависимости тянутся только в твой шелл из /nix/store.
Можно просто nix run nixpkgs#imagemagick -- convert ... и оно скачается, исполнится, и при следующем garbage collector исчезнет. Никаких следов.
ручками, если хочш почистить - nix-collect-garbage -d втуливаешь.
Откуда вообще Nix
В 2006 году крутой мужик по имени Eelco Dolstra защитил PhD в Utrecht University. Тема диссертации: “The Purely Functional Software Deployment Model”
Идея была радикальной: а что если пакет - это чистая функция?
Вход: исходники + зависимости + флаги компиляции. Выход: бинарник.
Одинаковый вход = одинаковый выход. Всегда. На любой машине. Без “у меня собирается а у тебя нет”.
Для этого /nix/store устроен гениально просто. Каждый пакет лежит в своей директории, и путь включает хеш всех входных данных:
/nix/store/5mq2jcn36ldd97xrcnf3jg8irnfp5xqr-fish-4.0.1/
Хеш зависит от исходников, зависимостей, флагов компиляции, версии компилятора. ВСЕГО.
Любое изменение - другой хеш - другой путь. Два пакета не конфликтуют потому что лежат в разных директориях. Атомарные обновления. Никакого “я поставил новую версию и поломал старую”.
Эт совершенно другая парадигма, по сравнению с другими пакетниками.
Экосистема nixpkgs сейчас - крупнейший в мире репозиторий пакетов. И всё это собирается одной фермой Hydra и кешируется в бинарный кеш.
на самом деле немного обман цифр - очень много пакетов разбиты на куча маленьких. Если смотреть по реальному софту - nixpkgs меньше чем тот же aur.
Императивное vs декларативное
Как вываливали в какой-то очень старой мысли ещё на заре придумывания Nix - пакетники можно сравнить с языками программирования.
Есть статья “Functional Package Management with Guix” где эта мысль хорошо раскрыта, но идея звучала и раньше.
мне лень искать, где ещё, но было.
Императивные пакетники (apt, yum, pacman) - это как процедурное программирование. Ты говоришь системе ЧТО ДЕЛАТЬ: apt install nginx, потом systemctl enable nginx, потом ручками конфиг в /etc/nginx/nginx.conf. Последовательность команд меняет состояние.
Декларативные (Nix, Guix) - это как функциональное. Ты описываешь КАКОЙ РЕЗУЛЬТАТ нужен:
services.nginx = {
enable = true;
virtualHosts."example.com" = {
root = "/var/www/example.com";
};
};Не “поставь nginx и настрой”. А “вот такой nginx должен быть в системе”.
Разница фундаментальная. В императивном мире ты теряешь историю - система помнит текущее состояние, но не помнит как она в него пришла. В декларативном - каждый билд это функция от конфига. Хочешь повторить на другой машине - тот же конфиг, тот же результат.
а дальше чо? Какой-то более высокоуровневый подход, более абстрактный? (иль мега абстрактный llm-based chat interface??????? - ai problem resolver :D )
Экосистема
Сам по себе NixOS решает только часть проблемы. Системный уровень. А есть ещё куча всего, что хочется в декларативщину.
flakes
Экспериментальная фича с 2021 года. До сих пор экспериментальная.
Но по факту все давно сидят на флейках. Они решают две главные проблемы старого Nix: версионирование зависимостей (через flake.lock) и единый формат проекта.
До флейков был channels - глобальное состояние системы. Поменял канал - поменялось для всего. Никакой изоляции.
С флейками у каждого проекта свой flake.lock, который фиксирует конкретные версии ВСЕХ зависимостей. Как package-lock.json но для всей системы.
Флейк авто-дискаверит хосты из папок - кидаешь hosts/<hostname>/, он сам подхватывает в nixosConfigurations.<hostname>. Никаких if hostname == костылей на уровне дискаверинга.
home-manager
10k звёзд на гитхабе. Позволяет декларативно управлять пользовательским окружением - дотфайлы, пользовательские пакеты, сервисы.
Раньше дотфайлы делали через GNU stow или bare git repo. home-manager позволяет всё то же самое, но в Nix-стиле: с опциями, с зависимостями, с иммутабельностью.
И главное - интегрируется с NixOS модулем. Один nixos-rebuild switch пересобирает и систему и пользовательское окружение.
disko
Достаточно один раз прописать конфиг разметки дисков, а не дрочить каждый раз gparted
Если хосты с одинаковыми дисками - можно спокойно реплиецировать.
sops-nix
Секреты (SSH-ключи, пароли, GPG) шифруются age-ключом и лежат прямо в репе. При билде расшифровываются в нужные места.
Раньше секреты хранили либо вне репы (и теряли), либо в зашифрованных git-репо (неудобно). sops-nix делает это прозрачно: секреты как часть конфига, но зашифрованы.
Проблема масштабирования
С NixOS есть одна засада. Ты начинаешь с одного хоста, всё красиво. Потом добавляешь второй. Потом третий.
И конфиг превращается в свалку из кучи исключений и т.п. (всё как в любом коде)
Есть и другие подходы:
- flake-parts - модульная система для флейков, позволяет разбивать конфиг на переиспользуемые модули. Хорош для больших проектов, но добавляет свой слой абстракции.
- snowfall-lib - библиотека для организации Nix-конфигов с авто-дискавери. Похожа на то что делаю я, но со своей философией.
- Куча народу просто живёт с
if hostnameи не парится. Тоже варик, если хостов 1-2.
Собственно, из этого и родился sccl_nix. - моя конфигурация, которая пытается не превратиться в помойку. (пару раз превращалась, но я очень стараюсь)
Мне хотелось архитектуру, где добавление нового хоста - это создание папки и декларирование sccl.* опций. Без единого if.
Архитектура sccl_nix
Дотфайлы разделены на три сущности.
hosts - железо и системщина. Диски (disko), дрова GPU, сеть, системные пакеты. Всё что нельзя синкать между разными машинами. Авто-дискаверятся флейком из hosts/.
profiles - пользователь со своим зоопарком прог, шеллом и user-level хламом. На одном хосте может быть сколько угодно профилей. Импортятся в конфиг хоста.
shared - база для всех. Рыба, niri, alacritty, waybar, базовые CLI тулзы. Один раз настроил - импортнул во все профили.
Сейчас два хоста: sacculos (десктоп, AMD) и aero15laptop (ноут, NVIDIA). Два профиля: paper (основной, со всем зоопарком) и bootstrap (минимальный, только vim, nmtui и ssh для установки с флешки).
как пример реального юза.
Схема:
flowchart TD F["❄️ flake.nix<br/>auto-discovery: hosts + shells"] NM["⚙️ nixos/modules/core.nix<br/>sccl.* options: conditional config"] H1["🖥️ hosts/sacculos<br/>desktop + amd gpu"] H2["💻 hosts/aero15laptop<br/>laptop + nvidia gpu"] P1["👤 profiles/paper<br/>main: steam, blender..."] PS["📦 profiles/shared<br/>base: fish, niri, waybar..."] PB["🪶 profiles/bootstrap<br/>minimal: nmtui, vim, ssh"] S["🔐 secrets/ sops-nix encrypted"] SH["🐚 shells/ auto-discovered devShells"] F --> H1 F --> H2 F --> SH H1 --> NM H2 --> NM H1 --> P1 H2 --> P1 H1 --> PB H2 --> PB P1 --> PS classDef flakeStyle stroke:#517599,stroke-width:2px,color:currentColor classDef hostStyle stroke:#5e81ac,stroke-width:2px,color:currentColor classDef profileStyle stroke:#8fbcbb,stroke-width:2px,color:currentColor classDef sharedStyle stroke:#d08770,stroke-width:2px,color:currentColor classDef moduleStyle stroke:#bf616a,stroke-width:2px,color:currentColor classDef secretStyle stroke:#bf616a,stroke-width:2px,color:currentColor classDef shellStyle stroke:#d08770,stroke-width:2px,color:currentColor class F flakeStyle class H1,H2 hostStyle class P1,PB profileStyle class PS sharedStyle class NM moduleStyle class S secretStyle class SH shellStyle
sccl.*
Главная фича, которая не даёт конфигу скатиться в свалку if hostname ==.
В core.nix определены ВСЕ опции, и все они по дефолту false. Каждый модуль гейтит сам себя через lib.mkIf config.sccl.<feature>.enable.
{ config, lib, ... }:
{
config = lib.mkIf config.sccl.zapret.enable {
services.zapret = { ... };
};
}Никаких if hostName == "laptop" then false. Модуль просто не включается.
Полный список опций (на момент написания статьи, хз буду ли обновлять):
sccl.ui.enable # Nord-тема + greetd
sccl.audio.enable # pipewire
sccl.bluetooth.enable # bluetooth + blueman
sccl.net.enable # networkmanager + прокси + firewall
sccl.automount.enable # udisks2 автоподключение флешек
sccl.secrets.enable # sops-nix шифрованные секреты
sccl.zapret.enable # обход DPI
sccl.flclashx.enable # FlClashX GUI для прокси
sccl.playground.enable # Docker + dev tools
sccl.chaotic.enable # chaotic-nyx репо
sccl.nix-ld.enable # nix-ld для бинарников не из nixpkgs
sccl.bootstrap # bool: минимальный режим установки
Конфиг хоста выглядит буквально так:
sccl = {
ui.enable = true;
audio.enable = true;
net.enable = true;
automount.enable = true; # только на десктопе
zapret.enable = true; # только на десктопе
playground.enable = true; # только на десктопе
nix-ld.enable = true;
};Добавление нового хоста - скопировал папку, поправил configuration.nix, сгенерил hardware-configuration.nix, поправил disko.nix. Флейк сам его подхватит.
Bootstrap-профиль решает проблему установки на слабом железе. Накатил bootstrap (~1-2 GB), загрузился, переключил sccl.bootstrap = false, перебилдил - и вот полная система. Не надо ждать пока на ноуте соберётся 100500 пакетов с флешки где ещё и места нет.
Для этого можно юзать nixos-anywhere, но bootstrap остаётся как бекап-вариант.
Клава и секреты
Раскладка
Раскладка параметризована через аргументы флейка (specialArgs).
У sacculos эрго-сплит на Vial прошивке - us,rulemak_vial. У aero15laptop - colemak_dh,rulemak. Один mkHost в flake.nix, и все слои (системная клава, XKB, WM) получают правильную раскладку.
На уровне WM (niri) раскладка тоже передаётся параметром: на десктопе Colemak-CAWS, на ноуте Colemak-DH-Wide. Это удобно когда у тебя разные клавиатуры с разной прошивкой и разными раскладками на разных машинах.
Без копипасты и костылей.
Секреты
SSH-ключи, GPG - всё зашифровано через sops-nix с age-ключом и лежит прямо в репе в secrets/common.yaml.
При ребилде с sccl.secrets.enable = true ключи сами расшифровываются в ~/.ssh/, GPG импортится автоматом.
Всё что над хранить отдельно - приватный age-ключ. Он у меня в менеджере паролей, не в репе.
Подвох?
Их есть у меня.
Nix - это другой язык. Не просто синтаксис конфигов, а полноценный функциональный язык. Ленивый, с динамической типизацией, со своей странной стандартной библиотекой. Кривая обучения - отвесная стена.
Документация. Она есть, но… Многое узнаёшь методом тыка и чтения чужих конфигов. How to Learn Nix от Ian Henry - это буквально дневник на 50+ постов о том как чувак учил Nix.
Время билда. Первый билд может идти долго, особенно если мало что закешировано. НоHydra кеширует почти всё, т.ч. последующие билды быстрые.
Flakes experimental с 2021. До сих пор. Но все используют. Статус скорее формальность на этом этапе.
Оверкилл для простых вещей. Если у тебя один сервер с nginx - тебе не нужен NixOS. Но если у тебя 3+ машины, кастомные патчи ядра, свой софт собранный из git - оно того стоит.
В целом: да, при большом скилле и тут можно насрать. Но архитектура sccl_nix хотя бы пытается этого не допустить. я в это верю (пытаюсь)
пока полёт нормальный. десктоп и ноут живут на одном конфиге с одинаковым профилем. Я получаю всегда одинаковую рабочую среду и даже не замечаю сижу ли я за ноутом, иль за пк (моя осанка замечает) - всё всегда настроено одинакого.