Ceiling

Linux 如何将程序安装成服务

在 Linux 服务器上运行程序时,如果直接在终端里执行,一旦关闭终端或断开 SSH 连接,程序就会随之退出。要让程序在后台长期稳定运行、开机自启、崩溃后自动恢复,最标准的做法就是把它交给 systemd 管理,安装为一个「服务」。

本文以 Node.js 程序为例,介绍如何将一个程序安装为 systemd 服务。

一、systemd 是什么

systemd 是现代 Linux 发行版(CentOS 7+、Ubuntu 16.04+、Debian 8+ 等)默认的初始化系统,负责在系统启动时拉起各种服务,并对它们进行统一管理。

我们只需要为程序编写一个「服务单元文件」(unit file),告诉 systemd:用什么命令启动、以什么用户运行、崩溃了怎么办,剩下的事情交给 systemd 即可。

二、创建服务单元文件

服务单元文件存放在 /etc/systemd/system/ 目录下,以 .service 结尾。例如创建一个 myapp.service

sudo vim /etc/systemd/system/myapp.service

写入以下内容:

[Unit]
Description=My Application Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/path/to/app
ExecStart=/usr/bin/node /path/to/app/index.js
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

这个文件分为三个部分:

  • [Unit]:描述服务的元信息。Description 是服务描述;After=network.target 表示等网络就绪后再启动。
  • [Service]:定义服务的运行方式,是核心部分,下面会详细解释。
  • [Install]:定义服务如何被启用。WantedBy=multi-user.target 表示在多用户模式(即正常启动模式)下运行。

三、关键配置项说明

字段说明
Type启动类型,simple(默认,ExecStart 进程即主进程)、forking(传统守护进程模式)
User运行服务的用户,如 root 或专门创建的普通用户
WorkingDirectory进程的工作目录,程序中的相对路径都基于此目录
ExecStart启动命令,必须写绝对路径
Restart重启策略:on-failure(异常退出时重启)、always(总是重启)、on-abnormal
RestartSec重启前的等待秒数
Environment设置环境变量,如 Environment=NODE_ENV=production
After指定启动顺序,在某些 target 或服务之后启动

四、常用管理命令

服务文件创建完成后,使用 systemctl 命令进行管理:

# 重新加载配置(修改/新增服务文件后必须执行)
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start myapp

# 停止服务
sudo systemctl stop myapp

# 重启服务
sudo systemctl restart myapp

# 设置开机自启
sudo systemctl enable myapp

# 取消开机自启
sudo systemctl disable myapp

# 查看服务状态
sudo systemctl status myapp

# 实时查看服务日志
sudo journalctl -u myapp -f

# 查看最近 100 行日志
sudo journalctl -u myapp -n 100

五、完整示例:部署 myapp

以一个 Node.js 程序为例,假设代码部署在服务器的 /opt/apps/myapp 目录下。

1. 创建服务文件

sudo vim /etc/systemd/system/myapp.service

内容如下:

[Unit]
Description=My App
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/apps/myapp
ExecStart=/root/.local/share/fnm/node-versions/v24.19.0/installation/bin/node /opt/apps/myapp/index.js
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

2. 启用并启动服务

sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp

3. 验证运行状态

sudo systemctl status myapp

输出中显示 active (running) 即表示服务正常运行。这样 myapp 就会在系统启动时自动运行,并在崩溃后自动重启。

六、常见坑:ExecStart 找不到 node 命令

很多人的 Node.js 是通过 fnmnvm 等版本管理工具安装的,写服务文件时如果直接这样写:

ExecStart=node /opt/apps/myapp/index.js

启动服务时会报「找不到 node 命令」的错误。

原因:systemd 启动服务时不会加载 shell 的 .bashrc.profile 等配置文件,所以 PATH 中并不包含 fnm 安装的 node 路径。 解决方法:在 ExecStart 中使用 node 可执行文件的绝对路径。先查出实际路径:
which node
# 输出类似:/root/.local/share/fnm/node-versions/v24.19.0/installation/bin/node

再把该路径填入 ExecStart。或者通过 Environment 显式设置 PATH:

Environment=PATH=/root/.local/share/fnm/aliases/default/bin:/usr/bin:/bin
ExecStart=node /opt/apps/myapp/index.js
注意:使用系统包管理器(apt/yum)安装的 Node.js 通常位于 /usr/bin/node,systemd 默认 PATH 就能找到,可以直接写 node

七、小结

将程序安装为 systemd 服务只需要三步:

  1. /etc/systemd/system/ 下编写 .service 单元文件;
  2. 执行 systemctl daemon-reload 加载配置;
  3. systemctl enable + systemctl start 启用并启动服务。

之后就可以通过 systemctl 统一管理服务,通过 journalctl 查看日志,程序崩溃也会按照 Restart 策略自动恢复,非常适合在服务器上部署 Node.js 应用。