GitHub ↗

Tetsuya 的多设备 Nix / NixOS / macOS Flake 配置

本节为 . 的项目说明。先看下方摘要,再按需展开具体专题。
展开完整 README 原文

Tetsuya 的多设备 Nix / NixOS / macOS Flake 配置

打开中文配置学习手册 · 学习配置架构 · 更新与故障排查

用一份 flake 管理多台 NixOS 机器和一台 macOS:公共配置抽成 modules/,每台 机器只保留自己的硬件或平台差异项。NixOS 使用 nixosConfigurations,macOS 使用独立的 darwinConfigurations;两者共享锁文件,但不直接共享 Linux 专用模块。

本仓库负责 NixOS 和 macOS 系统层:系统包和服务、硬件或平台差异、启动和 用户组,以及 本地桌面的 NixOS 系统接线。用户级私人编排由 ~/chezmoi 管理, 可公开复用的通用配置由 ~/dotfiles 管理;详细边界见 AGENTS.md。

目录结构

nixos-config/
├── flake.nix                  # 入口:注册所有主机,锁定 nixpkgs 版本
├── flake.lock                 # nixpkgs 的精确版本锁定(换机后照常使用)
├── modules/                   # 系统与平台模块
│   ├── core.nix               # 基础系统:引导、内核、网络、 locale、输入法、zram……
│   ├── desktop.nix            # 桌面:SDDM + Hyprland、PipeWire、字体……
│   ├── home-manager/           # NixOS/Darwin 用户级 Home Manager 配置
│   ├── darwin/                 # macOS / nix-darwin 模块
│   └── zsh.nix                 # NixOS 全局 Zsh
└── hosts/                     # 每台机器一个目录
    ├── aarch64/               # ARM64 虚拟机
    ├── hx90/                   # HX90 工作站
    └── macbook-m1-max/         # Apple Silicon macOS

主机现状

主机 flake 名 状态 说明
ARM64 虚拟机 aarch64 可用 QEMU aarch64-linux,GNOME、PipeWire、SPICE
HX90 工作站 hx90 可用 x86_64,休眠和桌面环境
WSL2 wsl 可用 x86_64,Windows 11 终端环境
Apple Silicon Mac macbook-m1-max 配置已加入,待首次安装 Nix/激活 aarch64-darwin,nix-darwin

macOS 的配置和第一次激活步骤见 docs/macos-nix-darwin.md。 想系统学习这次迁移的设计、日常操作、边界、回滚和扩展方式,见 docs/macos-nix-darwin/README.md。

HX90 的 networking.hostName 与 flake 输出名统一为 hx90,nixos-update 据此选中正确配置;omarchy update 转发到同一快照更新流程。

每台主机的 configuration.nix 只包含:主机名、时区(Asia/Tokyo)、用户 tetsuya、以及该机特有的服务;其余全部 import 共享模块。

模块都在干什么

modules/core.nix — 所有机器共用的底座

  • 引导/内核:systemd-boot + EFI,linuxPackages_latest 最新内核。
  • 网络:NetworkManager。
  • 本地化:默认 locale zh_CN.UTF-8,时间/货币等格式用 ja_JP.UTF-8。
  • 输入法:Fcitx5 + Rime(fcitx5-rime),走 Wayland text-input 协议 (waylandFrontend),GTK 不设 GTK_IM_MODULE,Qt/SDL 仍走显式 IM module。
  • sudo:tetsuya 免密码(单用户工作站)。
  • 服务:打印 (CUPS)、SSH、nix-ld(跑非 Nix 打包的二进制)、Firefox。
  • 键盘映射:keyd 服务由独立的 modules/keyd.nix 公共业务模块声明,所有主机 使用同一份 MINILA-R 配置;详见 docs/keyd.md。
  • zram:zstd 压缩、占内存 50%、优先级 100(高于磁盘 swap),配 vm.swappiness=180。解决 14G 内存机器冷页换出到 NVMe 后切窗口卡半秒的问题。
  • 基础包:git、curl、jq、ripgrep、python3、fnm 等。

modules/desktop.nix — 桌面环境

  • 登录:SDDM(Wayland 模式),Shizuka 主题。主题依赖 KDE QML 模块,所以 同时启用了 Plasma 6——这台机器上 Plasma 也作为备用会话存在。
  • HX90 默认会话:Labwc + Anchor Shell;保留本地 Hyprland 和 Plasma 备用会话。
  • 更新入口:nixos-update 从 ~/nixos-config 创建快照、构建候选并切换; omarchy update 转发到它。
  • 图形栈:Hyprland(含 XWayland)、xdg portal、polkit、gnome-keyring、 power-profiles-daemon。
  • 音频:PipeWire(兼容 ALSA / 32 位 / PulseAudio 客户端)。
  • 蓝牙:blueman。
  • 字体:Noto CJK、JetBrains Mono Nerd Font、emoji、图标字体。
  • 桌面工具:Labwc 使用 Anchor Shell(modules/anchor-shell,Quickshell 顶栏);Hyprland 使用本仓库打包的 Omarchy 兼容 shell。另有 grim/slurp/swappy (截图)、foot/kitty(终端)、pamixer、brightnessctl、nautilus 等。
  • 两处针对性修补:
    • QML2_IMPORT_PATH 指向 kirigami/qt5compat 的 .unwrapped,确保 polkit 图形代理正常工作。
    • amdgpu-dpm 服务:AC 供电时把 Cezanne iGPU 显存频率锁 high、电池时 auto(auto 会在 4K@scale2 合成时每秒在 400/1750MHz 之间跳,表现为掉帧), 并用 udev 规则在电源插拔时重跑。

modules/zsh.nix

全局启用 Zsh 和补全。用户 shell 在各主机 configuration.nix 里指定。

HX90 主机特有的部分

  • 休眠:boot.resumeDevice 指向 NVMe swap 分区。因为 zram 里的页在内存 里,直接休眠会 ENOMEM 失败,所以装了 systemd/system-sleep/10-hibernate-zram.sh: 休眠前把 zram swap 整个 swapoff 到磁盘、把 image_size 调到最小;唤醒后 重置 zram0 并重启 zram-setup 服务恢复优先级配置。
  • logind:电源键/(若存在的)盖子动作按主机配置处理,但禁用"无人值守空闲挂起", 以保证 SSH 任务不会因空闲而中断。
  • snapper:/ 和 /home 各一套自动快照(小时/天/周/月保留策略), 用于本地回滚。注释里写明:这不是加密 NAS 备份的替代品。
  • Docker + Windows VM 工具链:docker、docker-compose、freerdp(RDP)、 cifs-utils(SMB)、restic、btrfs-progs。

日常操作

重装后的 SSH 接管

新系统启动后,如果 Agent 要通过 SSH 接管,可以先把本仓库复制到新系统,并确认 安装时已经为用户设置密码,然后执行:

cd ~/nixos-config
./scripts/enable-ssh-bootstrap.sh

脚本会临时叠加 SSH、22 端口防火墙规则和密码登录配置,执行一次 nixos-rebuild switch,最后打印本机 IP。它不会修改仓库或 /etc/nixos/configuration.nix。 SSH 使用用户密码登录,禁止 root 直接登录;接管完成后建议改回密钥登录或关闭 SSH。

# 应用配置(在本机上,<name> 换成当前机器的 flake 名)
sudo nixos-rebuild switch --flake ~/nixos-config#hx90      # HX90
sudo nixos-rebuild switch --flake ~/nixos-config#aarch64   # ARM64 虚拟机

# 更新 nixpkgs 锁定(谨慎:当前刻意钉在 nixos-26.05 迁移基线)
nix flake update
sudo nixos-rebuild switch --flake ~/nixos-config#<name>

# 只检查并更新 Shizuka SDDM 主题
nix flake update shizuka --flake ~/nixos-config
sudo nixos-rebuild switch --flake ~/nixos-config#<name>

# 测试构建(不切换)
nixos-rebuild build --flake ~/nixos-config#<name>

# 回滚
sudo nixos-rebuild switch --rollback

omarchy update 已转发到本机 nixos-update,更新独立 flake 输入前创建 root/home 快照,构建候选后切换。不会更新 chezmoi 或 dotfiles。 操作与恢复见 docs/nixos-update-snapshots.md。 Nixarchy 外部依赖已移除,接管清单见 docs/nixarchy-removal.md。 全局 AI 环境与 skills 接线见 docs/agent-environment.md。

Shizuka 登录主题的源码、flake.lock 锁定版本、NixOS generation 和 SDDM 实际加载 路径之间的关系,见该文档中的「Shizuka 的版本到底由哪里管理」章节。注销登录不会 自动更新 Shizuka;更新 GitHub 后必须更新 flake.lock 并重新构建切换。

想系统学习 NixOS 的设计取舍和本仓库的实践方式,可从 docs/nixos-learning-notes.md 开始。

更新前自动快照、NixOS generation、/home 恢复和 Omarchy 插件更新的完整设计见 docs/nixos-update-snapshots.md。

统一更新命令是 nixos-update;正式更新请使用它,以确保更新前自动创建 / 与 /home 快照,并同时更新 Omarchy 插件。

NixOS 与 chezmoi 的用户配置边界

本仓库通过 Home Manager 管理 NixOS 专属的用户配置,入口是 modules/home-manager/nixos-user.nix。这里适合放:

  • 依赖 Nix store 软件包的用户配置、用户级 systemd service;
  • Labwc / Anchor Shell 与 Omarchy 兼容资源的 NixOS 接线;
  • 只在 NixOS 上使用的用户环境变量、GUI 默认值和配置文件。

跨发行版或跨平台的用户偏好继续由 ~/chezmoi 管理,例如 Fcitx5、终端、tmux、 Voxtype 和通用脚本。macOS 专属的 AeroSpace、Karabiner、Hammerspoon、skhd 则由 本仓库的 Darwin Home Manager 管理。一个具体文件只能由一个系统管理:迁移到 Home Manager 后必须从 chezmoi 删除对应文件,反之亦然。NixOS 的用户配置通过 sudo nixos-rebuild switch --flake ~/nixos-config#<主机名> 生效;chezmoi 配置仍通过 chezmoi apply 生效。这样在 Fedora、Arch、Debian 或 macOS 上使用 chezmoi 时, 不会依赖 NixOS 的模块或 Nix store 路径。

仓库地图

换机时“配置回来”不等于只部署本仓库。主要配置由以下三个仓库组成:

仓库 地址 管什么 换机时的动作
nixos-config(本仓库) iamcheyan/nixos-config 系统层和桌面组件 clone + 生成 hardware 文件 + 注册主机 + rebuild
chezmoi(PRIVATE) iamcheyan/chezmoi 用户级私人软件与自动化编排 认证 clone + chezmoi apply
dotfiles(PUBLIC) iamcheyan/dotfiles 通用 Zsh、Neovim 与公开 CLI 配置 clone + dotlink link

不会自动回来的(换机前自行处理):

  • ~/.ssh/、~/.gitconfig —— chezmoi 刻意不管(密钥不入库)。新机器第一件事 是手动迁移 SSH key(或先用 HTTPS + token 克隆),否则 git@github.com: 全部拉不动。
  • 桌面运行时状态 —— 生成物,按需重新设置。
  • 浏览器数据、keyring 密码、Docker 卷等机器本地数据 —— 与配置仓库无关。

换一台新机器怎么用

场景 A:全新安装 NixOS

  1. 装系统:用官方 ISO 正常安装(分区时参考现有机器的布局:btrfs, root, home, and nix 三个子卷 + ESP + swap 分区,这样 hardware 文件结构一致, nix 子卷还能让 /nix/store 在重装后保留缓存)。
  2. 把仓库弄到新机器上(U 盘、SSH 或先装 git):
    git clone <你的仓库地址> ~/nixos-config
    
  3. 生成新主机的硬件文件——这是唯一必须在本机生成的部分:
    # 已 chroot 进新系统时:
    nixos-generate-config --root /mnt
    # 新系统已能启动时(文件在 /etc/nixos/ 下):
    cp /etc/nixos/hardware-configuration.nix ~/nixos-config/hosts/<新名字>/
    
  4. 建主机目录:复制一份现有的 hosts/nixos-new/configuration.nix 当模板, 改三处:
    • networking.hostName
    • imports 里硬件文件名(hardware-configuration.nix vs hardware.nix)
    • 删掉新机器没有的功能(比如不是 AMD 核显就删 amdgpu 相关注释参考, 不休眠就删 boot.resumeDevice 和 sleep 脚本;反过来笔记本要加)
  5. 在 flake.nix 注册,照抄现有条目:
    新名字 = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [ ./hosts/新名字/configuration.nix ];
    };
    
  6. 首次构建并切换:
    sudo nixos-rebuild switch --flake ~/nixos-config#新名字
    
  7. 重启后:在 SDDM 中选择 Labwc(或所需备用会话)登录。

场景 B:把现有机器纳入这套配置管理

和场景 A 相同,只是第 3 步直接:

mkdir -p ~/nixos-config/hosts/旧机器名
cp /etc/nixos/hardware-configuration.nix ~/nixos-config/hosts/旧机器名/

然后按 4-6 步走。旧机器的 system.stateVersion 保持它当初安装时的 版本不要改(本仓库三台都是 26.05,因为都是 26.05 时代装的)。

休眠(Hibernate)跨机器的注意点

休眠是这套配置里最"机器绑定"的功能。内存大小本身不是问题——zram 按 百分比(50%)分配,钩子里的 image_size 恢复值是运行时从 /proc/meminfo 算的,没有任何写死的内存数值。真正的绑定点:

检查项 要求 不满足时会发生什么
swap 分区大小 ≳ 物理内存(swap ≥ RAM 是可靠规则) 重负载时镜像写不下,写盘阶段失败、解冻弹回
boot.resumeDevice UUID 必须是这台机器的 swap 分区 UUID 休眠能正常写入镜像,但开机恢复不了:直接全新启动、会话丢失(数据不坏,但等于白休眠)
zram 刷盘钩子 有 zram 就必须带 10-hibernate-zram.sh zram 里的页在内存里,快照算不下会 ENOMEM 弹回(nixos-new 实测踩过)
Secure Boot lockdown 关闭(或内核未进 lockdown) lockdown 开启时内核直接禁止休眠,与本配置无关

HX90 台式机策略

HX90 是需要长期通过 SSH 运行任务的台式机,因此配置为:

  • 空闲时不自动 suspend 或 hibernate:services.logind.settings.Login.IdleAction = "ignore"。
  • 手动 suspend 和 hibernate 仍然可用;例如 systemctl hibernate。
  • 禁用 hybrid sleep 与 suspend-then-hibernate,避免后台策略自行改变电源状态。
  • hibernate 写入磁盘后使用 HibernateMode = "shutdown"。这台机器的固件在 ACPI S4 阶段会因为 USB 控制器返回 EBUSY 导致恢复失败,所以采用快照后正常关机。
  • 休眠目标是独立 NVMe swap 分区,不是 EXT4/Btrfs 文件系统里的 swapfile。当前 HX90 的 swap UUID 是 cfceef33-5044-4a72-8c01-c8d1f4444f00,必须同时出现在 hardware-configuration.nix 的 swapDevices 和 configuration.nix 的 boot.resumeDevice。

这套台式机策略不应原样复制到笔记本:笔记本通常需要保留合盖动作,并可能需要 suspend-then-hibernate。复制时应按笔记本的电源管理需求单独设置 logind,并使用 笔记本自己的 swap UUID。

新机器要启用休眠的检查清单:

  1. 装机时留出 ≥ 内存的 swap 分区(HX90 使用约 68.4 GiB swap / 约 62 GiB RAM)。
  2. nixos-generate-config 生成 hardware 文件后,从里面的 swapDevices 拿到 swap 分区 UUID,填进该主机 configuration.nix 的 boot.resumeDevice。
  3. 把 HX90 里 environment.etc."systemd/system-sleep/10-hibernate-zram.sh" 那一整块复制过去——zram 在 modules/core.nix 是共享启用的,所以只要用 zram 就需要这个钩子(钩子和 resumeDevice 同在 host 文件里,结构上保证同进退)。
  4. 验证顺序:swapon --show 确认两个 swap(zram0 优先级 100 + 磁盘分区 -1) → nixos-rebuild build --flake .#主机名 → 真点一次休眠按钮走完整断电循环 → 唤醒后确认会话还在、zram 优先级恢复 100。

电源面板只在内核支持 disk 休眠且存在非 zram 的磁盘 swap 分区时显示 Hibernate 按钮,没配 swap 的机器会自动隐藏。

注意事项 / 坑

  • hardware 文件绝不跨机器复制。里面的磁盘 UUID、initrd 内核模块 (kvm-intel vs kvm-amd)、CPU 微码(intel vs amd)都是机器专属。
  • system.stateVersion 不要动。它只表示"当初安装时的 NixOS 版本", 升级它不会升级系统,反而可能触发一次性迁移逻辑。
  • nixpkgs 钉在 nixos-26.05。这是刻意的迁移基线,新机器稳定运行之前 不要顺手 nix flake update。
  • 免密 sudo:tetsuya 在所有机器上 NOPASSWD: ALL。多用户环境不适用, 需要时改 modules/core.nix。
  • HX90 的空闲挂起被禁用(logind IdleAction=ignore),因为它是需要保持 SSH 在线的台式机;手动挂起/休眠仍可用,电源键和(若存在的)合盖动作仍按各自的 Handle* 设置处理。

各主机 rebuild 速查

sudo nixos-rebuild switch --flake ~/nixos-config#hx90
sudo nixos-rebuild switch --flake ~/nixos-config#aarch64