systemctl restart nginx。敲完。搞定。关掉终端。

这是 99% Linux 用户和 systemd 的日常关系。systemd 是个巨复杂的工具,但你只用了它的三个子命令。

不是你的问题——入门教程就只教这三个。

但这玩意儿真正实用的功能藏在后面。这篇文章翻几个出来,都是你明天上班就能用的。


一、不再 etc/cron.d 写定时任务:systemd timer 才是正解

cron 最大的痛:环境变量和 systemd 不一致。你在 shell 里能跑通的脚本,cron 里就是不行。

systemd timer 直接解决方法:你的脚本在 systemd 单元中运行,环境变量、PATH、依赖关系全在同一个框架里

写一个 timer 两步走:

第一步,创建 service 单元 /etc/systemd/system/backup-db.service

[Unit]
Description=每日数据库备份

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-db.sh

第二步,创建 timer 单元 /etc/systemd/system/backup-db.timer

[Unit]
Description=每天凌晨3点备份

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

启用:

sudo systemctl daemon-reload
sudo systemctl enable --now backup-db.timer

OnCalendar 的语法比 cron 更灵活,举几个例子:

写法含义
daily每天 00:00
*-*-* 03:00:00每天凌晨 3 点
Mon..Fri 09:30:00工作日 9:30
*-*-1,15 00:00:00每月 1 号和 15 号
*:0/15每 15 分钟

Persistent=true 的含义很重要:如果机器在预定时间处于关机状态,启动后立即补跑一次。cron 做不到,anacron 勉强但难用。

cron 已经不需要了。 我在所有 VPS 上已经全部换成 timer,再也没出过「脚本不执行」的玄学问题。


二、不动原配置文件改行为:systemctl edit 和 drop-in

这是 systemd 被低估最多的功能。

想改 nginx 的启动参数?传统做法:vim /etc/systemd/system/nginx.service,但下次 nginx 包升级会覆盖你的改动。

drop-in 解决这个问题。

sudo systemctl edit nginx

这会打开一个空文件。你只写要覆盖的部分:

[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -g 'daemon off;' --custom-flag

保存退出后,systemd 自动生成 /etc/systemd/system/nginx.service.d/override.conf。优先级高于原始单元文件,下包更新不会覆盖。

不需要 copy 整个单元文件来找要改哪一行。 只写要覆盖的配置段+键名。

多个 drop-in 文件按名称排序加载,也是 systemctl cat nginx 可以查看合并后的完整配置。


三、journalctl 不是用来翻墙的

大多数人查日志时的操作:tail -f /var/log/nginx/access.log

如果 service 已经把日志交给了 journald,那你用 journalctl 可以做得更好。

按 unit 查:

journalctl -u nginx -f

只看 nginx 的日志,同时 f 参数让你像 tail -f 一样持续追踪。

按时间查:

journalctl -u nginx --since "10 min ago"
journalctl -u nginx --since "2026-06-01" --until "2026-06-02 12:00"

不需要 grep 去翻 /var/log/ 下的大文件。

按优先级查:

journalctl -u nginx -p err -b

只看当前这次启动以来的错误日志。-p err 表示 level >= err(err、crit、alert、emerg)。

实时查看最新 50 行并追踪:

journalctl -u nginx -n 50 -f

查看上次启动的日志:

journalctl -u nginx -b -1

-b -2 是上上次,依此类推。crash 后分析最有用。

按 message 关键词查:

journalctl -u nginx | grep "Connection refused"

说实话,这比 grep/var/log/syslog 效率高得多——因为 -u 已经过滤到该服务,数据量小了几个数量级。

⚠️ 一个坑:journald 默认日志持久化需要手动配。如果你没有做,重启后只能看到当前启动的日志。

sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald

做一次,之后日志持久到磁盘。


四、用户级 systemd:每个用户都可以有自己的服务

不是只有 root 才能用 systemd。普通用户也能 systemctl --user 管理自己的守护进程。

systemctl --user enable --now my-service.timer

这对不需要 root 权限的场景很实用:个人代理隧道、开发环境服务、后端 API 模拟器。

用户服务的文件放到 ~/.config/systemd/user/ 下。

注意事项:

  • 用户服务默认在用户登录时启动,退出时停止。
  • 如果想要无登录时也运行(比如开机就起一个 trojan 客户端),需要 loginctl enable-linger $USER
sudo loginctl enable-linger $(whoami)

开了 linger 后,用户服务在无登录状态下也会运行。对后台常驻服务非常有用。


五、分析开机慢:systemd-analyze

先来条命令跑一下:

systemd-analyze blame

输出按启动耗时从长到短排列,一眼看出哪个 service 拖慢了开机。

5.234s networkd-wait-online.service
3.541s plymouth-quit-wait.service
2.102s dev-sda1.device
1.234s postgresql.service
...

看到 networkd-wait-online.service 5 秒多——如果你不需要启动时网络完全就绪(多数场景不需要),可以直接 disable 掉:

sudo systemctl disable systemd-networkd-wait-online.service

图形化分析:

systemd-analyze plot > /tmp/boot.svg

浏览器打开 SVG,每个服务的启动时间、依赖关系、并行执行一目了然。


六、临时覆盖环境变量和参数(调试利器)

不想改配置,只是临时跑一次?

systemctl run user@1234.service -- -D 2>&1 | tee /tmp/debug.log

或者一个更实用的模式——直接在命令行里覆盖 service 的环境变量:

sudo systemctl set-environment FOO=bar
sudo systemctl restart my-service

set-environment 设置的是全局环境变量,对该用户的所有 systemd 服务生效。调试完记得 unset。


七、几个小但管用的

查看 service 文件最终合并态:

systemctl cat nginx

查看 service 依赖树:

systemctl list-dependencies nginx

看所有 timer 及下次执行时间:

systemctl list-timers --all

这是我最常用的一条命令之一。一眼可以看到每个定时任务的下次执行时间和已过去的时间。

mask 一个 service(彻底禁用):

sudo systemctl mask nginx

disable 只是不让开机自启,但其他服务还可以依赖它来启动它。mask 建立了一个空符号链接到 /dev/null——任何企图启动这个服务的操作都会静默失败。极其有用,比如系统预装但你不需要的服务。


收尾

systemd 不止是 start/stop/restart。它是一个完整的系统管理框架,覆盖了初始化、服务、定时任务、日志、boot 分析、资源限制。

这篇文章说的几个点,每一个都是你遇到问题、去 StackOverflow 搜了三个小时之后才「原来这么简单」的事情。

如果只带走三个:

  • 定时任务用 timer,别碰 cron
  • 改配置用 drop-in,别碰原文件
  • 查日志用 journalctl -u,别再 tail 日志文件

原文发表于 cn-res.vip,没有版权自由转载。标明出处非常感谢,删了也没事。