多机器配置的组织结构
管理多台 NixOS 机器时,最佳实践是用一个 Git 仓库存放所有配置,每台机器是 nixosConfigurations 中的一个条目:
# flake.nix — 多机器配置
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
home-manager = {
url = "github:nix-community/home-manager/release-24.05";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, home-manager, sops-nix, ... }: {
nixosConfigurations = {
# Web 服务器
webserver = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./modules/common.nix
./modules/server.nix
./hosts/webserver
sops-nix.nixosModules.sops
];
};
# 开发机
dev-machine = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./modules/common.nix
./modules/desktop.nix
./hosts/dev-machine
home-manager.nixosModules.home-manager
{ home-manager.users.alice = import ./home/alice.nix; }
];
};
};
};
}
deploy-rs — 远程部署 NixOS
deploy-rs 是一个 Rust 编写的 NixOS 远程部署工具,可以将本地构建的系统配置部署到远程机器:
# flake.nix — 添加 deploy-rs
{
inputs.deploy-rs.url = "github:serokell/deploy-rs";
outputs = { self, nixpkgs, deploy-rs, ... }: {
# ... nixosConfigurations ...
# deploy-rs 部署节点配置
deploy.nodes = {
webserver = {
hostname = "192.168.1.100"; # 或域名
profiles.system = {
sshUser = "root";
path = deploy-rs.lib.x86_64-linux.activate.nixos
self.nixosConfigurations.webserver;
};
};
};
# 让 nix flake check 也验证 deploy 配置
checks = builtins.mapAttrs
(system: deployLib: deployLib.deployChecks self.deploy)
deploy-rs.lib;
};
}
# 部署到所有节点
nix run github:serokell/deploy-rs -- .
# 部署到指定节点
nix run github:serokell/deploy-rs -- .#webserver
# 部署前先 dry-run(不实际切换,只构建)
nix run github:serokell/deploy-rs -- --dry-activate .#webserver
nixos-anywhere — 远程全新安装
nixos-anywhere 可以通过 SSH 连接到一台目标机器,自动分区、格式化并安装 NixOS——无需手动操作目标机器:
# 前提:目标机器已在任意 Linux 系统下运行(live CD 或现有系统)
# 需要 root SSH 访问
# 安装到目标机器
nix run github:nix-community/nixos-anywhere -- \
--flake .#webserver \
root@192.168.1.100
# 使用自定义磁盘配置(disko)
nix run github:nix-community/nixos-anywhere -- \
--flake .#webserver \
--disk-encryption-keys /tmp/luks.key \
root@target-machine
colmena — 多机器管理
colmena 是专为大规模 NixOS 集群设计的部署工具,支持标签过滤、并行部署:
# colmena.nix(或 flake.nix 中的 colmena 输出)
{
meta = {
nixpkgs = import <nixpkgs> {};
};
# 所有机器共享的配置
defaults = { pkgs, ... }: {
environment.systemPackages = [ pkgs.vim pkgs.git ];
};
webserver-01 = { name, nodes, ... }: {
deployment.targetHost = "10.0.0.1";
deployment.tags = [ "web" "production" ];
services.nginx.enable = true;
};
webserver-02 = { ... }: {
deployment.targetHost = "10.0.0.2";
deployment.tags = [ "web" "production" ];
services.nginx.enable = true;
};
database = { ... }: {
deployment.targetHost = "10.0.0.3";
deployment.tags = [ "db" "production" ];
services.postgresql.enable = true;
};
}
# 部署所有机器
colmena apply
# 只部署 web 标签的机器
colmena apply --on '@web'
# 并行部署,最多 3 台同时
colmena apply --parallel 3
# 构建但不部署(检查配置)
colmena build
sops-nix — 加密管理 Secrets
数据库密码、API Key 等敏感信息不能明文写入 Nix 配置(会进入 /nix/store,可被任何用户读取)。sops-nix 使用 age 或 GPG 加密管理这些 secrets:
# 安装 sops 和 age
nix profile install nixpkgs#sops nixpkgs#age
# 生成 age 密钥对
age-keygen -o ~/.config/sops/age/keys.txt
# 输出:Public key: age1xxxxxx...
# 获取主机 SSH 公钥(NixOS 会用此密钥解密)
ssh-keyscan my-server | ssh-to-age
# 输出:age1xxxxxx...
# .sops.yaml — 配置哪些密钥可以解密哪些文件
creation_rules:
- path_regex: secrets/.*\.yaml$
age: |
age1xxxxxx... # 你的管理员密钥
age1yyyyyy... # 服务器的 age 密钥(从 SSH 公钥转换)
# 创建加密 secrets 文件
sops secrets/secrets.yaml
# 打开编辑器,输入内容(YAML 格式):
# database_password: my-secret-password
# api_key: sk-xxxx...
# 保存后自动加密
# 查看/编辑 secrets
sops secrets/secrets.yaml
# NixOS configuration — 使用 sops-nix
{ config, ... }:
{
imports = [ <sops-nix/modules/sops> ];
sops = {
# age 密钥文件(在机器上)
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
age.keyFile = "/var/lib/sops-nix/key.txt";
# 声明要使用的 secrets
secrets."database_password" = {
sopsFile = ./secrets/secrets.yaml;
owner = "myapp"; # 文件所有者
mode = "0400"; # 只有所有者可读
};
};
# 在服务配置中使用(路径会在运行时被解密内容填充)
systemd.services.myapp.environment.DATABASE_PASSWORD_FILE =
config.sops.secrets."database_password".path;
# 值为 /run/secrets/database_password(启动时由 sops 解密填充)
}
系统回滚
# 查看系统 generations
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
# 从命令行回滚(立即切换)
sudo nixos-rebuild switch --rollback
# 从引导菜单回滚(无需 SSH,适合系统无法启动的情况)
# 重启时在 GRUB/systemd-boot 菜单选择旧的 generation
# 手动切换到特定 generation
sudo nix-env --switch-generation 5 --profile /nix/var/nix/profiles/system
sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
学习路径规划
Nix 的学习曲线较陡,以下是推荐的渐进式路径:
nix-shell / nix develop(1-2周)
从开发环境开始——为现有项目写一个 shell.nix 或 flake.nix devShell,体验隔离依赖的价值。配合 direnv,实现进目录自动激活。
Flakes(1-2周)
将开发环境迁移到 Flakes,理解 inputs/outputs/flake.lock。开始为项目构建产物和 Docker 镜像。
Home Manager(1-2周)
在 macOS 或 Linux 上用 Home Manager 管理 dotfiles。不需要 NixOS 就能体验声明式用户环境的好处。
NixOS(长期)
在虚拟机中安装 NixOS,从零配置一台开发机。理解模块系统,逐步将配置模块化,加入 secrets 管理。
多机器管理(进阶)
用单个 flake.nix 管理多台 NixOS 机器,引入 deploy-rs 或 colmena 自动化部署,用 sops-nix 管理 secrets。
社区资源
Nix 的本质是一个一致性保证系统:从开发环境(nix shell)到应用包(derivation)到整个操作系统(NixOS),再到 CI/CD 构建(nix build)和 Docker 镜像(dockerTools),Nix 在每一个层面都提供"相同输入永远产生相同输出"的保证。这不只是工具的选择,更是思维方式的转变——从命令式的"执行这些步骤"到声明式的"我想要这个状态"。学习 Nix 有一定成本,但一旦掌握,你的开发和运维效率将得到质的提升。