Arch Linux 配置记录:shim + systemd-boot + UKI + MOK
参考
关键流程
shim-signed 在 AUR,安装阶段必须关闭 Secure Boot。进入系统装好 AUR 包、签名、导入 MOK 后,再进固件开启。
本文使用:
- shim(AUR
shim-signed,微软签名的引导垫片) - systemd-boot(EFI 启动管理器)
- UKI(Unified Kernel Image,统一内核镜像)
- MOK(Machine Owner Key,机器所有者密钥)
- BTRFS(带子卷布局的快照能力)
没有使用:sbctl、GRUB、传统 vmlinuz + initramfs 分离式启动。
TL;DR
- SB 关 → 安装系统(BTRFS 子卷 + UKI + systemd-boot)→ 重启进桌面
- 装 AUR 的
shim-signed→ 生成 MOK key → 签名 systemd-boot 和 UKI mokutil --import→ 重启 → MokManager 确认 → 进固件开 SB → 完成- pacman hook + mkinitcpio post hook 自动签名,此后内核/systemd 更新无需手动操作
- BTRFS 快照提供系统级回滚能力
一、启动链
UEFI Secure Boot
→ shim (BOOTx64.EFI,微软签名)
→ systemd-boot (grubx64.efi,MOK 签名)
→ UKI (arch-linux.efi,MOK 签名)即:UEFI 信任 shim(微软签名)→ shim 通过 MOK 验证 systemd-boot → systemd-boot 通过 shim_lock 协议验证 UKI → 启动内核。
关键技巧:shim 默认加载同目录下的 grubx64.efi。把 systemd-boot 的 EFI 二进制重命名为 grubx64.efi 放到 shim 旁边即可——不是 GRUB,只借了名字。
二、分区布局与 BTRFS 子卷
2.1 分区方案
| 分区 | 大小 | 类型 | 挂载点 | 用途 |
|---|---|---|---|---|
/dev/sdX1 | 1G | EFI System (vfat) | /efi | ESP |
/dev/sdX2 | 剩余 | BTRFS | / | 系统 + 数据 |
/dev/sdX3 | 16G+ | swap | — | 交换空间 |
本文命令中的设备路径请替换为你实际的磁盘。
2.2 创建 BTRFS 子卷
mkfs.btrfs -L arch /dev/sdX2
mount /dev/sdX2 /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
umount /mnt子卷职责:
@— 根文件系统/@home— 用户数据/home,独立于系统快照@snapshots— 只读快照存放位置,挂载到/.snapshots
CachyOS 的完整子卷布局参考
| 子卷 | 挂载点 | 用途 |
|---|---|---|
@ | / | 根文件系统 |
@home | /home | 用户数据 |
@root | /root | root 用户家目录 |
@srv | /srv | 服务数据 |
@cache | /var/cache | 包缓存等可变缓存数据 |
@tmp | /var/tmp | 临时文件 |
@log | /var/log | 日志(隔离防止日志写满根分区) |
2.3 挂载
# 根子卷
mount -o subvol=/@ /dev/sdX2 /mnt
mkdir -p /mnt/{home,.snapshots,efi,boot}
# 用户数据
mount -o subvol=/@home /dev/sdX2 /mnt/home
# 快照目录
mount -o subvol=/@snapshots /dev/sdX2 /mnt/.snapshots
# ESP
mkfs.fat -F32 /dev/sdX1
mount /dev/sdX1 /mnt/efi三、安装基础系统
3.1 pacstrap
pacstrap -K /mnt base base-devel linux linux-firmware \
btrfs-progs intel-ucode \
networkmanager sudo vim zsh \
efibootmgr sbsigntools mokutil注意:
shim-signed在 AUR,不进 pacstrap。完整包列表见文末附录。
3.2 生成 fstab
genfstab -U /mnt >> /mnt/etc/fstab最终 fstab 示例:
# /dev/sdf2 LABEL=arch
UUID=c236f1be-cb6e-4555-884d-885e959130d3 / btrfs rw,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=/@ 0 0
# /dev/sdf2 LABEL=arch
UUID=c236f1be-cb6e-4555-884d-885e959130d3 /home btrfs rw,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=/@home 0 0
# /dev/sdf2 LABEL=arch
UUID=c236f1be-cb6e-4555-884d-885e959130d3 /.snapshots btrfs rw,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=/@snapshots 0 0
# /dev/sdf1
UUID=FB11-EED2 /efi vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro 0 2
# /dev/sdf3
UUID=c40265f9-4bae-4619-a31f-59976d605b43 none swap defaults 0 0挂载参数说明:
| 参数 | 作用 |
|---|---|
noatime | 禁止访问时间戳更新,减少写入 |
compress=zstd:3 | 透明压缩,zstd level 3 兼顾速度与压缩比 |
discard=async | 异步 TRIM,对 SSD 友好 |
space_cache=v2 | BTRFS 第二版空间缓存,提升性能 |
subvol=/@ | 指定挂载的子卷 |
四、基础配置 (chroot)
arch-chroot /mnt4.1 时区、本地化、主机名
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
hwclock --systohc
# 编辑 /etc/locale.gen,取消 en_US.UTF-8 UTF-8 和 zh_CN.UTF-8 UTF-8 的注释
locale-gen
echo "LANG=en_US.UTF-8" > locale.conf
echo "archbox" > /etc/hostname4.2 用户与权限
passwd # 设置 root 密码
useradd -m -G wheel -s /bin/zsh yoimiya
passwd yoimiya # 设置用户密码
EDITOR=vim visudo # 取消 %wheel ALL=(ALL:ALL) ALL 的注释4.3 基础服务
systemctl enable NetworkManager bluetooth五、配置 UKI(统一内核镜像)
5.1 内核命令行
mkdir -p cmdline.d
cat > root.conf << 'EOF'
rootdelay=5 root=UUID=c236f1be-cb6e-4555-884d-885e959130d3 rootflags=subvol=@ rw
EOFrootdelay=5:给 BTRFS 设备 5 秒就绪等待,因为这个示例是移动硬盘rootflags=subvol=@:指定根子卷- 如果需要
quiet或splash,可以追加
5.2 mkinitcpio 配置
确认 /etc/mkinitcpio.conf 中 HOOKS:
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block filesystems fsck)
systemdhook 用于 systemd-based initramfs;filesystems自动处理 BTRFS 多设备挂载等场景。
5.3 定制 preset 生成 UKI
编辑 /etc/mkinitcpio.d/linux.preset:
# linux.preset
ALL_kver="/boot/vmlinuz-linux"
PRESETS=('default')
default_uki="/efi/EFI/Linux/arch-linux.efi"
default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"
default_uki指定 UKI 输出路径。systemd-boot 会自动扫描EFI/Linux/目录下的 EFI 文件作为启动项,无需手动写 loader entries。
生成 UKI(此时未签名):
mkinitcpio -p linux六、搭建 systemd-boot
6.1 安装
bootctl install这会把 systemd-boot 安装到 /efi/EFI/systemd/systemd-bootx64.efi 和 /efi/EFI/BOOT/BOOTx64.EFI(fallback)。
6.2 loader 配置
cat > loader.conf << 'EOF'
default @saved
timeout 3
console-mode keep
editor no
EOFdefault @saved:记住上次启动的选项timeout 3:3 秒选择超时editor no:禁止启动时编辑内核参数(安全考量)
UKI 放在 EFI/Linux/ 下 systemd-boot 自动发现,不需要手写 /efi/loader/entries/*.conf。
6.3 退出 chroot、重启进桌面
exit
umount -R /mnt
reboot # SB 保持关闭,先进桌面七、进桌面后:Secure Boot 配置
此时 Secure Boot 仍然是关闭的。
7.1 安装 shim-signed (AUR)
paru -S shim-signed7.2 信任链概览
| 组件 | ESP 路径 | 签名者 | 被谁信任 |
|---|---|---|---|
| shim | EFI/BOOT/BOOTx64.EFI | 微软 | UEFI 固件 (db) |
| systemd-boot | EFI/BOOT/grubx64.efi | MOK | shim |
| UKI | EFI/Linux/arch-linux.efi | MOK | shim(通过 shim_lock) |
7.3 生成 MOK 密钥对
cd ~
openssl req -newkey rsa:4096 -nodes -keyout MOK.key \
-new -x509 -sha256 -days 3650 \
-subj "/CN=my Machine Owner Key/" \
-out MOK.crt
# 生成 DER 格式证书(供 MokManager 导入)
openssl x509 -outform DER -in MOK.crt -out MOK.cer保护私钥:
sudo mkdir -p /etc/ssl/private/secure_boot
sudo cp MOK.key MOK.crt /etc/ssl/private/secure_boot/
sudo chown root:root /etc/ssl/private/secure_boot/*
sudo chmod 400 /etc/ssl/private/secure_boot/MOK.key务必离线备份私钥和证书。没有私钥,未来无法给新内核签名。
7.4 摆放 shim、签名、创建 EFI 启动项
# 1. 将 systemd-boot 的 fallback EFI 重命名为 grubx64.efi
# (shim 默认加载同名目录下的 grubx64.efi)
mv /efi/EFI/BOOT/BOOTx64.EFI /efi/EFI/BOOT/grubx64.efi
# 2. 把 shim 放到 BOOTx64.EFI 的位置
cp /usr/share/shim-signed/shimx64.efi /efi/EFI/BOOT/BOOTx64.EFI
cp /usr/share/shim-signed/mmx64.efi /efi/EFI/BOOT/
KEY=/etc/ssl/private/secure_boot/MOK.key
CRT=/etc/ssl/private/secure_boot/MOK.crt
# 3. 签名 systemd-boot
sudo sbsign --key $KEY --cert $CRT /efi/EFI/BOOT/grubx64.efi --output /efi/EFI/BOOT/grubx64.efi
# 4. 签名 UKI
sudo sbsign --key $KEY --cert $CRT /efi/EFI/Linux/arch-linux.efi --output /efi/EFI/Linux/arch-linux.efi
# 5. 创建 EFI 启动项(按实际磁盘调整 --disk 和 --part)
sudo efibootmgr --create --disk /dev/sdX --part 1 \
--loader '\EFI\BOOT\BOOTx64.EFI' \
--label 'Arch Linux (shim)' --unicode7.5 导入 MOK 证书
# 把证书放到 ESP,MokManager 需要从 ESP 读取
cp MOK.cer /efi/
# 创建导入请求
sudo mokutil --import MOK.cer
# 按提示输入一个临时密码(MokManager 确认时用)
reboot关键:重启后 shim 检测到待处理的 MOK 导入请求,自动弹出 MokManager 蓝屏界面。选择 "Enroll MOK" → 找到
MOK.cer→ 输入临时密码 → 确认导入 → 重启。证书导入后,所有用 MOK.key 签名的 EFI 文件都将被信任。MOK 导入成功后,进固件重新开启 Secure Boot。
八、自动化签名
手动签名在内核/启动管理器更新时容易忘记。用 hook 自动处理。
8.1 pacman hook:自动签名 systemd-boot
systemd 包更新时会替换 systemd-bootx64.efi,用 pacman hook 在更新后自动签名并部署:
sudo mkdir -p /etc/pacman.d/hooks# /etc/pacman.d/hooks/80-secureboot.hook
[Trigger]
Operation = Install
Operation = Upgrade
Type = Path
Target = usr/lib/systemd/boot/efi/systemd-boot*.efi
[Action]
Description = Signing systemd-boot EFI binary for Secure Boot
When = PostTransaction
Exec = /bin/sh -c 'while read -r f; do /usr/lib/systemd/systemd-sbsign sign --private-key /etc/ssl/private/secure_boot/MOK.key --certificate /etc/ssl/private/secure_boot/MOK.crt --output "${f}.signed" "$f"; done'
Depends = sh
NeedsTargets
systemd-sbsign生成的.signed文件会被bootctl update自动识别和部署到 ESP。
8.2 mkinitcpio post hook:自动签名 UKI
每次 mkinitcpio -p linux 生成新的 UKI 后自动签名:
sudo mkdir -p /etc/initcpio/post#!/usr/bin/env bash
# /etc/initcpio/post/uki-sbsign
uki="$3"
[[ -n "$uki" ]] || exit 0
key=/etc/ssl/private/secure_boot/MOK.key
cert=/etc/ssl/private/secure_boot/MOK.crt
if ! sbverify --cert "$cert" "$uki" &>/dev/null; then
sbsign "$uki" --key "$key" --cert "$cert" --output "$uki"
fisudo chmod +x /etc/initcpio/post/uki-sbsign8.3 验证自动签名
sudo mkinitcpio -p linux
sudo sbverify --list /efi/EFI/Linux/arch-linux.efi输出应包含你的证书信息。
九、最终 ESP 布局
/efi
├── EFI
│ ├── BOOT
│ │ ├── BOOTx64.EFI # shim(微软签名)
│ │ ├── grubx64.efi # systemd-boot(MOK 签名)
│ │ └── mmx64.efi # MokManager
│ ├── Linux
│ │ └── arch-linux.efi # UKI(MOK 签名)
│ └── systemd
│ └── systemd-bootx64.efi # systemd-boot 原始副本
├── loader
│ ├── loader.conf # systemd-boot 配置
│ ├── entries/ # 空——UKI 自动发现
│ └── random-seed
└── MOK.cer # MOK 证书(MokManager 导入后可不保留)十、验证与排错
# 已导入的 MOK 列表
sudo mokutil --list-enrolled
# UKI 签名信息
sudo sbverify --list /efi/EFI/Linux/arch-linux.efi
# systemd-boot 签名信息
sudo sbverify --list /efi/EFI/BOOT/grubx64.efi
# EFI 引导项
sudo efibootmgr -v
# 启动后确认 Secure Boot 状态
dmesg | grep -i secure
# 期望输出:Secure boot enabled若启动时报 prohibited by secure boot policy:
- 检查 MOK 证书是否已在 MokManager 中确认导入
- 用
sbverify --list逐一检查 EFI 文件是否已被正确签名 - 确认系统时间正确(证书有效期检查依赖系统时间)
十一、日常维护速查
| 场景 | 操作 |
|---|---|
内核更新 (linux 包) | mkinitcpio -p linux(post hook 自动签名 UKI)→ 重启 |
| systemd 更新 | pacman hook 自动签名 → bootctl update 部署 → 重启 |
| 手动重建 UKI | sudo mkinitcpio -p linux → 自动签名 |
| 更换 MOK key | 生成新 key → 签名所有 EFI → mokutil --import 新证书 → 重启确认 → mokutil --delete 旧证书 |
新增内核(如 linux-lts) | 写 preset → 生成 UKI → 手动签名 → 重启 |
十二、BTRFS 快照回滚 (Proof of Concept)
BTRFS 子卷布局的核心好处是快照与回滚。
12.1 确认子卷布局
sudo btrfs subvolume list / | grep -E '@$|@home|@snapshots'
mount | grep btrfs12.2 拍快照
# 安装前创建只读快照
sudo btrfs subvolume snapshot -r / /.snapshots/pre-neovim_$(date +%Y%m%d_%H%M%S)
# 安装软件
sudo pacman -S neovim
which nvim && echo "nvim installed"
# 查看快照
sudo btrfs subvolume list -s / | grep pre-neovim12.3 从快照回滚
模拟需要回滚的场景:
# 从 livecd 或另一个系统操作:
# 挂载 BTRFS 顶层(subvolid=5)
sudo mkdir -p /mnt/btrfs
sudo mount -o subvolid=5 /dev/sdX2 /mnt/btrfs
# 挂载 ESP
sudo mkdir -p /mnt/btrfs/efi
sudo mount /dev/sdX1 /mnt/btrfs/efi
# 备份当前的 @
sudo mv /mnt/btrfs/@ /mnt/btrfs/@_broken
# 从快照恢复
sudo btrfs subvolume snapshot /mnt/btrfs/@snapshots/pre-neovim_20260618_143022 /mnt/btrfs/@
reboot重启后系统回到快照时的状态,Neovim 消失。
12.4 清理
# 挂载顶层
sudo mount -o subvolid=5 /dev/sdX2 /mnt/btrfs
# 删除已废弃的备份子卷
sudo btrfs subvolume delete /mnt/btrfs/@_broken
# 清理快照
sudo btrfs subvolume delete /mnt/btrfs/@snapshots/pre-neovim_20260618_143022删除子卷前注意是否有嵌套子卷。用
sudo btrfs subvolume list /mnt/btrfs检查top level字段,先删除嵌套子卷再删父子卷。
十三、与 Gentoo shim + GRUB 方案对比
另一个用 Gentoo + GRUB 做过的 Secure Boot 配置,两者的关键差异:
| Arch 方案(本文) | Gentoo 方案 | |
|---|---|---|
| 引导器 | systemd-boot | GRUB |
| 内核格式 | UKI(单文件) | vmlinuz + initramfs(分离) |
| UKI / 镜像签名 | mkinitcpio post hook 自动 sbsign | 手动 sbsign vmlinuz |
| bootloader 签名 | pacman hook → systemd-sbsign → bootctl update | Portage SECUREBOOT_SIGN_* / 手动 |
| 模块签名 | 无需单独处理(Arch 内核包自带机制) | Portage MODULES_SIGN_* 自动 |
| 自动化程度 | 高(全自动钩子链) | 中(模块自动签,镜像需手动) |
| 快照 | BTRFS 子卷快照 | 无内置(需外部工具) |
两者共同的信任根:shim + MOK,通过 MokManager 一次性确认。
附录:完整包列表 (pacman -Qqe)
7zip
adw-gimp3-git
archlinuxcn-keyring
baobab
base
bluez-utils
chromium
chrony
clash-party-bin
cockpit
code
dconf-editor
direnv
efibootmgr
extension-manager
eza
fastfetch
fd
fzf
gdm
gnome-backgrounds
gnome-characters
gnome-logs
gnome-shell-extension-appindicator
gnome-shell-extension-dash-to-dock
gnome-shell-extension-gsconnect
gnome-shell-extension-vitals
gnome-text-editor
gnome-tweaks
gradia
htop
ibus-rime
intel-ucode
kvantum
kvantum-manjaro
libgda6
libva-nvidia-driver
linux
linux-firmware
linuxqq
loupe
mokutil
nano
noto-fonts-cjk
noto-fonts-emoji
nvidia-open
nvtop
pacman-contrib
papers
papirus-icon-theme
paru
pkgfile
pnpm
ptyxis
qt6-5compat
qt6ct
refine
resources
ripgrep
sbsigntools
shim-signed
showtime
starship
telegram-desktop
tree
ttf-cascadia-mono-nerd
vim
vkmark
wechat-bin
wget
wimlib
xorg-xwininfo
zoxide
zsh-autosuggestions