把游戏服务端或网站跑起来只是第一步。真正麻烦的是:服务器重启后服务没起来、进程半夜崩了没人知道、查日志要翻好几个文件。
systemd 就是解决这些事的。它是现代 Linux 的标准服务管理器,写好一个 .service 文件,就能获得:开机自启、崩溃自动重启、统一日志、标准启停命令。
需要一台常开的机器?财富云计算 的云服务器支持 7×24 运行。NAT 型云服务器无独立公网 IP,价格比带独立 IP 的机型省一半以上,做内网服务、游戏服务端非常划算。
一、为什么要用 systemd
不用 systemd 时的典型做法:
nohup ./start.sh > server.log 2>&1 &问题一堆:
- 服务器重启后,没人再把它拉起来
- 进程崩了就真崩了,不会自动恢复
- 关掉要自己找 PID
kill - 日志会无限增长
- 不知道它是从什么时候开始跑的、跑没跑起来
用了 systemd 之后:
systemctl start myserver
systemctl stop myserver
systemctl restart myserver
systemctl enable myserver # 开机自启
systemctl status myserver
journalctl -u myserver -f # 看日志服务挂了还能自动重启,运维体验完全不同。
二、systemd 基础命令
systemctl start nginx # 启动
systemctl stop nginx # 停止
systemctl restart nginx # 重启
systemctl reload nginx # 重载配置(不中断服务,nginx 支持)
systemctl status nginx # 查看状态与最近日志
systemctl enable nginx # 设置开机自启
systemctl enable --now nginx # 设置自启并立即启动
systemctl disable nginx # 取消开机自启
systemctl is-enabled nginx # 查询是否自启
systemctl is-active nginx # 查询是否在运行
systemctl list-units --type=service # 列出已加载的服务
systemctl list-units --type=service --state=failed # 只看失败的
systemctl list-unit-files --type=service # 列出所有服务文件及自启状态
systemctl daemon-reload # ⚠️ 改了 service 文件后必须执行
systemctl reset-failed # 清除失败计数开机启动耗时分析(想优化开机速度时):
systemd-analyze
systemd-analyze blame # 谁拖慢了开机
systemd-analyze critical-chain三、service 文件写在哪
| 路径 | 用途 |
|---|---|
/etc/systemd/system/ | 管理员自建服务的推荐位置,优先级最高 |
/usr/lib/systemd/system/(有的发行版是 /lib/systemd/system/) | 软件包安装的服务 |
~/.config/systemd/user/ | 用户级服务(需 systemctl --user) |
自建服务统一放 /etc/systemd/system/,比如 /etc/systemd/system/gameserver.service。
四、service 文件结构详解
一个完整例子(游戏服务端):
[Unit]
Description=CS2 Game Server
Documentation=https://z0w.cn
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=steam
Group=steam
WorkingDirectory=/opt/steam/cs2
ExecStart=/opt/steam/cs2/start.sh
ExecStop=/bin/kill -SIGTERM $MAINPID
ExecReload=/bin/kill -SIGHUP $MAINPID
Restart=on-failure
RestartSec=10
TimeoutStopSec=30
KillSignal=SIGTERM
StandardOutput=journal
StandardError=journal
SyslogIdentifier=cs2
LimitNOFILE=65535
Environment="LANG=en_US.UTF-8"
EnvironmentFile=/opt/steam/cs2/env.conf
[Install]
WantedBy=multi-user.target[Unit] 段
| 字段 | 说明 |
|---|---|
Description | 服务描述,systemctl status 里能看到 |
Documentation | 文档链接 |
After | 在哪些单元之后启动(只管顺序,不表示依赖) |
Before | 在哪些单元之前启动 |
Requires | 强依赖,依赖挂了自己也停 |
Wants | 弱依赖,依赖挂了自己继续跑 |
Conflicts | 与哪些服务互斥 |
游戏服务端最常用的就是 After=network-online.target,确保网络真正就绪(不是 network.target,那个只表示网络服务启动了,不代表 IP 已拿到)。
[Service] 段(核心)
| 字段 | 说明 |
|---|---|
Type | 进程类型,见下文 |
User / Group | 以哪个用户身份运行(强烈建议不要 root) |
WorkingDirectory | 工作目录 |
ExecStart | 启动命令(必须绝对路径) |
ExecStop | 停止命令 |
ExecReload | 重载命令 |
Restart | 重启策略 |
RestartSec | 重启前等待秒数 |
TimeoutStopSec | 停止超时时间 |
Environment | 环境变量,可多行 |
EnvironmentFile | 从文件读环境变量 |
LimitNOFILE | 文件句柄上限(高并发服务要调) |
StandardOutput | 输出去向(journal / file:路径 / null) |
SyslogIdentifier | 日志里的标识名 |
Type 取值:
| 类型 | 适用 |
|---|---|
simple(默认) | 程序在前台运行不退出,大多数情况 |
forking | 程序会 fork 到后台(传统 daemon),需配 PIDFile= |
oneshot | 跑完就退出的脚本(配合 RemainAfterExit=yes) |
notify | 程序启动完会主动通知 systemd(需程序支持 sd_notify) |
idle | 等其他任务都完成了再执行 |
Restart 策略:
| 值 | 含义 |
|---|---|
no | 不自动重启(默认) |
always | 无论什么原因退出都重启 |
on-success | 正常退出(code 0)才重启 |
on-failure | 非正常退出、超时、被信号杀死时重启(最常用) |
on-abnormal | 被信号杀死或超时才重启 |
on-abort | 异常终止才重启 |
on-watchdog | 看门狗超时才重启 |
[Install] 段
[Install]
WantedBy=multi-user.target # 多用户命令行模式(服务器标准)systemctl enable 的本质就是在 multi-user.target.wants/ 目录里建一个软链接。图形界面环境用 graphical.target。
五、实战一:把游戏服务端做成服务
以 SteamCMD 装的通用服务端为例:
1)建专用用户
useradd -r -m -s /sbin/nologin steam
mkdir -p /opt/steam/cs2
chown -R steam:steam /opt/steam2)写启动脚本
nano /opt/steam/cs2/start.sh#!/bin/bash
cd /opt/steam/cs2
./cs2 -dedicated -console \
-port 27015 \
+map de_dust2 \
+maxplayers 10 \
-tickrate 128chmod +x /opt/steam/cs2/start.sh
chown steam:steam /opt/steam/cs2/start.sh注意:启动命令必须是前台阻塞运行的。如果你的脚本里用了 nohup ... & 把自己放到后台,systemd 会认为进程已退出,服务立刻失败。3)写 service 文件
sudo nano /etc/systemd/system/cs2.service[Unit]
Description=Counter-Strike 2 Dedicated Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=steam
Group=steam
WorkingDirectory=/opt/steam/cs2
ExecStart=/opt/steam/cs2/start.sh
Restart=on-failure
RestartSec=15
LimitNOFILE=65535
StandardOutput=journal
StandardError=journal
SyslogIdentifier=cs2
[Install]
WantedBy=multi-user.target4)启用
sudo systemctl daemon-reload
sudo systemctl enable --now cs2
sudo systemctl status cs2现在它会开机自动启动,崩了 15 秒后自动重启。
六、实战二:给程序设置资源限制与自动重启策略
限制内存(防止服务端吃光内存把系统拖死):
[Service]
MemoryMax=6G # 硬上限,超过会被 OOM kill
MemoryHigh=5G # 软上限,超过会限流/回收(不杀进程)
CPUQuota=200% # 最多用 2 个核
TasksMax=500
LimitNOFILE=65535
LimitNPROC=4096崩溃后逐步退避重启(避免疯狂重启循环):
[Service]
Restart=on-failure
RestartSec=10
StartLimitIntervalSec=300
StartLimitBurst=5 # 5 分钟内最多重启 5 次,超过就放弃进程守护看门狗(程序需支持 sd_notify):
[Service]
WatchdogSec=30七、实战三:定时/一次性任务(systemd timer,替代 cron)
cron 的问题是不好调试、没有日志、系统忙时会跳过。systemd timer 更现代:
/etc/systemd/system/backup.service
[Unit]
Description=Daily backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh/etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true # 关机错过的时间点,开机后补跑
RandomizedDelaySec=300 # 随机延迟,避免多机同时跑
[Install]
WantedBy=timers.targetsystemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers # 查看所有定时器OnCalendar 常用写法:
OnCalendar=daily # 每天 00:00
OnCalendar=*-*-* 03:00:00 # 每天 3 点
OnCalendar=Mon *-*-* 02:00:00 # 每周一 2 点
OnCalendar=*-*-01 04:00:00 # 每月 1 号 4 点
OnCalendar=*:0/15 # 每 15 分钟八、日志:journalctl 用法
journalctl -u cs2 # 看某个服务的全部日志
journalctl -u cs2 -f # 实时跟踪(等同 tail -f)
journalctl -u cs2 --since "2026-10-01" --until "2026-10-02"
journalctl -u cs2 -n 100 # 最近 100 行
journalctl -u cs2 -p err # 只看错误级别
journalctl -b # 本次开机以来的日志
journalctl -b -1 # 上一次开机的日志
journalctl --disk-usage # 日志占了多少磁盘
journalctl -u cs2 -o json-pretty # JSON 格式输出(给程序处理)日志会占磁盘,建议限制:
sudo nano /etc/systemd/journald.conf[Journal]
SystemMaxUse=500M
MaxRetentionSec=14day
Compress=yessudo systemctl restart systemd-journald
journalctl --vacuum-size=500M # 立即清理到 500M
journalctl --vacuum-time=7d九、调试 service 的套路
服务起不来,按这个顺序查:
# 1. 看状态和最近的日志
systemctl status myserver -l
# 2. 看完整日志
journalctl -u myserver -n 100 --no-pager
# 3. 手动跑一遍 ExecStart,看是不是命令本身有问题
sudo -u steam /opt/steam/cs2/start.sh
# 4. 检查语法
systemd-analyze verify /etc/systemd/system/myserver.service
# 5. 重置失败状态(超过重启上限后服务会进入 failed)
systemctl reset-failed myserver
systemctl start myserver常见错误:
| 报错 | 原因 |
|---|---|
Failed to start: Exec format error | 脚本缺 shebang #!/bin/bash,或没 chmod +x |
Status=203/EXEC | ExecStart 路径不存在或不可执行 |
Status=217/USER | User= 指定的用户不存在 |
Status=200/CHDIR | WorkingDirectory 不存在 |
Start request repeated too quickly | 一直启动失败,触发了 StartLimit |
| 启动后马上退出(Type=simple) | 程序自己 fork 到后台了,改 Type=forking + PIDFile= |
| 改了文件没生效 | 忘了 systemctl daemon-reload |
十、服务模板:一个实例跑多个
想在一台机器上开 3 个游戏服(27015/27016/27017),用 @ 模板:
/etc/systemd/system/gamesrv@.service
[Unit]
Description=Game Server instance %i
After=network-online.target
[Service]
Type=simple
User=steam
WorkingDirectory=/opt/steam/%i
ExecStart=/opt/steam/%i/start.sh %i
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target%i 会被替换成实例名。启动:
systemctl enable --now gamesrv@cs2
systemctl enable --now gamesrv@valheim
systemctl status gamesrv@cs2一套配置管多个实例,非常适合开多服的玩家(本站《多游戏服共存与端口规划》有更详细的方案)。
十一、安全加固选项
systemd 提供不少沙箱能力,给对外服务加上能大幅降低被攻破的危害:
[Service]
# 文件系统隔离
ProtectSystem=strict # /usr /boot /etc 只读
ProtectHome=yes # 看不到 /home
PrivateTmp=yes # 独立的 /tmp
ReadWritePaths=/opt/steam/cs2 # 只放行需要写的目录
# 权限
NoNewPrivileges=yes # 禁止提权(SUID 失效)
User=steam
Group=steam
# 系统资源
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
MemoryDenyWriteExecute=yes # 禁止 W+X 内存(防部分漏洞利用)
# 网络
RestrictAddressFamilies=AF_INET AF_INET6加完后用 systemd-analyze security 服务名 打分,看看还有哪些可以加强。
十二、完整清单:给任何程序写 service 的步骤
# 1. 确认程序能前台运行
/opt/app/start.sh # 直接跑,Ctrl+C 能停住
# 2. 建运行用户
useradd -r -s /sbin/nologin apprunner
# 3. 授权目录
chown -R apprunner:apprunner /opt/app
# 4. 写 service 文件
sudo nano /etc/systemd/system/app.service
# 5. 重载并启用
sudo systemctl daemon-reload
sudo systemctl enable --now app
# 6. 验证
systemctl status app
journalctl -u app -f
# 7. 测重启恢复
sudo reboot
# 重启后 systemctl status app 应该 active常驻服务需要一台稳定的服务器。财富云计算 的云服务器 7×24 运行、支持开机自启与随时重装。若只是内网服务、游戏服务端、学习环境,选 NAT 型云服务器(无独立公网 IP)价格比带独立 IP 的机型省一半以上,性价比很高。
相关阅读:
- 《screen 与 tmux 会话保持实战》
- 《服务器资源排查:CPU / 内存 / 磁盘 / 带宽》
- 《Linux 常用命令速查表》
延伸阅读
- 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
- 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
- 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
- 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
- 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
- RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
- 短链接服务搭建:Shlink 自托管,链接数据自己掌握
- 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道

[...]systemctl disable --now bluetooth # 服务器没蓝牙一条就省几十 MB,积少成多。2. 限制游戏服内存上限用 systemd 给服务端设 MemoryMax,防止失控(详见systemd 服务实战):Service
2026-10-13 回复
[...]journalctl -u palworld -f # 实时日志第一次启动会再校验一遍文件,看到日志刷「Loading world」就是在建图了。systemd 其他玩法见systemd 服务与开机自启。五、放行端口游戏端口是 UDP,别只放 TCP:sudo ufw allow 8211/udp[...]
2026-10-15 回复
[...]* hard nproc 4096游戏服场景:服务端崩溃后重启脚本写错,每 30 秒起一个新进程,一天攒几千个。检查你的守护配置是不是「起了不检查旧的」,见systemd 服务与开机自启。六、日常监控:让异常早发现# 每日巡检三行[...]
2026-10-15 回复
[...]快照(可选,按量) = 存档不大就几乎免费对个人服来说,服务器本身就是全部成本的大头,而 NAT 型直接把这大头砍掉一半以上。带宽选型见云服务器带宽怎么选,新手 10-20M 固定带宽 + 按量兜底最稳。四、正规档:什么时候才需要加钱?出现以下任一情况,说明你的服要「升级」了,该考虑独立 IP 或更高配:稳定在线 50 人以上:NAT 型带宽是共享出口,人一多晚[...]
2026-10-18 回复
[...]└── Lethal Company.exe第三步:装专用服务端模组去 Thunderstore / NexusMods,在 Lethal Company 分类下搜 dedicated server(选维护活跃、下载量高的)。下载后解压,把里面的 dll 文件拖进 BepInEx/plugins/。首次启动一次游戏(或服务端),让模组生成配置文件。第四步:配置服务端模组首次运行后,配置在:D:\s[...]
2026-10-18 回复
[...]netsh advfirewall firewall add rule name="GameRange" dir=in action=allow protocol=UDP localport=26901-26903完整的 Windows 环境准备(远程桌面连接、运行库安装、SteamCMD 用法、开机自启、8 个常见坑)见:《Windows 云服务器开服通用前置教程》→ htt[...]
2026-10-18 回复
[...]sudo systemctl enable --now cloudrevesystemd 服务编写细节见systemd 服务编写与开机自启。3. Nginx 反代 + HTTPS:server {[...]
2026-10-18 回复