blog/install-nixos-with-alpine-live-cd

Install NixOS with Alpine Live CD

某家 VPS 提供商的促销活动重启了,于是以很低的价格入了台带宽、流量、延迟都还不错的 VPS。然而这家提供的预装操作系统比较少,也不能自行上传 ISO。不过还好提供了几个安装镜像可以随便挂载,也提供了 noVNC,于是使用他们提供的 Alpine Live CD 来安装 NixOS。

noVNC

服务商提供了一个 noVNC 窗口。为了切换 TTY,需要发送 Ctrl+Alt+F{1..12} 按键。虽然界面上没有按钮,但是我们可以通过 noVNC 的 RFB API 发送按键。在浏览器菜单中打开开发者工具,在 Console 中定义函数:

function sendCtrlAltFx(keysym, code) {
  rfb.sendKey(XK_Control_L, "ControlLeft", true)
  rfb.sendKey(XK_Alt_L, "AltLeft", true)
  rfb.sendKey(keysym, code, true)
  rfb.sendKey(keysym, code, false)
  rfb.sendKey(XK_Alt_L, "AltLeft", false)
  rfb.sendKey(XK_Control_L, "ControlLeft", false)
}

使用方法:sendCtrlAltFx(XK_F1, "F1"),第二个参数为 web API 的 KeyboardEvent.code

为了能粘贴一长串 key,定义函数:

function sendString(str) {
  let i = 0
  const t = setInterval(() => {
    if (i >= str.length) clearInterval(t)
    rfb.sendKey(str.charCodeAt(i), 'Key' + str.charAt(i).toUpperCase())
    i++
  }, 200)
}

使用方法:sendString('ssh-ed25519 AAAA....')

配置 Alpine Live CD

插入 Alpine Live CD,可以看到网络都没有配置。先配置网络。

root# vi /etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
root# /etc/init.d/networking restart

然后发现 Alpine Linux 的软件源也没有配置。

root# vi /etc/apk/repositories
/media/cdrom/apks
http://dl-3.alpinelinux.org/alpine/v3.10/main

安装必要的工具。

root# apk update
root# apk add parted e2fsprogs btrfs-progs squashfs-tools util-linux

安装 NixOS

下载 ISO,挂载。

root# curl -fLO https://channels.nixos.org/nixos-21.05/latest-nixos-minimal-x86_64-linux.iso
root# mkdir /iso
root# mount latest-nixos-minimal-x86_64-linux.iso /iso

我们的 RAM 只有 1.6 GiB,tmpfs 是放不下 NixOS Live CD 里面的文件的。分区时分出一块地方,用于放 squashfs 解压出来的东西。

root# parted /dev/vda
(parted) mklabel msdos
(parted) mkpart primary btrfs 1MiB -5GiB  # 最终安装的分区
(parted) mkpart primary ext4 -5GiB 100%  # 解压 NixOS Live CD squashfs 的地方

创建文件系统。这家用的都是 SSD,但是笨笨 btrfs 检测不到,我们手动指定元数据的格式为 single

root# mkfs.btrfs -L nixos -m single /dev/vda1
root# mkfs.ext4 -L livecd /dev/vda2

然后把 Live CD 中的 Nix store 文件解压到 /dev/vda2

root# mkdir /livecd
root# mount /dev/vda2 /livecd
root# mkdir /livecd/nix
root# unsquashfs -d /livecd/nix/store /iso/nix-store.squashfs '*'

解压好了就可以删除文件了,节约内存。

root# umount /iso
root# rm latest-nixos-minimal-x86_64-linux.iso

然后换根到 /livecd,这里参考了 NixOS wiki 的 Install from Linux 页面NixOS 论坛上 Shados 的回答

root# cd /livecd
root# mkdir -p etc dev proc sys
root# cp /etc/resolv.conf etc
root# for fn in dev proc sys; do mount --bind /$fn $fn; done
root# INIT=$(find . -type f -path '*nixos*/init')
root# BASH=$(find . -type f -path '*/bin/bash' | tail -n 1)
root# sed -i "s|exec systemd|exec /$BASH|" $INIT
root# mkdir old_root
root# mount --make-rprivate /
root# pivot_root . old_root
root# $INIT

换根后就能用 NixOS 的安装器了。

root# mount /dev/vda1 /mnt
root# nixos-generate-config --root /mnt
root# vim /mnt/etc/nixos/configuration.nix
root# NIX_PATH="nixpkgs=channel:nixos-21.05" nixos-install

记得设置 root 密码或添加 SSH key,不然会被锁在服务器门外。如果执行安装器时忘记设定可以使用 nixos-enter 换根修改命令。

root# nixos-enter --root /mnt
root# passwd root

重启后就进入 NixOS 了。

恢复分区

前面分了个 5 GiB 的分区用来解压 NixOS Live CD,安装好后可以删了。分个小的当 swap。

我们无法搬动自己脚下的石头。插入 Alpine Live CD,更换启动顺序为 (1) CDROM (2) Hard Disk。启动,然后像之前那样安装好 parted。

root# parted /dev/vda
(parted) rm 2
(parted) resizepart 1 -2GiB
(parted) mkpart primary linux-swap -2GiB 100%

然后将启动顺序改回来,重启进入 NixOS。

user$ sudo btrfs filesystem resize max /
user$ sudo swapon /dev/vda2
user$ sudo nixos-generate-config
user$ sudo nix-channel --update
user$ sudo nixos-rebuild boot
user$ sudo reboot

About Me