缘起#
在上一篇中,我们介绍了系统状态与数据备份。开始部署服务之后,这些内容就会连在一起:软件从哪里来,程序怎样启动,数据写在哪里,以及哪些电脑能够访问它。
之前我在Docker使用方法中介绍过用Compose整理容器。NixOS还可以直接用系统模块管理服务,所以这里整理一下两种方式的用途,以及启动关系、数据目录和网络设置。
示例使用虚构主机laptop、保留的示例域名demo.invalid和演示网页,不包含现有服务配置。下面先在本机回环地址测试,不需要真实域名或公开端口。
服务部署方式#
常见方式可以分为三类:
| 方式 | 配置位置 | 适合的情况 |
|---|---|---|
| NixOS服务模块 | services.*等系统选项 | 已有合适模块,希望统一管理账户、配置和启动方式 |
| 自定义systemd服务 | systemd.services.* | 自己的程序或脚本,需要明确运行身份和启动条件 |
| Docker或Podman容器 | Compose或相应NixOS容器选项 | 应用已有镜像,或需要保留已有容器部署方式 |
安装一个软件包,不一定会启用它的服务。模块往往还会生成配置、账户和systemd单元;这些设置也不一定与上游软件的默认值完全一致。使用之前,应检查当前锁定版本提供的选项。
容器同样需要有人管理启动、更新、机密、数据和网络。可以选择NixOS的OCI容器模块,也可以继续维护Compose文件,但应明确哪个工具负责启动哪组容器,避免两套配置争用同一个端口或数据目录。
目前使用的服务组织方式#
现在这些电脑上的容器服务,仍由Compose定义和启动。NixOS负责容器引擎、启动时准备运行配置的任务,以及一些主机服务。服务的通用Compose定义与主机差异分开保存,应用源码也可能是独立Git子模块;迁移时调整目标主机的安排,不必把整套Compose配置改写成Nix表达式。
部署时先检查加密输入和普通参数,生成权限受限的运行时文件,取得对应的Compose组合,再重建或重新创建受影响的服务。NixOS重建和Compose部署不是同一个操作:只修改容器镜像或主机参数时,不一定需要重建整个系统,但仍要重新生成所需运行配置并验证实际服务。
访问入口主要由Traefik与相应隧道或直接路由提供。需要代理的容器加入共享代理网络,能通过这个网络转发的应用不另外发布宿主机端口。路由与主机差异分开记录,公网入口和直接入口分别验证;端口没有发布,也不表示代理提供的入口没有暴露。
实际迁移时,还要一并处理持久数据、解密权限、镜像可用性和原位置的停止状态。服务能够启动只是其中一步,健康与访问路径都要在目标位置检查。
下面用Nginx和一个小型容器说明服务模块、监听地址与代理关系。它们是教学例子,不是当前主机的边缘代理配置;DynamicUser示例也只是说明systemd如何管理目录,并不表示现有服务全部采用动态账户。
使用NixOS服务模块#
配置Nginx演示网页#
在已有配置中创建modules/service-demo.nix,并将它导入主机的模块列表:
| |
这份配置启用Nginx,并让演示虚拟主机监听127.0.0.1:8088。writeTextDir生成store中的静态网页,适合这里没有机密、无需运行时修改的内容。真实上传文件和数据库应使用另外的数据目录。
这是假设端口空闲、可以调整Nginx的演示环境。已有Nginx配置时,应检查现有虚拟主机和监听设置,保留它们并避免名称冲突。一个演示主机监听回环地址,不会自动把其他虚拟主机也变成仅本机可访问。
相关选项可以参考NixOS Nginx模块。
构建与检查#
| |
这里的laptop需要替换为自己的输出名称。构建后,按第五篇的流程检查并应用配置,再查看服务和网页:
| |
正常情况下,可以看到回环地址上的监听,以及包含NixOS service demo的HTML。Host请求头选择示例虚拟主机,不需要将demo.invalid配置到DNS里。
服务显示active,说明systemd认为它处于相应运行状态;端口监听和网页内容则验证另外两件事。真实服务还需要测试登录、数据读写等实际功能,不能仅凭启动状态判断可用。
systemd启动关系#
一个服务往往依赖挂载、数据库或运行时机密。systemd把“是否拉起另一个单元”和“启动顺序”分别处理:
| 设置 | 作用 |
|---|---|
wantedBy | 将服务加入相应目标的启动安排 |
wants | 拉起所列单元,其失败通常不会直接阻止本服务 |
requires | 建立更强的依赖关系,失败处理还与启动顺序等设置有关 |
after或before | 安排同时启动的单元之间的顺序,本身不会拉起另一个单元 |
比如,数据库客户端可能既需要数据库服务被启动,也需要它先启动。但数据库进程启动,不一定已经能接受连接。程序仍需要重试、超时或相应的就绪检查。
network-online.target表示系统所配置的网络等待机制完成,并不保证某个远程网站或数据库一直可达。不要给所有服务都机械地添加它;本机静态网页通常没有这种需求。
相关概念可以参考systemd单元说明。容器的Compose也有类似区别:普通depends_on主要安排启动关系,使用service_healthy时才会等待指定的健康检查;健康检查通过之后,依赖服务仍可能再次失败。可以参考Compose依赖说明。
服务身份与数据目录#
自己的脚本可以通过systemd声明运行身份和目录。例如,下面是一个独立的演示模块:
| |
StateDirectory让systemd准备持久状态目录,并通过STATE_DIRECTORY提供给程序。DynamicUser使用临时分配的运行身份,和systemd管理的目录配合使用;不要拿每次可能变化的UID去手工安排其他目录的所有权。
可以这样运行和检查:
| |
它是一次性任务,成功退出后显示inactive是正常情况。这里写入的只是演示文本,所以可以读取;真实服务的状态文件可能含有私人内容,不能照搬输出到日志或聊天中。
在使用DynamicUser时,持久目录可能通过/var/lib/private等方式保护,备份时应确认实际路径和权限。RuntimeDirectory则用于临时运行文件,生命周期与服务相关,不能当作持久存储。相关说明见systemd目录与运行身份文档。
系统回滚不会自动恢复这些状态文件。容器的数据卷也一样,软件版本和数据恢复需要分别处理。机密的运行时提供方法,可以参考第九篇。
使用容器部署服务#
如果选择容器方式,可以在一个新的演示目录里创建compose.yaml:
| |
这里使用与前面相同的宿主机端口,因此应先移除或调整原生Nginx演示的8088监听,不能把两种部署直接同时启动。需要已有Docker与Compose环境;这份文件不会替我们配置容器引擎。
镜像标签用于说明配置格式,不代表长期维护时应一直停留在这个版本。真实部署应选择仍受支持的版本,记录实际镜像摘要,并安排更新。
在演示目录执行:
| |
网页应包含Container service demo。site是宿主机目录,只读挂载到容器里;如果应用需要写入数据库或上传文件,应另外明确写入位置和备份方法。
这里指定127.0.0.1,只在宿主机回环地址发布端口。省略地址的端口映射通常发布到所有宿主机地址,不能把它当作默认的私有访问方式。Docker版本和网络模式也会影响可达性;例如官方文档记录了旧版本回环发布的同网段访问问题。可以参考Docker端口发布说明。
结束演示时,可以在这个目录停掉这组容器:
| |
宿主机的site目录仍然保留。真实服务不要随意添加-v删除数据卷,也不要把停止容器当作已经完成数据备份。
网络访问与反向代理#
网络访问需要分别考虑监听地址、主机防火墙、路由和应用权限。开放防火墙端口不会让一个仅监听127.0.0.1的程序直接接受局域网连接;反过来,监听所有地址也不表示所有网络都能通过。
Docker会管理端口转发和防火墙规则,所以容器发布端口的流量,不一定经过与普通主机服务相同的规则。不能仅看NixOS的allowedTCPPorts就断言某个容器端口没有暴露。可以参考Docker防火墙说明,并从实际访问位置测试。
反向代理可以统一入口,将请求转发给后端。例如,使用宿主机Nginx代理上面的容器时,可以添加:
| |
这个片段需要已经启用Nginx,并应替换前面同名演示虚拟主机的定义,不要与它重复合并。应用后检查:
| |
此时入口是8089,后端仍是8088。如果Nginx本身也在容器里,127.0.0.1通常指向那个容器自己的网络环境,不能直接当作宿主机或另一个容器;这时应按网络安排使用相应服务名或宿主机地址。
真实公开入口还需要域名、TLS、认证及相应的访问策略。反向代理本身不会自动给应用加上登录保护。本例只说明转发关系,没有配置公开站点。
问题解决#
我通常建议按以下顺序检查:
- 配置是否导入了正确主机,构建和应用是否完成;
- 服务或容器是否启动,日志里的首个错误是什么;
- 程序监听了哪个地址和端口,是否有冲突;
- 从后端、本机入口、局域网或外部访问位置分别测试;
- 最后检查DNS、TLS、认证和实际业务功能。
例如,本机后端正常、代理返回错误,可以先检查代理目标和它所处的网络环境;代理正常、另一台电脑不能访问,再检查入口监听、防火墙与路由。修改时尽量一次只调整一个环节,避免为了让页面打开而同时关闭多处访问限制。
推荐的使用方法#
我建议先检查是否有合适的NixOS服务模块。自己写的程序可以用systemd明确运行身份和数据目录;已有成熟容器部署的应用,也可以继续用Compose,但应统一配置位置并记录启动方式。
让AI协助时,可以要求它说明服务账户、持久数据、机密来源、监听地址和启动条件。配置修改后分别验证进程、访问范围和实际功能,并按上一篇的办法准备数据恢复。
下一篇将介绍更新与多台电脑的部署,包括输入更新、构建资源安排和远程验证。
