UP | HOME

NixOS 配置

Table of Contents

本节内容正在修缮中,当前内容可能已经过时,仅供参考

包管理

接下来会讨论如何为系统添加额外的包。NixOS 包管理的方式有两种:

  • 配置文件声明:可以在配置文件为系统或用户声明需要安装的包,每次你重新生成系统,NixOS 都会确保本地包含指定的这些包。这是持久的
  • 非持久环境。使用 nix-env 管理软件包安装,升级与卸载。这种方式允许不同软件仓库频道版本的包共存。这也是非 root 用户唯一安装软件包的方式

声明式包管理

configuration.nix 中, 提供用于声明系统环境包含的包的 environment.systemPackages 数组:

environment.systemPackages = [ pkgs.firefox ];  # 将来源于 pkgs(Nixpkgs) 的包安装到系统

配置文件并不是实时生效的 。需要运行 sudo nixos-rebuild switch 来生成当前配置文件描述的系统

配置依赖

对于某些包(例如依赖 D-Bus 或 systemd 服务注册的包),仅仅是安装还是不够的,需要为它们对系统进行一些配置

可以访问选项列表 https://nixos.org/manual/nixos/stable/options.html 来检索需要启用的 NixOS 模块

可以使用以下命令获取在线包仓库中可用的软件包的列表:

nix-env -qaP '*' --description
nixos.firefox   firefox-23.0   Mozilla Firefox - the browser, reloaded
...

通常会输出很多行可以获取的包的信息。第一列输出是属性名(例如 nixos.firefox

nixos 前缀表明当前包是从 nixos 频道获取的

如果想卸载这个包,修改配置后重新生成系统即可

定制软件包

一些软件包会提供一些禁用或启用功能,更改一些特性的选项。例如 Firefox 插件捆绑包(会额外提供一些诸如 Adobe Flash Player 的插件)会提供一个启用 Google Talk 的选项,如此配置便可以:

nixpkgs.config.firefox.enableGoogleTalkPlugin = true;
遗憾的是,Nixpkgs 依然无法提供一种简易查询这些选项的方式

除了高阶选项外,还可以以几乎任意方式调整软件包,例如更改或禁用软件包的依赖项。例如,Nixpkgs 中的 Emacs 软件包默认依赖于 GTK 2。如果你想将其构建为使用 GTK 3 的软件包,可以按如下方式指定:

environment.systemPackages = [ (pkgs.emacs.override { gtk = pkgs.gtk3; }) ];

使用了 override 函数指定了用户定义的参数,意味着 覆写 了一部分原本的参数,构建的包也因此改变了。细看这个语句,gtk 默认是接受 pkgs.gtk2 参数的,使用 pkgs.gtk3 作输入的时候,默认参数已经失效了,于是构建出来的包是依赖 GTK 3 的了

圆括号是必要的,因为在 Nix 语言中,列表构造优先级高于函数。如果不使用括号,列表将会认为它接收了两个元素

还可以使用 overrideAttrs 函数做出更多定制。override 函数的机制是覆写了包输入函数的参数,而 overrideAttrs 允许 覆写 传递给 mkDerivation 的属性 。如此几乎能修改这个包的方方面面,甚至包括源码。如果你想覆写源码输入,可以这样做:

environment.systemPackages = [
  (pkgs.emacs.overrideAttrs (oldAttrs: {
    name = "emacs-25.0-pre";
    src = /path/to/my/emacs/tree;  # 你的源码目录
  }))
];

在这里,pkgs.emacs 被衍生出了一个重新调用 stdenv.mkDerivation 并替换了 name 和 src 属性的版本。然后 overrideAttrs 接收了这个衍生,成为了目前系统环境的 emacs 包

添加自定义包

使用 Nix 语言构建
使用预构建文件

大多数可执行文件都不能在 NixOS 上直接工作,但是将 依赖一起打包容器格式 就可以,常见的容器格式有 flatpaksAppImages

非持久包管理

这种方式不持久是相对于声明式包管理的。声明式包管理可以保证系统的一致性和可复制性,所以是持久的。不过 Ad-Hoc 方式非常灵活

Ad-Hoc 这个词语的起源是拉丁语,意思是“为此”。它通常表示一种针对特定目的,问题或任务的解决方案,而不是一种可以适用于其他情况的通用解决方案

例如,一个政府为了解决一个具体问题而设立的委员会就是一个 ad-hoc 委员会。更宽松地说,它也可以意味着“自发的 ”,“未计划的”或“即兴的”

在 nixos 中,Ad-Hoc 的意义是指可以在一个临时的 shell 环境中使用任何用 nix 打包的程序,而不需要永久地安装它

这样可以方便地创建和使用开发环境,而不影响系统的状态

通过 nix-env 命令,可以像常规发行版那样使用命令安装软件:

nix-env -iA nixos.thunderbird
  • 如果以 root 权限执行此语句,软件包将会被安装到 /nix/var/nix/profiles/default ,并且对 所有用户可见
  • 如果是 普通用户 ,软件包将会安装到 /nix/var/nix/profiles/per-user/username/profile ,并且仅对当前用户可见
  • -A 参数指定了 软件包所属的属性

    如果不带属性,直接匹配 thunderbird 速度会较慢,同时也可能匹配到多个名称相同的包,产生歧义 
    

假设需要更新的包来自于系统频道,可以先更新系统频道,然后重新安装或更新指定包:

nix-channel --update nixos  # 更新系统频道
nix-env -iA nixos.thunderbird  # 再次安装时,此包会被替换为最新版

上面的语句可以指定另外的频道,从而用不同频道的包去代替当前包。如果想用当前包默认的来源升级包,尝试这样做:

nix-channel --update nixos
nix-env -u thunderbird

如果想升级所有包,可以这样:

nix-env -u '*'

但是需要注意, 它并不会升级系统配置中描述的包 ,那些包由 nixos-rebuild switch 命令管理

如果想更新那些包, nixos-rebuild switch --upgrade 即可,它会自动更新频道并更新系统生成

如果想卸载使用命令安装的包,使用以下命令:

nix-env -e thunderbird

此外,用户环境的状态是可以回滚的:

nix-env --rollback

用户管理

类似的,NixOS 支持声明式用户管理和命令行用户管理

声明式用户管理

下面的例子说明声明式用户管理的大致细节:

users.users.alice = {
  isNormalUser = true;
  home = "/home/alice";
  description = "Alice Foobar";
  extraGroups = [ "wheel" "networkmanager" ];
  openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ];
};
  • 根据描述,该用户加入了 wheel 组,意味着它可以使用 sudo 命令提权
  • 此外它还加入了 networkmanager 组,意味着该用户可以配置网络

不过这样创建出来的用户是没有初始密码的,仍需要使用 passwd 命令为其分配密码, 每次重新生成系统的时候不会影响到密码的状态 。对于 ssh 连接,你可以指定认证密钥,只要公钥与私钥匹配就能连接。如果设置 users.mutableUsers 为 False , /etc/passwd/etc/group 目录的内容将与配置文件中描述的一致

例如,如果你从配置文件中删除了某位用户,然后重新生成系统,这个用户就真实消失了。同时通过命令行管理用户的方式将失效

不过你仍然可以通过设置用户的hashedPassword 选项来分配密码

用户 uid 是自动分配的,不过你也可以自行指定:

uid = 1000;

gid 分配也是自动的,同样可以用户定义,也是类似的方法:

users.groups.students.gid = 1000;

命令行式用户管理

创建一个名为 alice 的用户,-m 参数用于给该用户创建 home 目录:

useradd -m alice

为了让 nix 工具集可以为该用户所用,还需要给这个用户打开 login shell(加载用户配置的 shell)。这一步会把 ~/.nix-defexpr 链接 到该用户的目录,这样该用户才能使用 nix 的一系列命令

su - alice -c "true"

还需要为其分配密码,才能登录:

passwd alice
Enter new UNIX password: ***
Retype new UNIX password: ***

可以使用 userdel -r alice 删除该用户, -r 参数用于移除该用户的 home 目录。此外还有 usermodgroupadd , groupmodgroupdel 可以使用

文件系统

使用 fileSystems 来配置文件系统,然后按照挂载点配置文件系统,分区的参数等等:

fileSystems."/data" =
  { device = "/dev/disk/by-label/data";
    fsType = "ext4";
  };

这条配置 生成 /etc/fstab ,系统在开机时会根据这个表文件来挂载分区

  • device 不一定要根据 label 来指定,也可以通过 uuid

    可以用下面的方法查看到这些块的 UUID:
    
    tritium@KOVA ~> lsblk -o name,mountpoint,size,uuid
    NAME MOUNTPOINT         SIZE UUID
    sda                  363.3M
    sdb [SWAP]               2G 1159b63e-3072-4483-b374-78cd487e6460
    sdc                      1T 8108c250-d488-4724-9237-5d926569fbef
    sdd /mnt/wslg/distro     1T 8677e11d-56ab-4ecb-8dfd-8effb322493f
    

在默认情况下,所有被写在配置的分区都会被自动挂载,除非指定了 noauto 的选项:

  • 也可以缺省 fsType 的值,因为它会自动检测文件系统类型

    如果 fstab 内容有误,系统会在启动时显示令人窒息的急救 Shell
    
    为了避免这种情况,可以在 option 里加入 nofail 来确保挂载是异步的且不会严重影响启动
    

显示系统