我为 jekyll 创建了自己的服务,当我启动该服务时,它似乎没有作为后台进程运行,因为我被迫退出ctrl它c。由于--watch,它只是停留在前台。我不知道如何绕过它并使其在后台运行。有什么想法吗?
# /etc/systemd/system/jekyll-blog.service
[Unit]
Description=Start blog jekyll
[Service]
Type=forking
WorkingDirectory=/home/blog
ExecStart=/usr/local/bin/jekyll build --watch --incremental -s /home/blog -d /var/www/html/blog &
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
User=root
Group=root
[Install]
WantedBy=multi-user.target
答案1
Systemd 能够处理各种不同的服务类型,特别是以下之一
simple
- 一个长时间运行的进程,不将其自身置于后台并保持附加到外壳。forking
- 一个典型的守护进程,它会自行分叉,将其与运行它的进程分离,从而有效地将自身置于后台。oneshot
- 预计将退出的短暂进程。dbus
- 与简单类似,但进程启动完成的通知是通过 dbus 发送的。notify
- 与简单类似,但进程启动完成的通知是通过 inotify 发送的。idle
- 与简单一样,但二进制文件在作业分派后启动。
在您的情况下,您选择了Type=forking
这意味着 systemd 正在等待进程自行分叉并等待父进程结束,这表明进程已成功启动。但是,您的进程并没有执行此操作 - 它保留在前台,因此systemctl start
将无限期挂起或直到进程崩溃。
相反,您需要Type=simple
,这是默认值,因此您可以完全删除该行以获得相同的效果。在这种模式下,systemd 不会等待进程完成启动(因为它无法知道何时发生),因此会立即继续执行和依赖服务。在你的情况下没有,所以这并不重要。
关于安全性的一个小注意事项:
您以 root 身份运行该服务,这是不鼓励的,因为它比以非特权用户身份运行它的安全性更低。这样做的原因是如果jekyll 中存在一个漏洞,该漏洞以某种方式允许执行命令(可能是通过它正在解析的代码),那么攻击者无需执行任何其他操作即可完全控制您的系统。另一方面,如果它以非特权用户身份运行,则攻击者只能造成与该用户一样多的破坏,现在必须尝试获得 root 权限才能完全控制您的系统。它只是增加了攻击者必须通过的额外一层。
您可以简单地以与运行 Web 服务器的用户相同的用户身份运行它,但这会让您面临另一种潜在的攻击。如果您的 Web 服务器中存在允许用户操纵系统上的文件的漏洞,他们可以修改生成的 html 文件,或者最坏的源文件并导致您的服务器提供他们想要的任何服务。但是,如果生成的文件和源文件只能由 Web 服务器读取并且可由其他非特权用户写入,那么他们将无法通过攻击 Web 服务器轻松地修改它们。
但是,如果您只是从该服务器提供静态文件并保持服务器最新,则这些攻击的可能性非常小 - 但仍然有可能。您有责任根据系统的重要性来权衡风险与设置费用,但这两个技巧的设置都非常简单,并且几乎没有维护费用。
答案2
此外 @迈克尔·达芬的解决方案,您还可以使用守护进程forking
工具来实现如下例所示的用法。
给定一个我想要守护并控制 systemd 的小 shell 脚本,我将其保存为/home/pi/testscript.sh
:
#!/bin/bash
while true;
do
sleep 1
echo -n "."
done
如果你还没有安装守护进程,请安装它,如下所示:
sudo apt install daemonize
现在创建文件服务定义文件:
sudo vi /etc/systemd/system/testomat.service
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit testomat.service
# See "man systemd.service" for details.
# copied from https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service and modified by Michael
[Unit]
Description=Test service
After=network.target
[Service]
ExecStart=daemonize -p /run/testomat/testomat.pid -o /home/pi/testscript.log /home/pi/testscript.sh
TimeoutSec=1200
# Make sure the config directory is readable by the service user
PermissionsStartOnly=true
# Process management
####################
Type=forking
PIDFile=/run/testomat/testomat.pid
Restart=on-failure
GuessMainPID = true
# Directory creation and permissions
####################################
# Run as pi:pi
User=pi
Group=pi
# /run/testomat
RuntimeDirectory=testomat
RuntimeDirectoryMode=0710
# /var/lib/testomat
StateDirectory=testomat
StateDirectoryMode=0710
# Hardening measures
####################
# Provide a private /tmp and /var/tmp.
PrivateTmp=true
# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full
# Allow access to /home, /root and /run/user
# Chosing "false" is actually no hardening, this is just to demonstrate the usage of a service. Well, I could have omitted it. True. :)
ProtectHome=false
# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true
# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true
# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true
[Install]
WantedBy=multi-user.target
新创建的服务必须向 systemd 声明:
systemctl daemon-reload
现在您可以启动服务,并且脚本会分叉。正如预期的那样,服务启动立即返回到 shell。结果显而易见:
$ tail -f testscript.log
.....................