systemd 服务自动重启教程:Unit 编写、日志与安全加固
讲解 Linux VPS 上 systemd service 的专用用户、Unit 文件、Restart 策略、速率限制、journal 日志、文件系统沙箱和部署排错。

systemd 服务自动重启与安全加固教程
在 Linux VPS 上长期运行 Go、Node.js、Python 或自编译程序时,直接放进后台并不足以形成可靠服务。systemd 可以管理启动顺序、运行用户、异常重启、日志和资源边界,但错误的 Restart 策略可能制造重启循环,过度加固又可能让程序无法访问必需目录。本教程依据 systemd 官方 service、exec 与 unit 文档,给出可验证的配置流程。
创建专用用户与目录
不要让普通网络服务长期以 root 身份运行。先创建没有交互登录权限的系统用户,并把程序、只读配置和可写数据分开:
sudo useradd --system --home /var/lib/myapp --create-home --shell /usr/sbin/nologin myapp
sudo install -d -o myapp -g myapp /var/lib/myapp
sudo install -d -o root -g root /etc/myapp
sudo install -m 0755 myapp /usr/local/bin/myapp
程序二进制和 unit 文件应由 root 管理,业务用户只获得数据目录写权限。敏感环境变量可放入权限为 0600 的独立文件,但更成熟的部署应使用凭据机制。Linux 权限基础可参考 Linux 运维入门教程。
编写最小 service unit
创建 /etc/systemd/system/myapp.service:
[Unit]
Description=My application service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/var/lib/myapp
EnvironmentFile=-/etc/myapp/myapp.env
ExecStart=/usr/local/bin/myapp
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
[Install]
WantedBy=multi-user.target
Type=simple 适合以前台方式持续运行的程序,应用不应自行转入后台。ExecStart 使用绝对路径,避免依赖交互 Shell 的 PATH。EnvironmentFile 前的减号表示文件不存在时不让启动直接失败;如果配置必需,应去掉减号。
加载并启动:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
sudo systemctl status myapp.service
sudo journalctl -u myapp.service --since '10 minutes ago'
每次修改 unit 后都要 daemon-reload。可先运行 systemd-analyze verify /etc/systemd/system/myapp.service 检查语法,再重启服务。
正确设置自动重启
官方 systemd.service 文档提供多种 Restart 策略。on-failure 会在进程非正常退出、信号终止或超时时重启,通常适合长期服务;always 连正常退出也会重启,可能妨碍管理员有意停止应用内部流程。RestartSec 为重启间隔,不能设为零后忽略根本故障。
还应设置启动速率限制,避免错误配置高速循环:
[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5
连续失败后 systemd 会停止重试,管理员应查看 journal、修复配置,再执行 systemctl reset-failed myapp。自动重启用于处理临时异常,不是掩盖崩溃、权限或数据库连接错误。
增加基础沙箱限制
确认服务正常后,可以逐项增加 systemd.exec 提供的安全选项:
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/myapp
NoNewPrivileges 阻止进程及其子进程通过 exec 获得额外权限;PrivateTmp 提供独立临时目录;ProtectSystem=strict 把大部分文件系统设为只读,再通过 ReadWritePaths 明确开放业务数据目录。一次只增加少量选项并测试登录、上传、缓存和后台任务。
如果应用需要读取用户家目录、调用特权辅助程序、写入非常规路径或访问设备,相关限制可能导致失败。不要从互联网上复制一组最高强度参数后直接上线。运行 systemd-analyze security myapp.service 可以检查暴露面,但评分不是业务正确性的证明。
日志、停止与部署
服务标准输出默认进入 journal。应用应输出结构化且不包含密钥的日志,并配置 journald 磁盘上限。停止时 systemd 先发送终止信号,应用应捕获信号、停止接收新请求并完成必要清理;超过 TimeoutStopSec 后可能被强制结束。
更新程序时,先在临时路径验证新二进制,再原子替换并重启。保留上一版本和数据库迁移回滚方案。自动安全更新方法可结合 Ubuntu VPS 自动安全更新教程,但应用升级应使用独立发布流程。
排错顺序
启动失败先看 systemctl status 和 journalctl -u,再核对 User、WorkingDirectory、ExecStart、环境文件和目录权限。命令在终端可用而服务失败,常见原因是 PATH、当前目录、环境变量或沙箱不同。用 sudo -u myapp 在接近服务权限的环境运行程序,可以缩小范围。
完成后应验证开机启动、异常退出后的重启、主动停止不会被误重启、日志轮转和数据目录权限。systemd 能让进程管理可预测,但真正可靠仍依赖健康检查、告警、备份和发布回滚。


