引言
NixOS 上「部署一个服务」不是写 shell 脚本和 systemd unit 文件,而是在 configuration.nix 里声明它——NixOS 会帮你生成 systemd unit、装好依赖、配好开机自启,全部可回滚。本文从声明一个 systemd 服务讲起,到 NixOS 原生容器和 nginx/postgres 等常用服务的标准部署。
前置:/nixos-configuration/(configuration.nix 基础)、/nixos-network-firewall/(网络与防火墙)。
目录
- 1. 服务的声明式思维
- 2. systemd 服务声明:写一个最小服务
- 3. 依赖、时序与开机自启
- 4. 环境变量、用户与秘钥
- 5. 常用服务:nginx 与反向代理
- 6. 常用服务:PostgreSQL 与 Redis
- 7. NixOS 容器:轻量隔离
- 8. 定时任务与 systemd.timer
- 9. 服务监控与排障
- 10. 速查表与一句话记忆
- 延伸阅读
1. 服务的声明式思维
1.1 传统 vs NixOS
| 传统方式 | NixOS 方式 |
|---|---|
| 写 systemd unit + 脚本 | systemd.services.<name> 声明 |
| 手工装依赖 | Nix 自动带上 |
| 手工 enable/start | rebuild switch 即生效 |
| 环境不一致 | 配置即部署 |
1.2 一个例子
systemd.services.myapp = {
description = "My application";
wantedBy = [ "multi-user.target" ]; # 开机自启
serviceConfig = {
ExecStart = "${pkgs.myapp}/bin/myapp --config /etc/myapp.conf";
Restart = "on-failure";
User = "myapp";
};
};
记忆:NixOS 服务 = 在 systemd.services.
里声明 unit,rebuild switch 即部署生效、可回滚,依赖由 Nix 自动解析 。
2. systemd 服务声明:写一个最小服务
2.1 最小可用服务
{ pkgs, ... }:
{
systemd.services.hello = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.hello}/bin/hello";
Restart = "always";
};
};
}
2.2 常用 serviceConfig 字段
| 字段 | 含义 |
|---|---|
| ExecStart | 启动命令 |
| Restart | on-failure / always / no |
| User/Group | 运行身份 |
| WorkingDirectory | 工作目录 |
| Environment | 环境变量 |
| LimitNOFILE | 文件描述符上限 |
| TimeoutStartSec | 启动超时 |
记忆:最小服务 = systemd.services.
+ wantedBy 开机自启 + ExecStart/Restart;其余按需加字段 。
3. 依赖、时序与开机自启
3.1 依赖声明
systemd.services.backend = {
after = [ "network-online.target" "database.service" ]; # 之后启动
requires = [ "database.service" ]; # 强依赖
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.backend}/bin/backend";
};
3.2 常见依赖目标
| target | 时机 |
|---|---|
| multi-user.target | 多用户登录后 |
| network-online.target | 网络就绪后 |
| local-fs.target | 文件系统挂载后 |
记忆:after 控制顺序、requires 控制强依赖、wantedBy 控制开机自启;网络就绪用 network-online.target。
4. 环境变量、用户与秘钥
4.1 环境变量
systemd.services.myapp = {
serviceConfig.Environment = [
"PORT=8080"
"LOG_LEVEL=info"
];
# 或引用文件
environmentFiles = [ /etc/myapp.env ];
};
4.2 专用系统用户
users.users.myapp = {
isSystemUser = true;
group = "myapp";
};
users.groups.myapp = { };
systemd.services.myapp.serviceConfig.User = "myapp";
4.3 秘钥引用(配合 sops/agenix)
systemd.services.myapp = {
environmentFiles = [ config.age.secrets.myapp_env.path ]; # 挂在 /run/secrets/
};
记忆:环境变量用 serviceConfig.Environment 或 environmentFiles;服务建专用系统用户;秘钥用 age/sops 解密到 /run/secrets 引用。
5. 常用服务:nginx 与反向代理
5.1 静态站点
services.nginx = {
enable = true;
virtualHosts."example.com" = {
root = "/var/www/example";
enableACME = true; # Let's Encrypt 自动证书
forceSSL = true;
};
};
5.2 反向代理到后端
services.nginx.virtualHosts."api.example.com" = {
locations."/" = {
proxyPass = "http://127.0.0.1:8080";
proxyWebsockets = true;
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
记忆:nginx 在 services.nginx.virtualHosts 声明;enableACME + forceSSL 自动 HTTPS;反向代理用 proxyPass。
6. 常用服务:PostgreSQL 与 Redis
6.1 PostgreSQL
services.postgresql = {
enable = true;
package = pkgs.postgresql_16;
initialDatabases = [{ name = "myapp"; }];
authentication = ''
local all all trust
host all all 127.0.0.1/32 trust
'';
settings = { max_connections = 100; };
};
6.2 Redis
services.redis.servers = {
default = {
enable = true;
port = 6379;
bind = "127.0.0.1";
};
};
记忆:PostgreSQL 在 services.postgresql 声明初始库与认证;Redis 用 services.redis.servers.default 声明监听地址端口。
7. NixOS 容器:轻量隔离
7.1 什么是 NixOS 容器
NixOS 原生容器(nixos-container)——不用 Docker、不用手动装运行时,声明式定义,开箱即隔离:
containers.web = {
privateNetwork = true;
hostAddress = "10.233.0.1";
localAddress = "10.233.0.2";
config = { pkgs, ... }: {
services.nginx.enable = true;
};
};
7.2 管理与限制
nixos-container list # 列出容器
nixos-container login web # 进入容器
记忆:NixOS 容器 = 声明式轻量隔离(无需 Docker);containers.
.config 写该容器自己的配置,hostAddress/localAddress 配网 。
8. 定时任务与 systemd.timer
8.1 声明定时任务
systemd.timers.backup = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily"; # 每天
Persistent = true; # 补跑错过的
};
};
systemd.services.backup = {
serviceConfig.ExecStart = "${pkgs.rsync}/bin/rsync -a /data /backup/";
};
8.2 替代 cron
NixOS 也提供传统 cron:
services.cron = {
enable = true;
systemCronJobs = [ "0 3 * * * root /usr/bin/backup" ];
};
记忆:定时任务推荐 systemd.timers(OnCalendar 声明周期 + Persistent 补跑);要传统 cron 用 services.cron.systemCronJobs。
9. 服务监控与排障
9.1 查看服务状态
systemctl status myapp # 状态
journalctl -u myapp -f # 实时日志
systemctl list-units --failed # 失败单元
9.2 常见排障
| 现象 | 排查 |
|---|---|
| 启动失败 | journalctl -u 看日志 |
| 依赖超时 | 检查 after/requires |
| 端口占用 | ss -tlnp 查看 |
| 权限拒绝 | 检查 User/Group 与 secret 权限 |
记忆:排障先用 journalctl -u <服务> 看日志;依赖/端口/权限是三大常见失败源。
10. 速查表与一句话记忆
| 场景 | 声明位置 |
|---|---|
| 自定义服务 | systemd.services. |
| 依赖顺序 | after / requires |
| 开机自启 | wantedBy multi-user.target |
| 环境变量 | serviceConfig.Environment |
| 系统用户 | users.users. |
| nginx | services.nginx.virtualHosts |
| PostgreSQL | services.postgresql |
| Redis | services.redis.servers |
| 容器 | containers. |
| 定时任务 | systemd.timers |
一句话记忆:NixOS 服务部署 = 在 configuration.nix 声明——自定义服务用 systemd.services.
延伸阅读
- /nixos-configuration/ — configuration.nix 与模块系统
- /nixos-network-firewall/ — 服务端口与防火墙配合
- /nix-secrets-management/ — 服务秘钥注入(/run/secrets)
- /nixos-storage-filesystems/ — 服务数据卷与存储
- /nixos-operations-maintenance/ — 服务升级与回滚
- [[linux]] — systemd 服务管理实操
- [[devops]] — 服务部署与可观测性
- NixOS systemd 模块文档
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。