核心概念速览#
NixOS 的配置由三个层次组成,理解它们的关系是一切的基础:
flake.nix ← nix 命令直接读取,声明依赖,组装系统
└── configuration.nix ← 系统级配置(需要 sudo)
└── home.nix ← 用户级配置(home-manager 管理)Nix 语言基础#
Nix 文件本质是一个返回值的表达式,最常见的返回值是 attribute set(键值对集合)。
Attribute Set(键值对集合)
{
name = "Alice";
age = 25;
nested = {
key = "value";
};
}函数
# 基本形式:参数: 返回值
x: x + 1
# 解构 attribute set 作为参数
{ name, age }: "Hello, ${name}, you are ${age}"
# 带默认值
{ name, age ? 0 }: "Hello ${name}"
# 捕获整个参数集合(@语法)
{ name, ... }@args: args常用语法糖
# with 语句:展开 attribute set,避免重复前缀
with pkgs; [ git neovim curl ]
# 等价于
[ pkgs.git pkgs.neovim pkgs.curl ]
# inherit:继承上层作用域的变量
{ inherit inputs pkgs; }
# 等价于
{ inputs = inputs; pkgs = pkgs; }
# let...in:局部变量
let
myVar = "hello";
in
"${myVar} world"
# 字符串插值
"Hello ${name}, you are on ${config.networking.hostName}"列表
[ "item1" "item2" pkgs.git ]flake.nix 详解#
flake.nix 不是函数,是一个有固定 schema 的 attribute set。Nix 工具认识这个结构,类似 npm 和 package.json 的关系。
{
description = "My NixOS config"; # 可选,描述信息
inputs = {
# 声明外部依赖;默认作为 flake 处理,也可用 flake = false 引入普通源码
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs"; # 让 HM 用同一份 nixpkgs,避免重复下载
};
};
# outputs 的值是函数,参数是所有 inputs 求值后的结果
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
# nixosConfigurations 是约定的 key,nixos-rebuild 会来这里找
nixosConfigurations."workstation" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
# specialArgs 把额外变量传递给所有子模块
specialArgs = { inherit inputs; };
modules = [
./configuration.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.alice = import ./home.nix;
home-manager.extraSpecialArgs = { inherit inputs; };
}
];
};
};
}inputs.X.follows 的作用
home-manager.inputs.nixpkgs.follows = "nixpkgs";让 Home Manager 的 nixpkgs input 指向系统的同一锁定节点,减少重复输入。不同输入可能产生不同依赖集合,但并非必然下载两份或不兼容;Home Manager 分支也需要与系统版本匹配。
flake.lock
自动生成,记录每个 input 的精确 git commit hash。不要手动编辑。
nix flake update→ 更新所有 inputsnix flake update nixpkgs→ 只更新 nixpkgs
configuration.nix 详解#
系统级配置,配置整台机器。修改后需要 sudo nixos-rebuild switch。
# 这是一个函数,参数由 NixOS 模块系统传入
{ config, lib, pkgs, inputs, ... }:
{
imports = [
./hardware-configuration.nix # 硬件配置,自动生成的
./modules/audio.nix # 可以拆分成子模块
];
# ── Boot ──────────────────────────────
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# ── Network ───────────────────────────
networking.hostName = "workstation";
networking.networkmanager.enable = true;
# ── System packages ───────────────────
environment.systemPackages = with pkgs; [
wget curl git neovim
];
# ── Users ─────────────────────────────
# 本例把用户包统一交给 home.nix,用户身份和组由系统管理
users.users.alice = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" "video" ];
};
# ── 不要改这个值 ──────────────────────
system.stateVersion = "25.11";
}传入参数说明
| 参数 | 含义 |
|---|---|
pkgs |
nixpkgs 里所有包的集合 |
config |
当前系统配置(可以引用其他选项) |
lib |
nixpkgs 工具函数库 |
inputs |
flake inputs(需要 specialArgs 传入) |
home.nix 详解#
用户级配置,由 home-manager 管理。配置的是某个用户的家目录、dotfiles、用户软件。
{ config, pkgs, inputs, ... }:
{
imports = [
./modules/shell.nix
./modules/dev.nix
inputs.some-flake.homeModules.default # 接口示意,须在 inputs 中定义并按该项目实际输出替换
];
# ── 必填 ──────────────────────────────
home.username = "alice";
home.homeDirectory = "/home/alice";
home.stateVersion = "25.11"; # 不要随意改
# ── 用户软件 ──────────────────────────
home.packages = with pkgs; [
htop btop obsidian
ghostty kitty
];
# ── 程序配置(带 dotfile 管理)─────────
programs.git = {
enable = true;
settings = {
user.name = "Example User";
user.email = "user@example.com";
init.defaultBranch = "main";
};
};
programs.zsh = {
enable = true;
autosuggestion.enable = true;
syntaxHighlighting.enable = true;
};
programs.home-manager.enable = true;
}系统级 vs 用户级 边界#
判断依据:这个东西是"机器"需要的,还是"用户"需要的?
放 configuration.nix |
放 home.nix |
|---|---|
| 内核模块、驱动 | 终端模拟器、编辑器 |
| 系统服务(pipewire, bluetooth) | shell 配置(zsh, bash) |
| 防火墙、网络 | dotfiles |
| 字体(系统级) | 用户软件包 |
users.users.X(账户及组) |
programs.git, programs.zsh 等 |
| 输入法框架(fcitx5) | 输入法个性配置 |
统一包管理入口
# 有效的 NixOS 用户包选项,但在此组织方式中避免双入口
users.users.alice.packages = with pkgs; [ obsidian ];
# 使用 Home Manager 时可统一放在 home.nix
home.packages = with pkgs; [ obsidian ];模块系统#
NixOS 和 home-manager 都使用同一套模块系统,理解它可以看懂任何配置。
# 一个模块的完整结构
{ config, lib, pkgs, ... }:
{
# imports:引入其他模块
imports = [ ./other-module.nix ];
# options:声明这个模块提供的选项(写库/框架时用)
options.myModule.enable = lib.mkOption {
type = lib.types.bool;
default = false;
};
# config:实际配置(条件激活时常用)
config = lib.mkIf config.myModule.enable {
environment.systemPackages = [ pkgs.hello ];
};
}大多数时候你只需要写顶层的配置,不需要 options 和 config 包装。
推荐目录结构#
/etc/nixos/
├── flake.nix # 入口,声明依赖
├── flake.lock # 自动生成,不要手动改
├── hardware-configuration.nix # 自动生成
├── configuration.nix # 系统配置入口(精简,只 imports)
├── modules/ # 系统级子模块
│ ├── locale.nix # i18n / 时区 / 输入法
│ ├── graphics.nix # GPU / Hyprland / display
│ ├── audio.nix # pipewire / bluetooth
│ ├── network.nix # network / firewall
│ └── nix-settings.nix # substituters / nix-ld / flakes
└── home/
├── home.nix # 用户配置入口
├── packages.nix # home.packages 列表
└── programs/
├── shell.nix # zsh/bash/starship/zoxide
├── dev.nix # git/zellij/direnv/neovim
└── desktop.nix # foot/ghostty/主题常用命令速查#
更新锁文件和激活是两步;先审阅锁文件差异并构建,通过后再按需要执行 test、boot 或 switch。清理命令会移除回滚点。
# 重建并切换到新配置
sudo nixos-rebuild switch --flake /etc/nixos#workstation
# 临时激活新配置(会切换运行系统,重启回到启动默认项)
sudo nixos-rebuild test --flake /etc/nixos#workstation
# 回滚到上一代
sudo nixos-rebuild switch --rollback
# 列出所有系统代
nix-env --list-generations --profile /nix/var/nix/profiles/system
# 更新所有 flake inputs
sudo nix flake update --flake /etc/nixos
# 只更新某一个 input
sudo nix flake update nixpkgs --flake /etc/nixos
# 清理旧代(释放磁盘)
sudo nix-collect-garbage -d
# 查找包
nix search nixpkgs firefox
# 临时试用一个包(不安装)
nix shell nixpkgs#ripgrep
# 进入 devshell
nix developPer-project Dev Shell 模板#
用 Nix 提供项目工具和系统依赖;是否叠加 Python venv/uv 取决于项目,mkShell 本身不提供容器式进程隔离。
# 放在项目根目录的 flake.nix
{
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
outputs = { nixpkgs, ... }:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in {
devShells.x86_64-linux.default = pkgs.mkShell {
packages = with pkgs; [
# Python 科学计算(让 nix 管,不要 pip 装)
(python3.withPackages (ps: [
ps.numpy ps.matplotlib ps.scipy
]))
uv # 只用来管理纯 Python 包,不碰系统包
];
shellHook = ''
echo "Dev shell ready"
'';
};
};
}# 进入项目 dev shell
cd my-project
nix develop
# 也可以用 direnv 自动激活(需要 programs.direnv.enable = true)
echo "use flake" > .envrc
direnv allow调试技巧#
依赖追踪需要两个 store 路径,第二个路径必须对应当前系统中实际使用的包版本;registry 的 nixpkgs 未必等于系统锁定输入。nix fmt 还要求 Flake 定义相应 formatter。
# 查看某个选项的文档
nixos-option services.pipewire.enable
# 查看某个包在哪里
nix eval nixpkgs#git.outPath
# 为什么某个包被引入(依赖追踪)
nix why-depends /run/current-system "$(nix eval --raw nixpkgs#gcc.outPath)"
# 检查 flake 结构
nix flake show /etc/nixos
# 格式化 nix 文件
nix fmt参考资源#
参考与延伸
- NixOS 手册 ↗
- Nix 语言手册 ↗
- Home Manager 手册 ↗
- Nix:flake update ↗
- NixOS 与 Flakes 中文指南(原笔记引用) ↗
- Home Manager Git 模块 ↗
根据技术笔记重新整理,示例使用通用名称。