切换到 GNU Guix:初学者的视角

Lobsters Hottest 新闻

摘要

一位初学者分享了从 Arch Linux 切换到 GNU Guix 的经验,讨论了声明式系统管理的好处、与 NixOS 的比较以及所面临的挑战。

<p><a href="https://lobste.rs/s/loapzc/switching_gnu_guix_beginner_s">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/13 18:52

# 转投 GNU Guix:初学者视角 来源:https://whhone.com/posts/switching-to-gnu-guix/ 2026\-09\-13\#linux (https://whhone.com/tags/linux/)\#guix (https://whhone.com/tags/guix/) **目录**- 背景:十年 Arch Linux 使用史 (https://whhone.com/posts/switching-to-gnu-guix/#background-a-decade-of-arch-linux) - NixOS 与 GNU Guix 对比 (https://whhone.com/posts/switching-to-gnu-guix/#nixos-vs-gnu-guix)- 虚拟机测试 NixOS (https://whhone.com/posts/switching-to-gnu-guix/#testing-nixos-in-a-vm) - 发现 GNU Guix (https://whhone.com/posts/switching-to-gnu-guix/#discovering-gnu-guix) - 初学者喜爱的特性 (https://whhone.com/posts/switching-to-gnu-guix/#what-i-like-as-a-beginner)- Git 中的统一声明式配置 (https://whhone.com/posts/switching-to-gnu-guix/#unified-declarative-config-in-git) - 灵活的 Guile 配置 (https://whhone.com/posts/switching-to-gnu-guix/#flexible-guile-configuration) - 简化的 Shepherd 定时任务 (https://whhone.com/posts/switching-to-gnu-guix/#streamlined-shepherd-timers) - 通过`guix shell`实现沙盒容器 (https://whhone.com/posts/switching-to-gnu-guix/#sandboxed-containers-with-guix-shell) - 纯净性与最小化引导种子 (https://whhone.com/posts/switching-to-gnu-guix/#purity-and-the-minimal-bootstrap-seed) - 问题及应对方式 (https://whhone.com/posts/switching-to-gnu-guix/#issues-and-how-i-handle-them)- 缓慢的`guix pull`与源码构建 (https://whhone.com/posts/switching-to-gnu-guix/#slow-guix-pull-and-source-builds) - 弥补软件包缺口 (https://whhone.com/posts/switching-to-gnu-guix/#addressing-the-package-gap) - 总结 (https://whhone.com/posts/switching-to-gnu-guix/#conclusion) ## 背景:十年 Arch Linux 使用史 Arch Linux 是我十余年来的首选发行版。其滚动更新模型、精简的基础系统以及宝贵的 ArchWiki 文档,让我觉得它可能是我最终的归宿。我的主力 Linux 设备是一台专用家庭服务器,承载 Home Assistant、本地 DNS、后台任务和开发者沙盒等服务。对于一台 24/7 运行的服务器,长期稳定性和可维护性至关重要。多年来的渐进式调整不可避免地导致配置熵增。系统状态变得分散于`/etc`、`/usr`、systemd 服务单元和包管理器事务记录中。每次修改时,我都必须仔细记录编辑了哪些文件、何时编辑以及为何编辑。近期事件,例如 Arch Linux AUR 安全事件(我在之前的 Caddy 文章 (https://whhone.com/posts/using-caddy-with-extensions-on-archlinux/) 中提及)以及围绕 Omarchy 的发展,促使我重新评估自己的配置方案。我需要一个声明式、可复现且完全可通过代码管理的操作系统。 ## NixOS 与 GNU Guix 对比 声明式操作系统为解决配置漂移提供了极具吸引力的方案。在调研选项时,NixOS 实际上是我的首选。 ### 虚拟机测试 NixOS 我搭建了一台 NixOS 虚拟机,通过在 Arch 上复现核心服务来进行实验,以确保一切正常运行。效果非常好:在配置文件中声明整个系统状态并具备即时回滚能力,这感觉是操作系统该有的模型。然而随着深入探索,NixOS 的文档成为主要障碍。较新的`nix`命令行界面和 Flakes 仍是实验性功能,尚未默认启用或在生态系统中标准化,导致文档和教程出现分歧。存在两个独立的 Wiki 更增加了寻找指导的复杂性。 ### 发现 GNU Guix 在了解 NixOS 的过程中,我看到了 System Crafters 的 David Wilson 的视频:我为何选择 Guix 而非 NixOS (https://www.youtube.com/watch?v=PiAMRXYIri0)。作为 David Wilson 的粉丝,他的论点与我产生了强烈共鸣。不久后,我又观看了 YouTux 的视频:最佳 Linux 发行版之一甚至不在 DistroWatch 前 100 名 (https://www.youtube.com/watch?v=MtYWp8sCsiE&t)。这些视频促使我研究 GNU Guix 并在虚拟机中尝试。 GNU Guix 与 NixOS 共享相同的核心架构基础(函数式包管理、声明式配置和原子回滚),但其设计选择显得更为统一: 1. **语言(GNU Guile Scheme 与 Nix DSL):** Nix 使用其自定义的领域特定语言。Guix 配置完全使用 GNU Guile 编写,这是一种通用的 Scheme(Lisp)语言。作为习惯 Emacs Lisp 的 Emacs 用户,Scheme 给我熟悉且富有表达力的感觉。我不需要学习专门的配置语法,而是可以利用一门支持一等函数、宏和模块的真实编程语言。 2. **初始化系统(GNU Shepherd 与 systemd):** NixOS 基于 systemd,而 Guix System 使用 GNU Shepherd 作为其服务管理器。在 Guix 中,Shepherd 服务也通过 Guile Scheme 定义。从软件包定义到系统守护进程再到 PID 1,所有内容共享统一的语言和数据模型。 3. **文档:** Guix 的文档具有显著的一致性。尽管部分社区教程可能过时,但 GNU Guix 官方参考手册始终统一、全面,避免了 Nix 那种碎片化的 Wiki 困境。 4. **哲学(GNU 自由标准与实用主义):** NixOS 采取实用主义立场,为专有软件和非自由驱动提供开关。GNU Guix 严格遵守 GNU 自由系统分发指南,默认仅提供 Linux-libre 内核和自由软件。这种哲学上的严格性有其取舍。对于我的家庭服务器(通过以太网连接网络),专有 Wi-Fi 固件并非必需,Linux-libre 内核可直接工作。其纯净性和可审计性令人满意,尽管这意味着需要处理更精简的软件包目录。 在 Scheme 的熟悉感、统一架构及其与 Emacs 的紧密关联下,我决定转向 GNU Guix。 ## 初学者喜爱的特性 ### Git 中的统一声明式配置 通过 GNU Guix,整个操作系统配置都以代码形式存在于 Git 中。我在单个文学化 Org 模式文件(`guix.org`)中使用 Org Babel 管理 Guix System(操作系统声明、系统守护进程、内核参数)和 Guix Home(用户软件包、Shell 环境和配置文件)。随时都能直接从代码库中查看已安装的软件包和活跃的服务。 过去,我曾对投入复杂系统配置犹豫不决,因为跨版本维护它们较为脆弱。而在 Guix 中,配置操作系统变得如同调整 Emacs 配置般易于管理和预测。 ### 灵活的 Guile 配置 Guix 配置使用功能完整的编程语言编写,而非静态的 YAML 或 JSON。这在组合服务时提供了极大的灵活性。通过 Guix 的服务扩展机制配合`simple-service`,你可以干净地扩展现有系统服务,无需修改基础声明。在传统发行版中,部署一个服务往往迫使其配置分散到完全不同的子系统:`/etc/systemd/system/`中的 systemd 单元、`/etc/tmpfiles.d/`中的目录初始化以及`/etc/nginx/conf.d/`中的反向代理块。而在 Guix 中,你可以将服务及其周边基础设施并列放置在同一个配置块中: `` ;; Home Assistant 容器 (simple-service 'home-assistant-container oci-service-type (oci-extension (containers (list (oci-container-configuration (provision "home-assistant") (image "ghcr.io/home-assistant/home-assistant:stable") ...详细配置...))))) ;; 注入用于 Home Assistant 的 Nginx 反向代理配置 (simple-service 'home-assistant-nginx-server nginx-service-type (list (nginx-server-configuration (inherit ssl-server-configuration) (server-name (list (string-append "home." domain))) (locations (list (nginx-location-configuration ...详细配置...))))) `` 这种架构清晰性使得理解、修改或移除服务变得自包含且轻松。 ### 简化的 Shepherd 定时任务 在 Guix 中定义定时任务也比传统发行版更为简洁。在 systemd 中设置定期任务需要声明一个`.service`文件和一个单独的`.timer`单元。而在 Guix 的 GNU Shepherd 中,你可以在一个 Guile 表达式中同时声明可执行脚本、依赖及其调度计划: `` (let* ((duckdns-script (program-file "duckdns-update" (with-extensions (list guile-gnutls) ; (web client) 所需 #~(begin (use-modules (ice-9 textual-ports) (web client)) (let ((token (string-trim-both (call-with-input-file "/etc/secrets/duckdns.token" get-string-all))) (query-template (string-append "https://www.duckdns.org/" "update?domains=" "&token=~a&ip="))) (http-get (format #f query-template token))))))) (duckdns-timer (shepherd-timer '(duckdns) "*/5 * * * *" #~(#$duckdns-script) #:requirement '(networking) #:documentation "每 5 分钟更新 DuckDNS 上的个人域名 IP。"))) (simple-service 'duckdns-timer shepherd-root-service-type (list duckdns-timer))) `` ### 通过`guix shell`实现沙盒容器 `guix shell`命令改变了我运行临时软件的方式。它无需用一次性工具污染我的配置,而是创建一个临时环境,会在会话结束时被清理。此外,其容器模式(`guix shell -C`或`--container`)使得轻量级隔离变得轻而易举。通过精确指定要暴露的目录(`--share`)和网络访问(`--network`),我可以在隔离的沙盒中运行不受信任的命令或 AI 编码代理。例如,我在沙盒中运行 Antigravity CLI,仅授予其访问当前工作目录、配置文件和必要二进制文件的权限: `` # 在 Guix 沙盒中运行 Antigravity CLI,仅可访问其配置和项目目录。 agy-guix() { guix shell --container --network --emulate-fhs \ --share="$PWD" \ --share="$HOME/.gemini" \ --share="$HOME/.local/bin" \ --preserve='^(TERM)$' \ coreutils nss-certs bash guix guile emacs git ripgrep fd zip unzip -- $HOME/.local/bin/agy "$@" } `` 知道代理无法访问其授权路径之外的任意文件,使实验更加安全。 ### 纯净性与最小化引导种子 默认情况下,GNU Guix 严格遵循自由软件标准。它提供 Linux-libre 内核,避免专有二进制 blob。除日常使用外,Guix 架构上注重引导完整性(通过 stage0/Mes 引导将引导二进制种子缩减至约 357 字节),这提供了强烈的技术严谨感。知道系统可以从最小、可审计的基础构建,为底层栈提供了真正的可信度。 ## 问题及应对方式 ### 缓慢的`guix pull`与源码构建 Guix 与 Arch Linux 的一个根本区别在于,Guix 本质上是源码构建的发行版,辅以提供预构建二进制文件的替代服务器。如果新拉取的通道提交尚未被替代构建农场(如`ci.guix.gnu.org`或 Bordeaux)构建,你的机器将退回到本地编译软件包。虽然这种架构赋予了强大的功能,如`guix challenge`(验证与其他服务器的构建可重现性)和`guix time-machine`(回溯到任何历史版本),但在家庭服务器上等待漫长的本地构建可能很乏味。 为避免意外的本地编译,我的实用解决方法是将`guix pull`固定到一两天前的特定提交,确保替代包已构建并缓存: `` ;; ~/.config/guix/channels.scm(或:guix pull --commit=) (list (channel (inherit %default-guix-channel) ;; 通过 Codeberg 镜像加速拉取 (url "https://codeberg.org/guix/guix.git") (commit "5b52edf051a020947b1d4859853799f2bbce176e"))) `` ### 弥补软件包缺口 对于从 Arch Linux 转来的初学者,最明显的障碍是软件仓库规模。官方 Guix 通道有严格的自由标准,目录也比 Arch 用户仓库(AUR)小。常用工具如`hugo`和`caddy`在官方通道中不存在。在实践中,我有几种应对这种缺口的实用方法: #### 1. 编写自定义软件包定义 用 Scheme 编写软件包定义很简单。你可以定义一个从源码构建或下载官方上游发布存档的软件包: `` (define hugo (package (name "hugo") (version "0.165.0") (source (origin (method url-fetch) (uri (string-append "https://github.com/gohugoio/hugo/releases/download/v" version "/hugo_" version "_linux-amd64.tar.gz")) (sha256 (base32 "0...")))) (build-system trivial-build-system) ...)) `` 对于 Hugo,我创建了一个本地软件包定义,下载官方预构建二进制文件,使其无缝地在系统和部署脚本中可用。 #### 2. 通过`guix shell`运行临时工具链 对于存在于语言生态系统中的工具,`guix shell`可以与生态系统运行器(`uvx`、`npx`)配合使用,无需全局安装软件包: `` # 这是我现在将博客发布到 Cloudflare 的方式。 guix shell node -- npx -y wrangler `` #### 3. 使用`guix import`生成定义 当软件包缺失时,`guix import` (https://guix.gnu.org/manual/1.5.0/en/html_node/Invoking-guix-import.html) 可以从上游注册表(如 PyPI、Crates.io、CPAN 或 GNU ELPA)自动生成软件包定义。这显著减少了编写软件包配方的 manual effort。 #### 4. 切换到现成的替代方案 有时最简单的路径是采用已在 Guix 中作为一等公民的软件。我没有维护带有第三方插件的自定义 Caddy 设置,而是切换回 Nginx 配合 Certbot。两者都是 Guix System 中受良好支持的原生服务,简化了长期维护。 ## 总结 将我的家庭服务器迁移到 GNU Guix 已过去一个月。通过 Git 以声明式方式管理操作系统状态消除了配置漂移,而 Guile Scheme 提供了一个与 Emacs 相辅相成的统一环境。虽然适应较小的软件包生态系统和管理替代包时序需要偶尔调整,但其稳定性、可重现性和容器隔离使其成为可靠的基础。业余时间,我开始阅读经典的 SICP(《计算机程序的构造和解释》),以加深对 Scheme 和函数式编程的理解。

相似文章

Nix Flakes 及其在 Guix 中的对应物

Lobsters Hottest

详细比较 Nix Flakes 与 Guix 包管理系统中的对应物,涵盖依赖声明、锁定、纯净性、输出、开发环境和系统配置。

GNU Guix 的实用软件自由

Lobsters Hottest

一场介绍四大软件自由、其重要性与局限性,以及 GNU Guix 如何实现软件的验证、修改和共享以保障用户自由的演讲。

从 Proxmox 迁移到 NixOS 和 Incus

Hacker News Top

作者描述了将其家庭实验室从 Proxmox 迁移到使用 Incus 的 NixOS 的过程,强调了声明式配置和可重现性相对于命令式系统的优势。