我喜欢的 NixOS 声明式安装方式

Michael Stapelberg 工具

摘要

一份关于使用 nixos-anywhere 等工具通过网络声明式安装 NixOS 的指南,重点强调在版本控制下管理配置文件。

<p>在我的一篇<a href="/posts/2023-10-25-my-all-flash-zfs-network-storage-build/#previously-coreos">网络存储 PC 构建</a>中,我寻找了 <a href="https://www.flatcar.org/">Flatcar Container Linux</a> 的替代品,并(在隔了将近 10 年后)再次尝试了 <a href="https://nixos.org/">NixOS</a>。安装 NixOS 有多种方式,本文将介绍我喜欢的安装方式:通过网络进行完全声明式安装,适用于物理硬件或虚拟机。</p> <h2 id="declarative">介绍:声明式?</h2> <p>术语<a href="https://en.wikipedia.org/wiki/Declarative_programming">声明式</a>意味着你描述<em>什么</em>应该被完成,而不是如何完成。对于 NixOS 来说,这意味着你声明你的系统应该包含哪些软件(例如添加到配置选项 <a href="https://search.nixos.org/options?show=environment.systemPackages"><code>environment.systemPackages</code></a>,或启用一个模块),而不是运行 <code>apt install</code>。</p> <p>声明式方法的一个好处是你的系统遵循你的配置,因此通过回滚配置更改,你也可以干净地回滚系统的更改。</p> <p>我喜欢在版本控制下管理声明式配置文件,通常使用 Git。</p> <p>当我最初设置当前的网络存储构建时,我选择了 CoreOS(后来的 Flatcar Container Linux),因为它是一个自动更新的基础系统,并带有声明式的 <a href="https://cloud-init.io/">cloud-init</a> 配置。</p> <h2 id="ways">安装 NixOS 的方式</h2> <h3 id="graphical-install">图形安装程序:仅适用于桌面</h3> <p><a href="https://nixos.org/manual/nixos/stable/#ch-installation">NixOS 手册的“安装”部分</a>描述了一个图形安装程序(“针对桌面用户”,基于 <a href="https://en.wikipedia.org/wiki/Calamares_(software)">Calamares</a> 系统安装程序,于 2022 年添加)和一个手动安装程序。</p> <p>使用图形安装程序,将 NixOS 安装到磁盘很容易:只要足够频繁地确认默认值,你就会得到一个可用的系统。但也有一些缺点:</p> <ul> <li>安装后需要手动启用 SSH——必须本地操作,不能通过网络。</li> <li>图形安装程序会为你生成初始 NixOS 配置,但无法注入你自己的初始 NixOS 配置。</li> </ul> <p>图形安装程序显然不适用于远程安装或自动化安装。</p> <h3 id="manual-install">手动安装</h3> <p>另一方面,手动安装程序对我来说过于手动:展开 <a href="https://nixos.org/manual/nixos/stable/#sec-installation-manual-summary">NixOS 手册的安装摘要</a>节中的“示例 2”和“示例 3”即可了解大致流程。明确地说,这些步骤非常可行,但我不想在紧急情况下以这种方式安装系统。首先,手动操作在压力下容易出错。其次,交互式地复制粘贴命令与编写声明式配置文件完全相反。</p> <h3 id="nixos-anywhere">网络安装:nixos-anywhere</h3> <p>理想情况下,我希望在舒适的自己的电脑上完成大部分安装,这意味着安装程序必须可以通过网络使用。同时,我希望机器在安装后立即启动并使用一个可用的初始 NixOS 配置(无需手动步骤!)。</p> <p>幸运的是,有一个(社区提供的)解决方案:<a href="https://github.com/nix-community/nixos-anywhere">nixos-anywhere</a>。你负责启动一个 NixOS 安装程序,然后运行一条命令,nixos-anywhere 就会通过 SSH 连接到该安装程序,对你的磁盘进行分区,并将 NixOS 安装到磁盘上。值得注意的是,nixos-anywhere 是以声明式方式配置的,因此你可以随时重复这一步。</p> <p>(我知道 nixos-anywhere 甚至可以 SSH 到任意系统并通过 kexec 重启它们进入 NixOS 安装程序,这确实是一个很酷的技巧,但我更喜欢明确启动安装程序的方法,因为在我看来这风险更低,而且更通用/可重复。)</p> <h2 id="setup-nix">设置:安装 Nix</h2> <p>我想在其中一台机器上使用 NixOS,但(目前)不在我的主力桌面 PC 上使用。</p> <p>因此,我仅在 Arch Linux 上安装了 <code>nix</code> 工具(用于构建,即使不运行 NixOS):</p> <pre tabindex="0"><code>% sudo pacman -S nix % sudo groupadd -r nixbld % for n in $(seq 1 24); do sudo useradd -c &#34;Nix build user $n&#34; \ -d /var/empty -g nixbld -G nixbld -M -N -r -s &#34;$(which nologin)&#34; \ nixbld$n; done % sudo systemctl enable --now nix-daemon.socket </code></pre><p>现在,运行 <code>nix-shell -p hello</code> 应该会进入一个安装了 GNU hello 包的新 shell:</p> <pre tabindex="0"><code>% export NIX_PATH=nixpkgs=channel:nixos-25.05 % nix-shell -p hello hello [nix-shell:/tmp]$ hello Hello, world! </code></pre><p>顺便说一下,<a href="https://wiki.archlinux.org/title/Nix">Arch Linux 维基上的 Nix 页面</a>解释了如何使用 nix 安装软件包,但这不是我感兴趣的内容:我只想远程管理 NixOS 系统。</p> <h2 id="own-installer">构建你自己的安装程序</h2> <p>之前我说“你负责启动一个 NixOS 安装程序”,这非常简单:将 ISO 镜像写入 U 盘,然后从该 U 盘启动你的机器(或者选择 ISO 并启动你的 VM)。</p> <p>但在我们能够通过 SSH 远程登录之前,需要手动设置一个密码。我还需要使用 <code>TERM=xterm</code> 环境变量进行 SSH,因为 rxvt-unicode(我偏好的终端)的 termcap 文件不包含在默认的 NixOS 安装程序环境中。同样,我配置的区域设置无法正常工作,我偏好的 shell(Zsh)也不可用。</p> <p>如果安装程序预配置了一个便利的环境,那不是更好吗?</p> <p>对于其他 Linux 发行版,如 Debian、Fedora 或 Arch Linux,我不会尝试重建官方的安装程序 ISO 镜像。我相信它们的流程和工具都很好,但我也确信这是我需要额外学习、调试和维护的一件事。</p> <p>但是,构建 NixOS 安装程序与配置常规 NixOS 系统<em>非常相似</em>:相同的配置,相同的构建工具。该过程在 <a href="https://wiki.nixos.org/wiki/Creating_a_NixOS_live_CD">官方 NixOS 维基</a> 中有文档说明。</p> <p>我将通常放入 <code>configuration.nix</code> 的自定义项复制过来,从 <code>nixpkgs</code> 导入 <code>installation-cd-minimal.nix</code> 模块,并将结果放入 <code>iso.nix</code> 文件中:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;"><code class="language-nix" data-lang="nix"><span style="display:flex;"><span>{ config<span style="color:#666">,</span> pkgs<span style="color:#666">,</span> <span style="color:#666">...</span> }: </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>{ </span></span><span style="display:flex;"><span> imports <span style="color:#666">=</span> [ </span></span><span style="display:flex;"><span> <span style="color:#235388">&lt;nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix&gt;</span> </span></span><span style="display:flex;"><span> <span style="color:#235388">&lt;nixpkgs/nixos/modules/installer/cd-dvd/channel.nix&gt;</span> </span></span><span style="display:flex;"><span> ]; </span></span><span style="display:flex;"><span> </span></span><span style="display:flex; background-color:#d8d8d8"><span> i18n<span style="color:#666">.</span>supportedLocales <span style="color:#666">=</span> [ </span></span><span style="display:flex; background-color:#d8d8d8"><span> <span style="color:#4070a0">&#34;en_DK.UTF-8/UTF-8&#34;</span> </span></span><span style="dis
查看原文
查看缓存全文

缓存时间: 2026/05/16 03:33

# 我喜欢如何使用声明式方法安装 NixOS 来源:https://michael.stapelberg.ch/posts/2025-06-01-nixos-installation-declarative/ ## 目录 - [介绍:声明式?](#declarative) - [安装 NixOS 的方式](#ways) - [图形安装器:仅限桌面](#graphical-install) - [手动安装](#manual-install) - [网络安装:nixos-anywhere](#nixos-anywhere) - [准备工作:安装 Nix](#setup-nix) - [构建自己的安装器](#own-installer) - [启用 Nix Flakes](#enabling-flakes) - [(重)安装步骤](#reinstall-steps) - [安装后步骤](#post-installation-steps) - [进行更改](#making-changes) - [结论](#conclusion) 为我的一个 [网络存储 PC 构建项目](https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/#previously-coreos) 寻找 Flatcar Container Linux 的替代品时,我再次(时隔将近 10 年)尝试了 [NixOS](https://nixos.org/)。安装 NixOS 有很多种方式,在这篇文章中,我将介绍我喜欢的在物理硬件或虚拟机上安装 NixOS 的方法:通过网络并完全声明式。 ## 介绍:声明式? 术语 [声明式](https://en.wikipedia.org/wiki/Declarative_programming) 意味着你描述**要完成什么**,而不是如何完成。对于 NixOS 来说,这意味着你声明你希望系统包含哪些软件(添加到配置选项 `environment.systemPackages`,或启用某个模块),而不是运行类似 `apt install` 这样的命令。声明式方法的一个好特性是你的系统会跟随你的配置变化,因此通过回滚配置更改,你也可以干净地回滚系统更改。我喜欢将声明式配置文件放在版本控制下管理,通常使用 Git。 当我最初搭建目前使用的网络存储时,我选择了 CoreOS(后来的 Flatcar Container Linux),因为它是一个自动更新的基础系统,带有声明式的 [cloud-init](https://cloud-init.io/) 配置。 ## 安装 NixOS 的方式 ### 图形安装器:仅限桌面 NixOS 手册的“安装”章节描述了一个图形安装器(“面向桌面用户”,基于 [Calamares](https://en.wikipedia.org/wiki/Calamares_(software)) 系统安装器,于 2022 年添加)以及一个手动安装器。使用图形安装器可以轻松地将 NixOS 安装到磁盘:只需足够多次确认默认选项,最终便会得到一个可用的系统。但有一些缺点: - 安装后需要手动启用 SSH——需要本地操作,不能通过网络。 - 图形安装器会为你生成一个初始的 NixOS 配置,但无法注入你自己的初始配置。 显然,图形安装器并不适用于远程安装或自动安装。 ### 手动安装 而手动安装器则对我而言又过于手工:展开 NixOS 手册安装摘要中的“示例2”和“示例3”即可了解。平心而论,这些步骤完全可以执行,但我并不想在匆忙中用这种方式安装系统。首先,手动流程在压力下容易出错。而且,交互式地复制粘贴命令恰好与编写声明式配置文件相反。 ### 网络安装:nixos-anywhere 理想情况下,我希望大部分安装工作可以在自己的电脑上舒适地完成,这意味着安装器必须能通过网络使用。此外,我希望机器在安装后立即启动并带有可用的初始 NixOS 配置(无需手动步骤!)。幸运的是,有一个(社区提供的)解决方案:[nixos-anywhere](https://github.com/nix-community/nixos-anywhere)。你负责启动一个 NixOS 安装器,然后运行一条命令,nixos-anywhere 便会通过 SSH 进入该安装器,分区磁盘并将 NixOS 安装到磁盘。值得注意的是,nixos-anywhere 的配置是声明式的,因此你可以在任何时间重复此步骤。(我知道 nixos-anywhere 甚至能够 SSH 到任意系统并通过 kexec 将其重启到 NixOS 安装器中,这无疑是一个很酷的特技,但我更喜欢显式地启动安装器,因为这样风险更小、通用性更好且可重复性更强。) ## 准备工作:安装 Nix 我希望在其中一台机器上使用 NixOS,但(目前)不用于我的主桌面 PC。因此,我仅在 Arch Linux 上安装了 `nix` 工具(用于构建,即使不运行 NixOS): ``` % sudo pacman -S nix % sudo groupadd -r nixbld % for n in $(seq 1 24); do sudo useradd -c "Nix build user $n" \ -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(which nologin)" \ nixbld$n; done % sudo systemctl enable --now nix-daemon.socket ``` 现在,运行 `nix-shell -p hello` 应该会进入一个新的 shell,其中安装了 GNU hello 包: ``` % export NIX_PATH=nixpkgs=channel:nixos-25.05 % nix-shell -p hello hello [nix-shell:/tmp]$ hello Hello, world! ``` 顺便提一下,[Arch Linux 维基上的 Nix 页面](https://wiki.archlinux.org/title/Nix) 讲解了如何使用 nix 安装包,但这并非我的兴趣所在:我只想远程管理 NixOS 系统。 ## 构建自己的安装器 之前我提到“你负责启动一个 NixOS 安装器”,这很简单:将 ISO 镜像写入 U 盘,然后从它启动机器(或选择 ISO 并启动 VM)。但在此之前,我们需要手动设置密码才能通过 SSH 远程登录。另外,我需要使用 `TERM=xterm` 环境变量进行 SSH,因为默认的 NixOS 安装器环境不包含 rxvt-unicode(我喜欢的终端)的 termcap 文件。同样,我配置的 locale 无法工作,我喜欢的 shell(Zsh)也不可用。如果安装器预先配置了一个便捷的环境,岂不是好得多? 对于其他 Linux 发行版,如 Debian、Fedora 或 Arch Linux,我不会尝试重新构建官方的安装器 ISO 镜像。我相信它们的流程和工具工作得很好,但我也确信这是我需要学习、调试和维护的额外内容。然而,构建一个 NixOS 安装器*与配置一个普通的 NixOS 系统非常相似*:相同的配置,相同的构建工具。该过程在 [官方 NixOS 维基](https://wiki.nixos.org/wiki/Creating_a_NixOS_live_CD) 中有文档说明。我将通常放在 `configuration.nix` 中的自定义项复制过来,从 `nixpkgs` 导入 `installation-cd-minimal.nix` 模块,并将结果放在 `iso.nix` 文件中: ```nix { config, pkgs, ... }: { imports = [ <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix> ]; i18n.supportedLocales = [ "en_DK.UTF-8/UTF-8" "de_DE.UTF-8/UTF-8" "de_CH.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" ]; i18n.defaultLocale = "en_US.UTF-8"; security.sudo.wheelNeedsPassword = false; users.users.michael = { openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5secret" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5key" ]; isNormalUser = true; description = "Michael Stapelberg"; extraGroups = [ "wheel" ]; initialPassword = "SGZ3odMZIesxTuh2Y2pUaJA"; # 本文随机生成 shell = pkgs.zsh; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ git # 用于检出 github.com/stapelberg/configfiles rsync zsh vim emacs wget curl rxvt-unicode # 用于 terminfo lshw ]; programs.zsh.enable = true; services.openssh.enable = true; # 此值决定了从该系统中获取有状态数据(如文件位置和数据库版本)的默认设置所依据的 NixOS 发行版。 # 完全可以且推荐将此值保留为该系统首次安装时的发行版版本。 # 在更改此值之前,请阅读该选项的文档 # (例如 man configuration.nix 或 https://nixos.org/nixos/options.html)。 system.stateVersion = "25.05"; # 你读过注释了吗? } ``` 要构建 ISO 镜像,我设置 `NIX_PATH` 环境变量,使 `nix-build` 指向 `iso.nix` 文件并选择上游的 NixOS 25.05 频道: ``` % export NIX_PATH=nixos-config=$PWD/iso.nix:nixpkgs=channel:nixos-25.05 % nix-build '' -A config.system.build.isoImage ``` 在我的 [2025 高端 Linux PC](https://michael.stapelberg.ch/posts/2025-05-15-my-2025-high-end-linux-pc/) 上大约 1.5 分钟后,安装器 ISO 位于 `result/iso/nixos-minimal-25.05.802216.55d1f923c480-x86_64-linux.iso`(我的情况大小约 1.46 GB)。 ## 启用 Nix Flakes 不幸的是,尽管“实验性”的新命令行界面(CLI)已经可用 5 年以上,nix 项目仍未将其设为默认启用,因此我们需要创建一个配置文件并启用现代 `nix-command` 界面: ``` % mkdir -p ~/.config/nix % echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf ``` 如何区分新旧?旧命令是连字符式(`nix-build`),新命令由空格分隔(`nix build`)。你可能会注意到我还启用了 [Nix flakes](https://wiki.nixos.org/wiki/Flakes),我使用 flakes 是为了让我的 nix 构建是封闭的,并锁定到某个特定的 nixpkgs 修订版本以及我希望包含在构建中的任何其他 nix 模块。我喜欢将 flakes 比作其他编程环境中的版本锁文件:其思想是,5 个月后构建系统将得到与今天相同的结果。 要验证 flakes 是否正常工作,运行 `nix shell`(而不是 `nix-shell`): ``` % nix shell nixpkgs#hello /tmp 2 % hello Hello, world! ``` ## (重)安装步骤 作为参考,以下是我用于在 Proxmox 中为 NixOS 创建新 VM 的配置。最重要的设置是 `bios=ovmf`(= UEFI 启动,非默认),这样我就可以在物理机和 VM 上使用相同的引导加载器配置: [Proxmox VM 创建对话框截图](https://michael.stapelberg.ch/posts/2025-06-01-nixos-installation-declarative/2025-05-17-proxmox-frigaten.jpg) 在启动我们的(未签名)安装器之前,我们需要进入 UEFI 设置并禁用 Secure Boot。请注意,例如 Proxmox 默认启用了 Secure Boot。然后,在目标系统上启动自定义的安装器 ISO,并确保 `ssh [email protected]` 无需密码即可工作。 声明一个 `flake.nix`,内容如下: ```nix { inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; disko.url = "github:nix-community/disko"; # 使用与 nixpkgs 相同的版本 disko.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = { nixpkgs, disko, ... }: let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; config.allowUnfree = false; }; in { nixosConfigurations.zammadn = nixpkgs.lib.nixosSystem { inherit system; inherit pkgs; modules = [ disko.nixosModules.disko ./configuration.nix ]; }; formatter.${system} = pkgs.nixfmt-tree; }; } ``` 在 `disk-config.nix` 中声明你的磁盘配置: ```nix { lib, ... }: { disko.devices = { disk = { main = { device = lib.mkDefault "/dev/sda"; type = "disk"; content = { type = "gpt"; partitions = { ESP = { type = "EF00"; size = "500M"; content = { type = "filesystem"; format = "vfat"; mountpoint = "/boot"; mountOptions = [ "umask=0077" ]; }; }; root = { size = "100%"; content = { type = "filesystem"; format = "ext4"; mountpoint = "/"; }; }; }; }; }; }; }; } ``` 在 `configuration.nix` 中声明你期望的 NixOS 配置: ```nix { modulesPath, lib, pkgs, ... }: { imports = [ (modulesPath + "/installer/scan/not-detected.nix") ./hardware-configuration.nix ./disk-config.nix ]; # 将 michael 添加为受信任用户意味着 # 我们可以通过 SSH 升级系统(参见 Makefile)。 nix.settings.trusted-users = [ "michael" "root" ]; # 每周清理 Nix 存储。 nix.gc = { automatic = true; dates = "weekly"; options = "--delete-older-than 7d"; }; boot.loader.systemd-boot = { enable = true; configurationLimit = 10; }; boot.loader.efi.canTouchEfiVariables = true; networking.hostName = "zammadn"; time.timeZone = "Europe/Zurich"; # 使用 systemd 进行网络管理 services.resolved.enable = true; networking.useDHCP = false; systemd.network.enable = true; systemd.network.networks."10-e" = { matchConfig.Name = "e*"; # enp9s0 (10G) 或 enp8s0 (1G) networkConfig = { IPv6AcceptRA = true; DHCP = "yes"; }; }; i18n.supportedLocales = [ "en_DK.UTF-8/UTF-8" "de_DE.UTF-8/UTF-8" "de_CH.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" ]; i18n.defaultLocale = "en_US.UTF-8"; users.mutableUsers = false; security.sudo.wheelNeedsPassword = false; users.users.michael = { openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5secret" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5key" ]; isNormalUser = true; description = "Michael Stapelberg"; extraGroups = [ "networkmanager" "wheel" ]; initialPassword = "install"; # TODO: 修改! shell = pkgs.zsh; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ git # 用于检出 github.com/stapelberg/configfiles rsync zsh vim emacs wget curl ]; programs.zsh.enable = true; services.openssh.enable = true; # 此值决定了从该系统中获取有状态数据(如文件位置和数据库版本)的默认设置所依据的 NixOS 发行版。 # 完全可以且推荐将此值保留为该系统首次安装时的发行版版本。 # 在更改此值之前,请阅读该选项的文档 # (例如 man configuration.nix 或 https://nixos.org/nixos/options.html)。 system.stateVersion = "25.05"; # 你读过注释了吗? } ``` ... 然后锁定它: ``` % nix flake lock ``` 1. 使用 nixos-anywhere,从安装器获取 `hardware-configuration.nix` 并将 NixOS 安装到磁盘: ``` % nix run github:nix-community/nixos-anywhere -- \ --flake .#zammadn \ --generate-hardware-config nixos-generate-config ./hardware-configuration.nix \ --target-host [email protected] ``` 大约一分钟后,我的 VM 就安装好并重启了!完整的 `nixos-anywhere` 安装日志(如果你好奇的话): ``` % nix run github:nix-community/nixos-anywhere -- \ --flake .#wiki \ --generate-hardware-config nixos-generate-config ./hardware-configuration.nix \ --target-host [email protected] Warning: Identity file /tmp/tmp.BT4E7i6eqJ/nixos-anywhere not accessible: No such file or directory. ### Uploading install SSH keys ### /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/tmp/tmp.BT4E7i6eqJ/nixos-anywhere.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys Warning: Permanently added '10.25.0.87' (ED25519) to the list of known hosts. Number of key(s) added: 1 Now try logging into the machine, with: "ssh -i /tmp/tmp.BT4E7i6eqJ/nixos-anywhere -o 'IdentitiesOnly=no' -o 'ConnectTimeout=10' -o 'IdentitiesOnly=yes' -o 'UserKnownHostsFile=/dev/null' -o 'StrictHostKeyChecking=no'" [ . . . ] ```

相似文章

NixOS 与密钥管理

Lobsters Hottest

教程介绍 NixOS 的密钥管理选项,比较 sops-nix、agenix 和 ragenix 工具,并提供使用 sops-nix 进行加密密钥管理的实际示例。

使用Nix的开发环境:四个快速示例

Michael Stapelberg

本教程演示了使用Nix设置开发环境的四种方法,包括交互式一次性使用、配置文件以及密封的Nix Flakes,并以GoCV和OpenCV为例。

将我的 NAS 从 CoreOS/Flatcar Linux 迁移到 NixOS

Michael Stapelberg

Michael Stapelberg 详细介绍了他将一台 NAS 从 CoreOS/Flatcar Linux 迁移到 NixOS 的过程,涵盖了从 Docker 容器逐步过渡到原生 NixOS 模块的步骤,并附有实际示例。