NixOS、Nix 安装与配置笔记

喜闻乐见的晒桌面环节(运行 GNOME 桌面环境的 NixOS,截图于 2018 年 9 月):

摘自 DistroWatch
NixOS 是独立开发的 GNU/Linux 发行,它旨在改进系统配置管理的现状。在 NixOS 中,整个操作系统,包括内核、应用程序、系统软件包、配置文件,统统都由 Nix 包管理器来创建。Nix 将所有软件包以彼此分离的方式进行存储,因此就不存在 /bin/sbin/lib/usr 之类的目录;相反,所有软件包都保存在 /nix/store 中。NixOS 的其他创新特色包括可靠升级、回滚、可重现的系统配置、二进制代码基于源文件的管理模型、多用户包管理。尽管 NixOS 是一份研究性项目,它是一份功能性的及可用的操作系统,能进行硬件检测,使用 KDE Plasma 作为缺省桌面,并采用 systemd 进行系统服务管理。

本文将指导如何用官方安装镜像启动的 Live 系统安装并配置 NixOS。

扫盲:代码(指的是本文出现的所有代码、NixOS 配置文件、Bash 命令和脚本)中每行出现的第一个 # 通常(忽略 # 前面有转义符的情况)有注释的意思,就是说当这个 # 被读取之后,该行的这个符号后面的所有内容都会被忽略(下一行会被正常读取)。如果你不知道 # 的含义,在很大程度上,你不适合阅读这篇文章,请选择更加适合你的发行版。

安装准备

获取镜像文件

前往 NixOS,点击 Graphical live CD, 64-bit Intel/AMD 下载带图形化桌面的安装 ISO 镜像文件(大小约 1G)。当然你也可以根据需要选择 Minimal installation CD, 64-bit Intel/AMD(大小约 0.5G)。

提示:由于 AWS CloudFront 为镜像的下载和软件包的获取提供了加速服务,一般情况下无需担心下载速度。

制作可启动 USB 驱动器

USB 驱动器,也被称为闪存驱动器、USB 记忆棒、U 盘等。可以从 ISO 制作 NixOS LiveUSB 系统,从 UEFI 或 BIOS 系统上直接启动 NixOS 安装环境。因为 SquashFS 的只读性质,关机后所有的更改都会丢失。这样的系统可用于 NixOS 安装、系统维护或者系统恢复。

提示:请先用 lsblk 找到 U 盘并确保没有挂载。
用 U 盘所在分区替换 /dev/sdx,如 /dev/sdb(不要加上数字,也就是说,不要键入 /dev/sdb1 之类的东西)。再用 NixOS 镜像文件所在的完整路径替换 /path/to/nixos.iso

1
dd bs=4M if=/path/to/nixos.iso of=/dev/sdx status=progress && sync

请等待 Sync 完成,所有数据都写入之后再拔掉 U 盘。

进入 Live 环境

重启系统并引导安装介质,NixOS 将会自动为你登录 root 账户。如果你使用了带图形化桌面的镜像文件,输入这个进入桌面:

1
systemctl start display-manager

在进入桌面后,我们建议你使用 Network Manager(桌面底栏提供了这个程序的设置入口)连接上网络。

分区

建立硬盘分区

提示:打开 Konsole(桌面上放置有 Konsle 的图标)继续完成下面的操作。
磁盘若被系统识别到,就会被分配为一个块设备,如 /dev/sda 或者 /dev/nvme0n1。可以使用 lsblk 查看。
结果中以 romloop 或者 airoot 结束的可以被忽略。

对于一个选定的设备,以下的分区是必须要有的:

  • 一个根分区(挂载在根目录)/
  • 如果 UEFI 模式被启用,你还需要一个 EFI 系统分区。

如需修改分区表,使用 Fdisk(UEFI 用户还可以使用 Gdisk)。

使用 Fdisk 分区的可以阅读 NixOS 官方文档的相关章节 了解分区方法,使用 Gdisk 分区的可以看看这个范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
gdisk /dev/sda

Command (? for help): o # 新建一个 GPT 分区表。
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y # 确认后不会将表接入硬盘,只是把操作记录下来而已。

Command (? for help): n # 新建一个分区。
Partition number (1-128, default 1): # 直接回车取默认值。
First sector (34-976773134, default = 2048) or {+-}size{KMGTP}: # 直接回车取默认值。
Last sector (2048-976773134, default = 976773134) or {+-}size{KMGTP}: +1G # EFI 分区建议 512M - 1G。
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): EF00 # EFI 分区。
Changed type of partition to 'EFI System'

Command (? for help): n
Partition number (2-128, default 2):
First sector (34-976773134, default = 2099200) or {+-}size{KMGTP}:
Last sector (2099200-976773134, default = 976773134) or {+-}size{KMGTP}: +100G # 根分区,和其它发行版不同,这里建议尽可能大,因为 Nix 保存下来的文件相当多。
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): # 标准 Linux 分区。
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (3-128, default 3):
First sector (34-976773134, default = 211814400) or {+-}size{KMGTP}:
Last sector (211814400-976773134, default = 976773134) or {+-}size{KMGTP}: +4G # Swap 分区,视情况添加。
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 8200 # Swap 分区。
Changed type of partition to 'Linux swap'

Command (? for help): n
Partition number (4-128, default 4):
First sector (34-976773134, default = 220203008) or {+-}size{KMGTP}:
Last sector (220203008-976773134, default = 976773134) or {+-}size{KMGTP}: # 使用剩余的所有空间。
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): w # 保存更改并写入硬盘。

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y # 最后的确认。

这是我的分区规划,下面几节都会以此方案为范例:

分区 文件系统 挂载点 大小
/dev/sda1 Fat32 /boot 1G
/dev/sda2 Xfs / 100G
/dev/sda3 Swap swap 4G
/dev/sda4 Xfs /home 剩余全部(约 360G)

格式化分区

当分区建立好了, 这些分区都需要使用适当的文件系统进行格式化。举个例子,如果想将 /dev/sda2 格式化成 Ext4, 可以运行:

1
mkfs.ext4 /dev/sda2

如果您创建了交换分区(例如 /dev/sda3),使用 mkswap 将其初始化:

1
mkswap /dev/sda3

还是刚才的例子:

1
2
3
4
mkfs.vfat -F32 /dev/sda1  # 将 /boot 分区格式化成 Fat32。
mkfs.xfs -f /dev/sda2 # 将 / 分区格式化成 Xfs。
mkswap /dev/sda3 # 将 Swap 分区格式化。
mkfs.xfs -f /dev/sda4 # 将 /home 分区格式化成 Xfs。

注意:由于 Nix 本身就提供了版本回退的功能,我们不建议在根分区使用 Btrfs。

挂载分区

首先将根分区挂载到 /mnt,例如:

1
mount /dev/sda2 /mnt

如果使用多个分区,还需要为其他分区创建目录并挂载它们(例如 /mnt/boot/mnt/home)。

1
2
mkdir /mnt/boot
mount /dev/sda1 /mnt/boot

对于 Swap 分区,使用 swapon:

1
swapon /dev/sda3

还是刚才的例子:

1
2
3
4
5
6
mount /dev/sda2 /mnt
mkdir /mnt/boot
mount /dev/sda1 /mnt/boot
mkdir /mnt/home
mount /dev/sda4 /mnt/home
swapon /dev/sda3

注意:如果你知道 ESP 分区是什么的话,我们建议将它挂载到 /boot 而不是 /boot/efi,否则在后面还得进行相关的设定。

配置 NixOS

初始化 NixOS 配置文件

NixOS 配置文件是这个发行版的灵魂所在,它接管了系统几乎所有事务。nixos-generate-config 可以自动建立一个配置文件:

1
nixos-generate-config --root /mnt

编辑 NixOS 配置文件

这一节是成功安装 NixOS 的关键所在。如果没有配置妥当,你有可能得到一个残废的系统。

默认的配置文件包括 hardware-configuration.nixconfiguration.nix 两个。前者记录了你的分区信息,后者记录了剩余的信息。只需要编辑后者就好,前者千万不要碰。

1
nano /mnt/etc/nixos/configuration.nix

这里贴上这个文件的开头注释:

1
2
3
Edit this configuration file to define what should be installed on
your system. Help is available in the configuration.nix(5) man page
and in the NixOS manual (accessible by running ‘nixos-help’).

开头

默认情况下这一部分大概长这样:

1
{ config, pkgs, ... }:

这一行说明一个函数包含至少两个参数,一个是 config,一个是 pkgs。无需理解这是什么回事,也别去管它。

导入相关文件

默认情况下这一部分大概长这样:

1
2
3
4
imports =
[
./hardware-configuration.nix
];

这说明 configuration.nix 被调取的时候会先读取 hardware-configuration.nix

如果你希望将 NixOS 配置文件写成类似于模组的形式,可以阅读官方文档了解更多。但在现在,我们是不需要(也建议)
去修改它的。

引导器

默认的配置与你所选择的启动模式有关,如果是 UEFI 模式,那应该是这样的:

1
boot.loader.systemd-boot.enable = true;

NixOS 读取到这一行后,会安装 systemd-boot 相关的软件包并将 systemd-boot 设置为引导器。

当然,我是不喜欢使用 systemd-boot 的。这时候,没必要将 true 改成 false,直接整行删掉就好(当然也可以在该行的最前面添加 # 号),接下来输入这个:

1
2
3
4
boot.loader.grub.enable = true;
boot.loader.grub.device = "nodev";
boot.loader.grub.efiSupport = true;
boot.loader.efi.canTouchEfiVariables = true;

留意两个细节,一个是引号,只要填的东西不是 truefalse 一律要加引号,不然会被视作变量。另一个是分号,每行结尾都会有的。

nodev 这里不用改,NixOS 会自动将引导器安装到 ESP 分区上。这样子我们就可以将 GRUB 设置为默认的引导器就好了。

BIOS 用户就没得选了,默认就是 GRUB,当然就只有这两行:

1
2
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";

/dev/sda 是你要将 GRUB 安装到的地方(这里不要填 nodev 了哈)。

网络连接

默认情况下这一部分大概长这样:

1
2
networking.hostName = "nixos";
networking.wireless.enable = true;

可以将 nixos 修改为你偏好的主机名称。第二行建议删掉或注释掉,转而使用这个:

1
networking.networkmanager.enable = true;

NixOS 读取到这一行后,会安装 Network Manager 相关的软件包并在开机时启用 Network Manager 并由它接管网络。在图形化桌面下我们通常选择使用这个。

本地化

中国大陆用户请这样设置:

1
2
3
4
5
i18n = {
consoleKeyMap = "us";
defaultLocale = "zh_CN.UTF-8";
supportedLocales = [ "zh_CN.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" ];
};

其中 consoleKeyMap 是键盘布局,一般情况下保持默认就好。defaultLocalesupportedLocales 都是设置 Locale 的,具体区别可以参考 Arch Linux 下的 locale.conflocale.gen

时区

请照做(这是时区,不是地区,中国大陆填 Asia/Shanghai 就好,不要填什么 Asia/Guangzhou 或是 Asia/Beijing):

1
time.timeZone = "Asia/Shanghai";

软件包

据说不少人(包括我在第一次安装的时候)卡在这一步,他们会说这里又没有什么元软件包,安装个 GNOME 还得把所有组件给全部列出来。其实不用这样子的,为什么呢,我们倒回去看看这个:

1
networking.networkmanager.enable = true;

NixOS 读取到这一行后,会安装 Network Manager 相关的软件包并在开机时启用 Network Manager 并由它接管网络。在图形化桌面下我们通常选择使用这个。

这是我说的原话吧,实际上添加这一行后 NixOS 已经为你自动勾选了一堆的软件包,所以在这里你就不用重复添加软件包了。没错 GNOME 和 KDE 也是同理的,有专门的行是留给它们的(可以阅读下文)。当然你重复添加也是没事的。

软件包名填什么呢,请访问 软件包查询页 搜索所需的软件包,确认软件包描述和你预想的一致,然后将 Attribute name 复制粘贴进去,注意不是 Package name,Package name 有些时候会重复的。

当然你也可以用 nix search 干这事,这就和其它包管理器差不多了。

这是我选择的软件包(截至 2018 年 8 月底):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
environment.systemPackages = with pkgs; [
wget
vim
libreoffice-fresh
arc-theme
papirus-icon-theme
neofetch
firefox
git
fcitx
fcitx-configtool
abiword
gnumeric
transmission
];

注意:像 LibreOffice 之类的包,NixOS 提供多个版本,在写入列表之前检查好版本号。

字体

字体不是普通的软件包,它们被 Nix 放置的区域不用,所以要另起一块:

1
2
3
4
5
6
7
8
9
10
11
12
fonts = {
fontconfig.enable = true;
enableFontDir = true;
enableGhostscriptFonts = true;
fonts = with pkgs; [
noto-fonts
noto-fonts-cjk
noto-fonts-emoji
wqy_microhei
wqy_zenhei
];
};

注意:务必将-_ 分清楚。

拓展功能

在开始的时候,你可能已经注意到,整个配置文件基本都是被注释了的。这是因为大多数参数都存在默认值(一般是 false,即不启用),所以我说可以放心删除某一些行。那这里呢,可以看看有些什么:Bash 补全、OpenSSH、防火墙、打印机、声音等等,需要的就启用,不需要拉倒。

1
2
3
4
programs.bash.enableCompletion = true;
services.printing.enable = true;
sound.enable = true;
hardware.pulseaudio.enable = true;

对于我来说,这就够用了。

桌面环境

根据常识,安装桌面环境之前肯定得启用 Xorg 服务:

1
2
services.xserver.enable = true;
services.xserver.layout = "us";

如果你需要触摸板支持,那顺便把它启用吧:

1
services.xserver.libinput.enable = true;

接下来选择一个桌面环境和一个登录管理器,通常是 KDE + SDDM 或 GNOME + GDM,如果是前者:

1
2
services.xserver.displayManager.sddm.enable = true;
services.xserver.desktopManager.plasma5.enable = true;

至于后者:

1
2
services.xserver.displayManager.gdm.enable = true;
services.xserver.desktopManager.gnome3.enable = true;

输入法

推荐使用 Fcitx 框架,加入以下内容:

1
2
3
i18n.inputMethod = {
enabled = "fcitx";
};

Fcitx 已经自带了几种输入法,一般情况下可以满足用户的需求。

ibus 同理:

1
2
3
4
i18n.inputMethod = {
enabled = "ibus";
ibus.engines = with pkgs.ibus-engines; [ libpinyin ];
};

其中,ibus.engines 后面跟得是需要添加的输入法,可以一次性添加多个,用空格隔开。Fcitx 下使用非自带的输入法操作同理。

1
fcitx.engines = with pkgs.fcitx-engines; [ mozc hangul m17n ];

可用的输入法可以查阅 官方文档

用户

这步也可以用 useradd 来完成,和其它发行版一个样。当然既然有配置文件就一次性完成了:

1
2
3
4
5
users.users.bobby285271 =
{ isNormalUser = true;
home = "/home/bobby285271";
description = "Bobby Rong";
extraGroups = [ "wheel" "networkmanager" ];

bobby285271Bobby Rong 替换掉即可。在 extraGroups 中加入 wheel 意味着这个用户可以使用 sudo,加入 networkmanager 意味这个用户可以使用 Network Manager 管理网络连接。

结尾

配置文件以这个(截至 2018 年 8 月)结尾,除非有新的大版本出来而且官方允许你修改它,否则别去碰它。

1
system.stateVersion = "18.03";

我的 NixOS 配置文件

个人的配置文件(2018 年 8 月),仅供参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:

{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];

# Use the systemd-boot EFI boot loader.
# boot.loader.systemd-boot.enable = true;
boot.loader.grub.enable = true;
boot.loader.grub.device = "nodev";
boot.loader.grub.efiSupport = true;
boot.loader.efi.canTouchEfiVariables = true;

networking.hostName = "nixos"; # Define your hostname.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
networking.networkmanager.enable = true;

# Select internationalisation properties.
i18n = {
# consoleFont = "Lat2-Terminus16";
consoleKeyMap = "us";
defaultLocale = "zh_CN.UTF-8";
supportedLocales = [ "zh_CN.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" ];
};

# Set your time zone.
time.timeZone = "Asia/Shanghai";

# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
wget
vim
libreoffice-fresh
adapta-gtk-theme
papirus-icon-theme
neofetch
firefox
git
fcitx
fcitx-configtool
transmission
gptfdisk
dos2unix
gnome3.zenity
];

fonts = {
fontconfig.enable = true;
enableFontDir = true;
enableGhostscriptFonts = true;
fonts = with pkgs; [
noto-fonts
noto-fonts-cjk
noto-fonts-emoji
wqy_microhei
wqy_zenhei
];
};

# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
programs.bash.enableCompletion = true;
# programs.mtr.enable = true;
# programs.gnupg.agent = { enable = true; enableSSHSupport = true; };

# List services that you want to enable:

# Enable the OpenSSH daemon.
# services.openssh.enable = true;

# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;

# Enable CUPS to print documents.
services.printing.enable = true;

# Enable sound.
sound.enable = true;
hardware.pulseaudio.enable = true;

# Enable the X11 windowing system.
services.xserver.enable = true;
services.xserver.layout = "us";
# services.xserver.xkbOptions = "eurosign:e";

# Enable touchpad support.
# services.xserver.libinput.enable = true;
i18n.inputMethod = {
enabled = "fcitx";
};

# Enable the KDE Desktop Environment.
# services.xserver.displayManager.sddm.enable = true;
# services.xserver.desktopManager.plasma5.enable = true;
services.xserver.displayManager.gdm.enable = true;
services.xserver.desktopManager.gnome3.enable = true;

# Define a user account. Don't forget to set a password with ‘passwd’.
# users.extraUsers.guest = {
# isNormalUser = true;
# uid = 1000;
# };
users.users.bobby285271 =
{ isNormalUser = true;
home = "/home/bobby285271";
description = "Bobby Rong";
extraGroups = [ "wheel" "networkmanager" ];
};

# This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database
# servers. You should change this only after NixOS release notes say you
# should.
system.stateVersion = "18.03"; # Did you read the comment?

}

安装

执行安装,祈祷:

1
nixos-install

如果配置文件存在错误,安装会在一开始的时候就中断,修改好后重新运行上面的命令即可。网络出现问题同理。

接下来安装程序会提示你设置一个密码,这个密码是给管理员用的,盲打两次即可。

1
2
3
setting root password...
Enter new UNIX password: ***
Retype new UNIX password: ***

如果你真得祈祷了,输入以下命令后,你将重启并进入新系统:

1
reboot

当然,重启后别忘了为你的普通用户设置密码(如 passwd bobby285271),不然有些登录管理器是不会给你登录的。

NixOS 入门

只需掌握一个命令:

1
nixos-rebuild switch

每次修改完配置文件(/etc/nixos/configuration.nix)就去跑一下,使改动生效。

接下来,请务必认真阅读 官方文档 深入了解 NixOS。

0%