Эта статья является прямым продолжением этой статьи, где мы подробно разбирали, что такое флейки и как работает установка пакетов в Nix.
Что мы будем делать сегодня?
Сегодня мы приступим к практике, напишем свой собственный flake.nix, а также рассмотрим несколько интересных функций механики флейков.
Какой практический результат у нас будет в конце?
-
flake.nix:Две конфигурации под два разных хоста(условно server_host и home_host) с разной разметкой дисков и разными настройками.
Доступ к двум каналам для скачивания пакетов: стабильному и нестабильному.
Полностью воспроизводимая конфигурация(вплоть до версий всех наших пакетов)
В конце концов у нас будет полностью воспроизводимая и рабочая конфигурация операционной системы. Это значит, что мы в следующий раз, зайдя с другого ПК, сможем выгрузить нашу конфигурацию из гитхаба, сделать nixos‑install и просто ждать, пока наша система не установится.
Активация Nix flakes, разбор flake.nix
Как включить флейки в configuration.nix?
В настоящее фремя флейки являются экспериментальной функцией и до сих пор не включены по умолчанию. Чтобы это исправить, нам нужно отредактировать наш файл configuration.nix, добавив строчку:
{ config, lib, pkgs, ... }: { # ... nix.settings.experimental-features = [ "nix-command" "flakes" ] # ... }
После внесения этих изменений вам нужно сохранить файл, выйти из текстового редактора и запустить sudo nixos-rebuild switch для применения модификации.
Что такое nix-command?
«Новый инструмент командной строки nix также предлагает некоторые удобные функции. Например, теперь вы можете использовать команду nix repl для открытия интерактивной среды языка nix. Если вы заинтересованы, вы можете использовать его для просмотра и тестирования всего синтаксиса Nix, который вы узнали ранее.»
Источник: ссылка
Пишем flake.nix
Для начала переместимся в папку с нашим configuration.nix через cd /etc/nixos, где и будем писать наш файл.
Вот, кстати, как будет выглядеть наш с вами flake.nix на первое время:
{ description = "A simple NixOS flake"; # Банальное описание, вообще роли не играет inputs = { # NixOS official package source, using the nixos-26.05 branch here nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; }; outputs = { self, nixpkgs, ... }@inputs: { # ВАЖНО! ЗАМЕНИТЕ nixoshostname НА ВАШ ХОСТНЕЙМ!!! nixosConfigurations.nixoshostname = nixpkgs.lib.nixosSystem { modules = [ ./configuration.nix ]; }; }; }
Понимаю, что тут много незнакомых конструкций по типу @inputs, какого‑то nixosConfiguration.my-nixos которые взялись из ниоткуда. Но на самом деле всё очень и очень просто, и мы с вами в этом прямо сейчас и убедимся.
Структура flake.nix
Начнём с того, что flake.nix состоит из ДВУХ блоков: inputs = {}; и outputs = {};. Зачем они нужны?
-
inputs = {}В этот блок(атрибут, если рассматривать его с точки зрения языка Nix) все ссылки, с которых мы будем скачивать ЗАВИСИМОСТИ. Все эти зависимости мы затем передаём блоку
outputsв качестве аргументов.Зависимости в
inputsмогут отличаться по типу. Это могут быть как git‑репозитории по типуnixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";, так и другие флейки и даже локальные пути.В нашем с вами
flake.nixпока что есть только одна зависимость —nixpkgs, репозиторий, который мы передадим в качестве аргумента ВЫВОДУ, то есть блокуoutputs. -
outputs = {}Этот блок является функцией, которая принимает зависимости из
inputsв качестве своих параметров. А её возвращаемым значением является СИСТЕМА, которую мы, в итоге, хотим получить.Прежде чем приступить к построчному разбору кода я поясню: конкретно в нашем примере это означает, что мы хотим получить конфигурацию операционной системы для хоста «my‑nixos», берущую деривации из nixpkgs и берущую все остальные настройки из файла
configuration.nix, который лежит с ней в одной папке.
Построчный разбор flake.nix
Всё содержимое flake.nix, как вы могли заметить, находится внутри фигурных скобок в начале и конце файла:
{ description = "..."; inputs = { ... }; outputs = { ... }; }
Про description говорить особо нечего — это просто описание вашего флейка. Зачем ему нужно описание? Чтобы другие люди, которые будут читать этот файл, смогли понять, что делает этот проект и конфигурация. Возможности флейков не ограничиваются одной воспроизводимостью, и их можно по‑разному настроить. Вы можете сами в этом убедиться при помощи команды nix flake show templates, которая покажет вам самые разные шаблоны для флейков.
-
Блок
inputs = {}inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; };Первой непоняткой, с которой может столкнуться новичок, может быть «а где объявление nixpkgs»? Мы же объявляем только
nixpkgs.url. Вообще, это можно записать вот так, чтобы было понятнее. Суть от этого не меняется:inputs = { nixpkgs = { url = "github:NixOS/nixpkgs/nixos-26.05"; }; };Что мы здесь делаем? Мы объявляем зависимость с названием
nixpkgs(можно назвать как угодно, хотьnixa-opsa-cheremsha— тут вообще нет никаких ограничений) и в параметреnixpkgs.url, который указывает, откуда она будет брать нужные ей файлы, ставимgithub:NixOS/nixpkgs/nixos-26.05.Почему url выглядит так, а не как стандартный
https://github.com/NixOS/nixpkgs/nixos-26.05? Такой формат называетсяFlake Input URL. Разработчики Nix сделяли эту схему, чтобы сделать конфигурационные файлы короче, понятнее и удобнее для чтения, избавив нас с вами от необходимости писать длинные адреса наподобиеhttps://github.com/nix-community/nixpkgs/nixos-26.05?Расшифровывается
github:NixOS/nixpkgs/nixos-26.05по схеме<откуда_скачивать>:<имя_пользователя>/<название_репозитория>/<название_ветки или тега>:github:— указывает никсе, что скачивать зависимость нужно именно с GitHub.NixOS— имя пользователя или организации на GitHub.nixpkgs— название конкретного репозитория, принадлежащего NixOS.nixos-26.05— название ветки/тега, откуда брать код.
Разумеется, флейки умеют распознавать не только гитхаб, но и множество других других источников — GitLab, локальные пути, Codeberg.
ВАЖНЫЙ НЮАНС! url — это не единственный параметр для зависимостей в
inputs = {}. Помимо него есть ещёinputs.nixpkgs.follows:{ inputs = { nixpkgs-for-niri = { url = "github:NixOS/nixpkgs/nixos-26.05"; }; niri = { url = "github:sodiboo/niri-flake"; inputs.nixpkgs.follows = "nixpkgs-for-niri"; }; } }Что происходит с этой строкой? Вы говорите: «Nix, когда будешь собирать Niri, не скачивай для него отдельный
nixpkgs. Вместо этого используй тотnixpkgs, который у меня в этом же файле назван словомnixpkgs-for-niri».Для чего это нужно? Для того, чтобы niri при сборке не скачивал тот
nixpkgs, на котором его тестировал разработчик — условныйnixpkgs-25.11. Это необходимо для того, чтобы избежать скачивания гигабайт дублирующихся библиотек и раздувания системы в целом. -
Блок
outputs = {}outputs = { self, nixpkgs, ... }@inputs: { # ВАЖНО! ЗАМЕНИТЕ nixoshostname НА ВАШ ХОСТНЕЙМ!!! nixosConfigurations.nixoshostname = nixpkgs.lib.nixosSystem { modules = [ ./configuration.nix ]; }; };
outputs = { self, nixpkgs, ... }@inputs: { <содержание> }
Как мы помним, outputs — это функция, принимающая в качестве параметров self, nixpkgs и .... Итак, давайте разберёмся, что такое self, ... и зачем мы вставили @inputs перед двоеточием и что он вообще значит?
-
Что такое
@inputs?Этот синтаксис в Nix называется at‑pattern (или «связывание аргументов»). По сути, это двойной доступ к данным. Он позволяет одновременно сделать две вещи:
Распаковать переданный набор аргументов на отдельные переменные(
self,nixpkgs).Сохранить весь исходный набор целиком под именем
inputs.
Без
@inputsвам пришлось бы вручную перечислять абсолютно все зависимости или передавать их дальше по отдельности. Теперь же внутри функции вы можете написать простоinputs.nixpkgsили передать весьinputsв другой модуль. Проще показать:# Если бы @inputs не было outputs = { self, nixpkgs, ... }: { # Дублирование кода! nixosConfigurations.nixoshostname = nixpkgs.lib.nixosSystem { inherit self nixpkgs; # Дублирование кода! }; }; -
Что такое
self?В контексте Nix Flakes,
selfэто специальный аргумент, указывающий на ваш собственный флейк(то есть на ту папку, где лежит вашflake.nix).Зачем он нужен? А затем:
Через
selfвы можете обращаться к результатам сборки вашего же проекта. Например,self.packages.x86_64-linux.Это позволяет модулям внутри вашего проекта ссылаться на другие части этого же проекта без использования жестко прописанных путей.
Вам он вряд ли сейчас пригодится. Да и скажу честно, я сам им не пользуюсь, но упомянул его, чтобы вы просто знали, что такое вообще существует.
-
Многоточие
...Если вы читали мою предыдущую статью про настройку NixOs, то наверняка помните, для чего нужно многоточие. Но если вы зашли сюда недавно, то я повторюсь:
В экосистеме NixOS файлы конфигурации(например, модули или
configuration.nix) вызываются самой операционной системой автоматически. При этом NixOs под капотом передает в каждый модуль огромный ворох системных параметров:config,pkgs,lib,modulesPath,optionsи так далее.Если мы пишем свой модуль, которому нужны только
configиpkgs, то мы указываем их, а в конце ставим...:{ config, pkgs, ... }: { # Код модуля }Этим мы говорим интерпретатору Nix: «Мне для работы жизненно необходимы
configиpkgs. Но, NixOs, я знаю, что ты передашь мне ещё кучу всего. Так вот: всё остальное просто проигнорируй и не ругайся на лишние аргументы»
Блок nixosConfigurations = {};
nixosConfigurations = { nixoshostname = nixpkgs.lib.nixosSystem { modules = [ ./configuration.nix ]; }; };
Этот блок отвечает за определение конфигураций операционной системы NixOS внутри файла flake.nix.
Этот блок является главной точкой входа для сборки систем. Внутри него вы описываете один или несколько компьютеров(серверов, ноутбуков, виртуальных машин), которыми управляет этот флейк.
Иными словами — это список конфигураций. Вот вам самый простой пример:
nixosConfigurations = { home-pc = nixpkgs.lib.nixosSystem { # Конфигурация для home-pc modules = [ ./configuration.nix ]; }; web-server = nixpkgs.lib.nixosSystem { # Конфигурация для веб-сервера modules = [ ./server-configuration.nix ]; }; };
Имя конфигурации внутри этого блока обычно совпадает с сетевым именем компьютера (networking.hostName). Когда вы запускаете команду обновления системы, NixOs автоматически ищет конфигурацию, соответствующую текущему имени машины.
О том, как это применяется на практике, мы поговорим в разделе «Разделение конфигураций», где создадим две конфигурации — для нашего домашнего пк и для сервера(примерную).
Блок nixoshostname = nixpkgs.lib.nixosSystem {};
Блок nixoshostname = nixpkgs.lib.nixosSystem { ... }; отвечает за создание и сборку конкретного экземпляра операционной системы NixOs с заданными параметрами(внутри фигурных скобок).
Это функция‑конструктор, которая берет исходный код nixpkgs, ваши файлы настроек и превращает их в готовую к работе операционную систему. Давайте разберём её по частям:
nixoshostname— это уникальный идентификатор вашей конфигурации внутри Flake (обычно совпадает сnetworking.hostNameвашей машины). К нему вы обращаетесь через флаг--flake .#nixoshostname(о нём я также расскажу в будущем).nixpkgs.lib.nixosSystem— это специальная функция из репозитория NixPKGS. Она является «сердцем» сборки системы и объединяет ядро Linux, системные службы(systemd), драйверы и программы в один рабочий образ.
ВАЖНО! Если в inputs вы назвали nixpkgs как‑то по‑другому, то и в nixpkgs.lib.nixosSystem его нужно назвать по‑другому! Вот УПРОЩЁННЫЙ пример:
inputs = { stable.url = "github:nixos/nixpkgs/nixos-26.05"; }; outputs = { self, stable, ... }@inputs: { nixoshostname = stable.lib.nixosSystem { # stable ВМЕСТО nixpkgs modules = [ ./configuration.nix ]; }; };
Что такое modules?
Если саму функцию nixosSystem представить как повара, то modules — это рецепты и ингредиенты, которые вы ему передаете. Без этого списка NixOs просто не будет знать, какие программы установить, каких пользователей создать и как настроить сеть. В него мы и передаём наши файлы конфигурации(configuration.nix).
Однако одними файлами дело не ограничивается. Помимо них в modules можно всунуть:
-
Сторонние инструменты (из
inputsвашего flake):inputs = { stable.url = "github:nixos/nixpkgs/nixos-26.05"; disko = { "github:nix-community/disko"; } } outputs = { self, stable, disko, ... }@inputs: { nixoshostname = stable.lib.nixosSystem { modules = [ ./configuration.nix disko.nixosModules.disko # Ставим disko из inputs ]; }; }; -
Анонимные модули(или код прямо на месте):
Иногда бывает нужно быстро переопределить одну настройку, не создавая отдельный файл:
inputs = { stable.url = "github:nixos/nixpkgs/nixos-26.05"; } outputs = { self, stable, disko, ... }@inputs: { nixoshostname = stable.lib.nixosSystem { modules = [ ./configuration.nix # Меняет имя хоста на "altair-laptop" ({ ... }: { networking.hostName = "altair-laptop"; }) ]; }; };
Создание двух каналов: stable и unstable
ВАЖНО! Каналы в Nix Flakes!= nix‑channels
Для начала скажу, что устаревший nix‑channels, который вытесняют флейки, не имеет никакого отношения к тому, что мы сейчас будем обсуждать.
В нашем случае, каналы — это ветки (branches) в Git‑репозитории NixOS/nixpkgs. Стабильные каналы — это релизные ветки (например, release-26.05), а нестабильный канал — это ветка nixos-unstable. Каналы работают по аналогии с репозиториями с фиксированными релизами и rolling‑release ветками в других дистрибутивах Linux.
Что такое стабильный канал? Стабильный канал в NixOS — это «замороженные» версии репозитория nixpkgs, которые обновляются каждые шесть месяцев и получают только исправления ошибок и важные обновления безопасности. Обозначаются по году и месяцу выпуска, например nixos-26.05 или nixos-25.05.
Что такое нестабильные каналы? Нестабильный канал — это основная ветка разработки репозитория Nixpkgs, которая работает по принципу непрерывных обновлений (то есть — rolling‑release).
Пакеты попадают в nixos-unstable только после того, как проходят базовый набор автоматических тестов (Hydra, о которой я писал в прошлой статье), гарантирующих, что сборка не сломается на базовом уровне.
Думаю, суть вы уловили. В стабильном канале обновления редкие и тщательно протестированные; в нестабильном — ежедневные.
Конечно, риск того, что пакет из нестабильного канала поломается, присутствует, но он маловероятен(по крайней мере — лично я с этим никогда не сталкивался).
Для нас же, как пользователей, сильной стороной NixOS является возможность смешивать каналы — использовать стабильную базу для системы, но подтягивать отдельные свежие программы из нестабильного канала.
От теории к коду
{ description = "My flakes"; inputs = { # Объявляем источники пакетов (каналы) stable.url = "github:nixos/nixpkgs/nixos-26.05"; unstable.url = "github:nixos/nixpkgs/nixos-unstable"; }; outputs = { self, stable, unstable, ... }@inputs: let system = "x86_64-linux"; # Общие настройки для обоих репозиториев nixpkgsConfig = { allowUnfree = true; # Разрешаем проприетарный софт (Obsidian и т.д.) }; # Самостоятельно импортируем и настраиваем каналы stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; }; in { nixosConfigurations = { nixoshostname = stable.lib.nixosSystem { inherit system; # Передаем нестабильный канал внутрь модулей системы specialArgs = { stable = stable-pkgs; unstable = unstable-pkgs; }; modules = [ # ВАЖНО: Подменяем стандартный системный pkgs нашим настроенным stable-pkgs { nixpkgs.pkgs = stable-pkgs; } ./configuration.nix ]; }; }; }; }
Так, а теперь давайте подробно разберёмся вот с этими блоками кода:
# 1. Что такое let in?! let system = "x86_64-linux"; nixpkgsConfig = { allowUnfree = true; }; stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; }; in # 2. Общие настройки nixpkgsConfig = { allowUnfree = true; }; # 3. Что творится и зачем мы объявили stable-pkgs и unstable-pkgs? Что за параметр config? stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; }; # 4. Почему здесь stable, а не nixpkgs или stable-pkgs? default = stable.lib.nixosSystem { ... } # 5. Как это? specialArgs = { stable = stable-pkgs; unstable = unstable-pkgs; }; # 6. Что это вообще значит и зачем это вообще нужно? { nixpkgs.pkgs = stable-pkgs; }
-
Что такое
let ... in?nixpkgsConfig = { allowUnfree = true; };Что это значит: Мы вынесли настройки пакетного менеджера в отдельную переменную
nixpkgsConfig. На данный момент здесь всего одна опция —allowUnfree = true, которая разрешает установку проприетарного софта, такого как драйверы Nvidia, браузер Chrome, Discord или Obsidian.Зачем это нужно: По умолчанию Nix собирает и устанавливает исключительно Open Source программы. Если вы попытаетесь установить закрытый софт без этой опции, сборка завершится ошибкой. Вынесение этого блока в переменную позволяет применить правило «разрешить несвободный софт» сразу к обоим каналам без дублирования кода.
-
Блок общих настроек.
stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; };Что творится: в Nix Flakes каждый элемент из
inputs(в нашем случаеstableиunstable) — это, как я писал в прошлой части, не готовый набор программ, а просто скачанный исходный код репозитория с GitHub. Чтобы превратить этот исходный код в рабочий инструмент, из которого можно устанавливать софт, его нужно «активировать» — то есть импортировать (import).Что за параметр
config: функция импорта принимает на вход настройки сборки. Через параметрconfigмы передаём туда созданную ранее переменнуюnixpkgsConfig, в которой разрешили установку проприетарного софта.Зачем мы это объявили: если бы мы просто использовали
stableиunstableнапрямую, NixOS не применила бы к ним наши настройки. Объявляяstable-pkgsиunstable-pkgs, мы создаем два полностью настроенных и готовых к работе экземпляра, которые знают архитектуру нашего процессора (system = "x86_64-linux") и разрешают установку проприетарных программ (config = nixpkgsConfig). -
Импорт репозиториев
stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; };Что творится: в Nix Flakes каждый элемент из
inputs(в нашем случаеstableиunstable) — это, как я писал в прошлой части, не готовый набор программ, а просто скачанный исходный код репозитория с GitHub. Чтобы превратить этот исходный код в рабочий инструмент, из которого можно устанавливать софт, его нужно «активировать» — то есть импортировать (import).Что за параметр
config: функция импорта принимает на вход настройки сборки. Через параметрconfigмы передаём туда созданную ранее переменнуюnixpkgsConfig, в которой разрешили установку проприетарного софта.Зачем мы это объявили: если бы мы просто использовали
stableиunstableнапрямую, NixOS не применила бы к ним наши настройки. Объявляяstable-pkgsиunstable-pkgs, мы создаем два полностью настроенных и готовых к работе экземпляра, которые знают архитектуру нашего процессора (system = "x86_64-linux") и разрешают установку проприетарных программ (config = nixpkgsConfig). -
Точка входа в конфигурации системы
default = stable.lib.nixosSystem { ... }Почему здесь
stable.lib, а неnixpkgs.libилиstable-pkgs.lib:Почему
stable, а неnixpkgs: в вашем блокеinputsвы назвали стабильный канал словомstable(stable.url = ...). Имя переменной на входе вoutputsполностью зависит от того, как вы назвали её вinputs. Если бы вы там написалиnixpkgs.url = ..., то здесь было быnixpkgs.lib.nixosSystem.Почему
stable, а неstable-pkgs: функцияnixosSystem— это специальный «строительный инструмент» (функция‑конструктор), который знает, как собрать полноценную операционную систему NixOs из отдельных модулей. Этот инструмент находится внутри исходного кода репозитория (stable.lib.nixosSystem). А созданная нами переменнаяstable-pkgs— это уже результат работы с пакетами, у неё внутри нет конструктора операционной системы, там лежат только сами программы. Поэтому для развертывания ОС мы используем функцию из исходного репозиторияstable. -
Проброс аргументов через
specialArgsspecialArgs = { stable = stable-pkgs; unstable = unstable-pkgs; };Как это работает: по умолчанию NixOs изолирует файлы конфигурации (такие как
configuration.nix) и передает в них стандартный и весьма ограниченный набор переменных (например, стандартныйpkgs). Модули системы ничего не знают о том, что происходит внутри вашегоflake.nix.Параметр
specialArgs(специальные аргументы) — это «мост» междуflake.nixи вашими файлами конфигурации. Всё, что вы укажете внутриspecialArgs, станет доступно для импорта в начале файлаconfiguration.nix. В данном случае мы берем наш настроенный нестабильный пакетный менеджерunstable-pkgsи пробрасываем его внутрь системы под коротким и удобным именемunstable. -
Подмена системного репозитория
modules = [ { nixpkgs.pkgs = stable-pkgs; } ./configuration.nix ];Что это вообще значит и зачем нужно: это самый важный архитектурный нюанс. Конструктор
stable.lib.nixosSystemпо умолчанию автоматически создает внутри системы стандартную переменнуюpkgs. Но этот стандартныйpkgsсоздается «с нуля» и ничего не знает про нашallowUnfree = true, который мы прописали вstable-pkgs.Строчка
{ nixpkgs.pkgs = stable-pkgs; }буквально говорит операционной системе: «Эй, NixOs, не создавай стандартный пакетный менеджер самостоятельно. Возьми мой готовый, уже настроенныйstable-pkgsи сделай его главным системнымpkgs».Результат: благодаря этой строчке в
configuration.nixстандартная переменнаяpkgsавтоматически становится нашим настроенным стабильным каналом. Теперь вы можете писатьpkgs.discord, и он установится без ошибок, так какallowUnfreeприменился глобально на всю систему.
А как это применить на практике?
Допустим, у нас с вами следующая ситуация: мы хотим установить Obsidian из стабильного канала, но при этом хотим установить Neovim из НЕстабильного.
Как это решается? Очень просто!
{ config, pkgs, unstable, ... }: { # Установка пакетов environment.systemPackages = [ # Стабильная и проверенная версия Obsidian pkgs.obsidian # Свеженький NeoVim из unstable unstable.neovim ]; # ... ваши остальные настройки системы (базовые параметры, таймзона и т.д.) }
Заметьте, что мы в начало добавили pkgs и unstable. Однако вместо pkgs можно использовать stable:
{ config, stable, unstable, ... }: { environment.systemPackages = [ # Стабильная версия stable.obsidian # Нестабильная версия unstable.neovim ]; }
Разделение конфигов: для хоста_1 и хоста_2
Помните, я упоминал, что благодаря флейкам мы в одном репозитории можем хранить сразу несколько несвязанных друг с другом конфигураций? Пришло время этой возможностью воспользоваться! Во Flakes это делается очень элегантно через добавление новых элементов в атрибут nixosConfigurations:
{ description = "My flakes with Disko support"; inputs = { stable.url = "github:nixos/nixpkgs/nixos-26.05"; unstable.url = "github:nixos/nixpkgs/nixos-unstable"; # Добавляем Disko в inputs disko.url = "github:nix-community/disko"; # Говорим Disko использовать наш стабильный репозиторий nixpkgs disko.inputs.nixpkgs.follows = "stable"; }; outputs = { self, stable, unstable, disko, ... }@inputs: let system = "x86_64-linux"; nixpkgsConfig = { allowUnfree = true; }; stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; }; sharedArgs = { inherit inputs; stable = stable-pkgs; unstable = unstable-pkgs; }; in { nixosConfigurations = { # Первый хост (например, ПК) host_1 = stable.lib.nixosSystem { inherit system; specialArgs = sharedArgs; modules = [ { nixpkgs.pkgs = stable-pkgs; } # Подключаем модуль Disko и файл разметки для host_1 disko.nixosModules.disko ./hosts/host_1/disko-config.nix ./hosts/host_1/configuration.nix ]; }; # Второй хост (например, ноутбук) host_2 = stable.lib.nixosSystem { inherit system; specialArgs = sharedArgs; modules = [ { nixpkgs.pkgs = stable-pkgs; } # Подключаем модуль Disko и файл разметки для host_2 disko.nixosModules.disko ./hosts/host_2/disko-config.nix ./hosts/host_2/configuration.nix ]; }; }; }; }
Файловое устройство у нас в каталоге /etc/nixos, в таком случае, будет следующее:
/etc/nixos/ ├── flake.nix ├── flake.lock └── hosts/ ├── host_1/ │ ├── configuration.nix │ ├── disko-config.nix │ └── hardware-configuration.nix # У каждого хоста свое железо! └── host_2/ ├── configuration.nix ├── disko-config.nix └── hardware-configuration.nix
Это я привёл код всего flake.nix целиком. На практике нас интересует лишь эта добавка и то, как мы вставили disko внутрь. Разумеется, описывать configuration.nix и disko-config.nix я для каждого host не буду.
# 1. Объявление самих конфигов nixosConfigurations = { # Первый хост (например, ПК) host_1 = stable.lib.nixosSystem { inherit system; specialArgs = sharedArgs; modules = [ { nixpkgs.pkgs = stable-pkgs; } disko.nixosModules.disko # Что это такое?! ./hosts/host_1/disko-config.nix ./hosts/host_1/configuration.nix ]; }; # Второй хост (например, ноутбук) host_2 = stable.lib.nixosSystem { inherit system; specialArgs = sharedArgs; modules = [ { nixpkgs.pkgs = stable-pkgs; } disko.nixosModules.disko ./hosts/host_2/disko-config.nix ./hosts/host_2/configuration.nix ]; }; };
В целом, мы особо ничего не поменяли. Новые конфигурации легко создаются при добавлении новых именованных атрибутов(host_1, host_2) в nixosConfigurations.
Обсудить, пожалуй, стоит только disko.nixosModules.disko. Но тут всё предельно просто, так что давайте разберём его по частям:
disko— это ссылка на сам скачанный репозиторий проекта Disko из вашихinputs. Внутри этого объекта лежит всё содержимое репозитория, преобразованное в формат Nix..nixosModules— это стандартный для Nix Flakes набор (аттрибут), в который разработчики библиотек складывают готовые модули для операционной системы NixOS..disko— это имя конкретного модуля внутри этого набора. Разработчики назвали свой главный модуль точно так же, как и сам проект.
А как всем этим пользоваться?
Хорошо, вот мы создали две конфигурации. Что дальше? Вот хочу я, Например, переключиться с host_1 на host_2, что нам делать? Или если я хочу установить конфигурацию host_2?
Если мы устанавливаем систему на голое железо впервые:
nixos-install --flake .#host_2
Если хотим пересесть на конфигурацию host_2:
sudo nixos-rebuild switch --flake .#host_2
Финальная конфигурация
К концу статьи у нас должна получиться примерно такой flake.nix, если у вас только один конфиг. Хочу отметить, что я не рассматривал отдельно перемещение disko-config.nix из configuration.nix в flake.nix, но раз уж мы полностью перевели всю систему на флейки, то убрать его мы обязаны:
{ description = "My flakes"; inputs = { stable.url = "github:nixos/nixpkgs/nixos-26.05"; unstable.url = "github:nixos/nixpkgs/nixos-unstable"; disko.url = "github:nix-community/disko"; disko.inputs.nixpkgs.follows = "stable"; }; outputs = { self, stable, unstable, ... }@inputs: let system = "x86_64-linux"; nixpkgsConfig = { allowUnfree = true; }; stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; }; in { nixosConfigurations = { nixoshostname = stable.lib.nixosSystem { inherit system; specialArgs = { stable = stable-pkgs; unstable = unstable-pkgs; }; modules = [ { nixpkgs.pkgs = stable-pkgs; } ./configuration.nix ./disko-config.nix ]; }; }; }; }
Или если у нас две конфигурации. В таком случае вам нужно создать необходимые файлы, которые в указали в modules под каждым хостом.
{ description = "My flakes - double config"; inputs = { stable.url = "github:nixos/nixpkgs/nixos-26.05"; unstable.url = "github:nixos/nixpkgs/nixos-unstable"; disko.url = "github:nix-community/disko"; disko.inputs.nixpkgs.follows = "stable"; }; outputs = { self, stable, unstable, disko, ... }@inputs: let system = "x86_64-linux"; nixpkgsConfig = { allowUnfree = true; }; stable-pkgs = import stable { inherit system; config = nixpkgsConfig; }; unstable-pkgs = import unstable { inherit system; config = nixpkgsConfig; }; sharedArgs = { inherit inputs; stable = stable-pkgs; unstable = unstable-pkgs; }; in { nixosConfigurations = { # Первый хост (например, ПК) host_1 = stable.lib.nixosSystem { inherit system; specialArgs = sharedArgs; modules = [ { nixpkgs.pkgs = stable-pkgs; } disko.nixosModules.disko ./hosts/host_1/disko-config.nix ./hosts/host_1/configuration.nix ]; }; host_2 = stable.lib.nixosSystem { inherit system; specialArgs = sharedArgs; modules = [ { nixpkgs.pkgs = stable-pkgs; } disko.nixosModules.disko ./hosts/host_2/disko-config.nix ./hosts/host_2/configuration.nix ]; }; }; }; }
Послесловие
Ну‑с, это была последняя статья из серии «Простая и декларативная установка NixOS». Сама работа над серией, признаюсь честно, очень‑очень затянулась — первую часть(которая стала моей первой статьёй на хабре) ещё в августе, а уже начало октября.
Тем не менее, я старался по мере своих возможностей. И всё так же жду любых советов, критики, которые помогут мне либо переписать нынешние статьи, либо создать новые, более качественные.
Источники, с которыми я работал:
https://nixos‑and‑flakes.thiscute.world/nixos‑with‑flakes/introduction‑to‑flakes
https://discourse.nixos.org/t/advice‑on‑multi‑system‑flake‑configuration/74518/5
Сообщество NixOS RU — консультация
Нейросеть Gemini — консультация
Нейросеть DeepSeek — консультация, грамматические правки