前面我们是在终端里手动启动服务的,这种方式虽然直观,但放到生产环境里会有两个明显问题:
- 终端窗口一关,或者服务器重启,服务就跟着退出了;
- 如果服务程序异常崩溃,不会有人帮我们自动重新启动。
因此在真实的 Linux 服务器环境中,像 Web 站点、数据库、API 接口这类需要长期运行的后台服务,通常会交给 systemd 来统一管理。
systemd 是 Linux 中常见的初始化系统和服务管理器。它负责:
- 开机时自动启动指定服务;
- 监控服务运行状态;
- 在服务异常退出时自动重启;
- 统一管理服务的启动、停止、查看日志等操作。
我们平时通过 systemctl 命令来和 systemd 交互。
查看服务单元配置文件
systemd 使用以 .service 结尾的配置文件来描述一个服务应该如何运行。
实验机上已经预置好了一个 bulletin.service,我们可以先查看它的内容:
crow@opsbox:~/work$ systemctl cat bulletin.service
它的核心配置如下:
[Unit]
Description=图书馆公告文件服务
After=network.target
[Service]
User=bulletin
Group=bulletin
EnvironmentFile=/etc/bulletin/server.env
ExecStart=/usr/bin/python3 -u -m http.server ${PORT} --bind ${BIND} --directory ${ROOT}
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
这个配置文件大致可以分为几个部分来理解。
Unit 段:定义服务的基本信息
[Unit]
Description=图书馆公告文件服务
After=network.target
Description:服务描述,说明这个服务是做什么的;After=network.target:表示该服务会在网络目标之后启动,也就是说,通常会等系统网络功能基本就绪后再启动服务。
这对于需要监听端口、访问网络资源的服务来说很有用,可以避免服务启动时网络还没准备好。
Service 段:定义服务如何运行
[Service]
User=bulletin
Group=bulletin
EnvironmentFile=/etc/bulletin/server.env
ExecStart=/usr/bin/python3 -u -m http.server ${PORT} --bind ${BIND} --directory ${ROOT}
Restart=on-failure
RestartSec=2
各字段的含义如下:
-
User=bulletin/Group=bulletin指定服务以bulletin这个专用用户和用户组运行。这样做的好处是权限最小化。服务进程不会使用
root权限,一旦程序本身出现问题,也能降低对系统的影响范围。 -
EnvironmentFile=/etc/bulletin/server.env表示 systemd 会从/etc/bulletin/server.env文件中读取环境变量。我们可以查看这个文件的内容:
crow@opsbox:~/work$ cat /etc/bulletin/server.env PORT=8080 BIND=127.0.0.1 ROOT=/srv/bulletin把配置放在外部文件中,可以让服务参数和启动命令分离,后续修改端口、监听地址或服务目录时更方便。
-
ExecStart表示 systemd 实际启动服务时执行的命令。在启动时,systemd 会把
${PORT}、${BIND}、${ROOT}这些变量替换成环境变量文件中的值。因此,最终执行命令大致等价于:
/usr/bin/python3 -u -m http.server 8080 --bind 127.0.0.1 --directory /srv/bulletin其中
-u参数可以让 Python 的 stdout 和 stderr 不被缓冲,这样日志输出会更及时,便于排查问题。 -
Restart=on-failure表示当服务进程非正常退出时,systemd 会自动尝试重启它。 -
RestartSec=2表示在重启前等待 2 秒,避免服务反复快速崩溃、重启、崩溃、重启。
Install 段:定义开机自启目标
[Install]
WantedBy=multi-user.target
这一部分主要影响 systemctl enable 的行为。
multi-user.target 表示系统进入普通多用户运行状态,也就是常见的服务器文本运行级别。
当我们执行:
sudo systemctl enable bulletin
systemd 会把这个服务关联到 multi-user.target,使其在系统正常进入多用户模式时自动启动。
启动、停止与重启服务
我们可以手动启动 bulletin 服务:
crow@opsbox:~/work$ sudo systemctl start bulletin
然后查看服务状态:
crow@opsbox:~/work$ systemctl status bulletin --no-pager
这里使用 --no-pager 是为了避免 status 输出内容较长时进入分页模式,直接一次性显示完整结果,方便观察。
服务启动后,可以再用 curl 验证它是否真的可以正常响应请求:
crow@opsbox:~/work$ curl -sS http://127.0.0.1:8080/hours.txt
图书馆开放时间:09:00-18:00
通过上面的操作,我们可以确认几件事:
status输出中出现Active: active (running),说明 systemd 认为服务正在运行;- 输出中有
Main PID,表示 systemd 管理的主进程号; curl能拿到文件内容,说明服务确实已经在8080端口提供文件访问。

常用的服务控制命令如下:
crow@opsbox:~/work$ sudo systemctl stop bulletin # 停止服务(主动停止不会触发异常重启)
crow@opsbox:~/work$ systemctl is-active bulletin # 查看当前是否在运行(返回 active 或 inactive)
crow@opsbox:~/work$ sudo systemctl restart bulletin # 重启服务(停止后重新启动,PID 会改变)
这里有一个细节值得注意:
如果你使用 systemctl stop 主动停止服务,systemd 会认为这是管理员的正常操作,因此即使配置了:
Restart=on-failure
它也不会自动重启服务。
只有在服务异常退出,也就是非正常失败退出时,systemd 才会按照配置执行重启策略。
开机自启与当前运行状态的区别
很多初学者会把下面两个概念搞混:
systemctl startsystemctl enable
其实它们控制的是完全不同的事情。
简单理解:
systemctl start:控制服务当前这一刻是否运行;systemctl enable:控制服务下次服务器开机时是否自动启动。
也就是说:
- 如果你只执行
start,服务现在会运行,但服务器重启后可能不会自动启动; - 如果你只执行
enable,服务会在开机时自动启动,但当前并不会立即运行,除非你同时执行start。
如果想既设置开机自启,又立刻把服务启动起来,可以使用 --now 参数:
crow@opsbox:~/work$ sudo systemctl enable --now bulletin
这条命令大致等价于:
sudo systemctl enable bulletin
sudo systemctl start bulletin
执行完成后,可以分别确认两个状态:
crow@opsbox:~/work$ systemctl is-enabled bulletin
enabled
crow@opsbox:~/work$ systemctl is-active bulletin
active
这里:
is-enabled返回enabled,说明服务已经设置为开机自动启动;is-active返回active,说明服务当前正在运行。
因此,在生产环境中,一个完整可靠的长期运行服务通常需要同时关注两个状态:
- 当前是否运行:
active - 开机是否自动启动:
enabled

