systemctl 是管理 systemd 服务的实际入口,所有操作都绕不开它。直接上结论:**别碰 /usr/lib/systemd/system 里的原始文件,改配置只动 /etc/systemd/system;启停服务用 start/stop,但开机自启必须用 enable,且需配合 daemon-reload 才能让修改生效**。
先搞清楚状态信息的门道。光看 active (running) 是不够的——很多问题出在“加载了但没启用”或“启用了但被屏蔽”上。关键要看 Loaded: 行:如果显示 loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: enabled),说明服务已启用,且来自发行版默认配置;如果是 loaded (/etc/systemd/system/nginx.service; disabled),说明你手动改过,但没 enable;一旦出现 masked 字样,服务已被彻底锁死,start 和 enable 都会失败。
常用命令组合也很简单:systemctl status nginx.service 快速查看当前状态和最近日志;systemctl is-enabled nginx.service 只返回 enabled/disabled/masked,适合脚本判断;systemctl list-dependencies --reverse nginx.service 则用来查看谁依赖这个服务——比如停掉 docker.service 前,最好先确认有没有其他服务靠它活着。

为什么 systemctl enable 不生效
这其实是个非常经典的坑。很多人改完 .service 文件后,直接 systemctl enable 就以为完事了。但 enable 只负责创建软链接,根本不读新内容。正确的操作顺序是:编辑 /etc/systemd/system/myapp.service;运行 systemctl daemon-reload——通知 systemd 重新解析所有 unit 文件;再运行 systemctl enable myapp.service,此时才会基于新配置生成链接。漏掉 daemon-reload 的话,enable 用的还是旧版本定义。比如你加了 Restart=always 却没生效,大概率就是卡在这一步。
验证方法也很直接:ls -l /etc/systemd/system/multi-user.target.wants/myapp.service 确认链接是否存在;systemctl cat myapp.service 查看实际加载的是哪个路径下的文件——避免误改了 /usr/lib 下的只读副本。
reload、restart 和 reload-or-restart 选哪个
三者行为差异直接影响服务可用性。systemctl reload nginx.service 仅向进程发送 SIGHUP,Nginx 会重载配置、复用 worker 进程,连接不会中断;systemctl restart nginx.service 则是先 stop 再 start,必然中断所有连接;systemctl reload-or-restart nginx.service 先尝试 reload,失败则自动 fallback 到 restart,适合不确定服务是否支持热重载时使用。
两个注意事项:第一,reload 对 MySQL、PostgreSQL 这类数据库服务无效,它们不响应 SIGHUP,强行调用会报 Job for mysql.service failed because the control process exited with error code。第二,reload-or-restart 不是万能的,某些服务(比如早期版本的 Redis)reload 后可能丢数据,用之前最好翻翻文档确认语义。
屏蔽(mask)服务后怎么恢复
mask 是最硬核的禁用方式,它把服务链接到 /dev/null,连 start 都拒绝执行。恢复步骤必须严格:先 systemctl unmask nginx.service 解除屏蔽;再 systemctl daemon-reload 刷新状态——否则依旧显示 masked;最后 systemctl start nginx.service 或 enable 启动服务。
容易踩坑的点有两个:一是 unmask 后不执行 daemon-reload,status 依然显示 masked,让人误以为操作失败;二是 mask 会影响所有依赖它的服务,比如 mask docker.socket 会导致 docker.service 启动失败,排查时很容易忽略 socket 层这个隐藏环节。
真正需要 mask 的场景其实很少,一般是临时禁用系统级服务(比如服务器上的 ModemManager)。日常管理的话,优先用 disable 就够了。
