如何让我的systemd服务以特定用户身份运行并在启动时自动启动?

我刚从Ubuntu服务器14升级到版本15。升级后,我在让我的upstart脚本正常工作方面遇到了困难,并且了解到systemd是新的默认选项。我离Linux专家还有很大距离,所以请对我温柔点 :-)
以下是我之前的upstart脚本内容:
description "NZBGet upstart script"

setuid robert
setgid robert

start on runlevel [2345]
stop on runlevel [016]

respawn

expect fork

script
    exec nzbget -D
end script

pre-stop script
    exec nzbget -Q
end script

根据upstart to systemd wiki page,我使用那里提供的表格尽可能地将事物映射到我的新systemd服务文件中。
[Unit]
Description=NZBGet Service

[Service]
Type=forking
ExecStart=/usr/local/bin/nzbget -D
ExecStop=/usr/local/bin/nzbget -Q
Restart=on-failure

这个文件位于/home/robert/.config/systemd/user/nzbget.service。要手动启动服务,我一直在执行以下操作:
$ systemctl --user start nzbget

这个工作得很好。然而,当我退出 SSH 会话时,该服务就会关闭。而且它不会在启动或用户登录时自动启动。我希望它的行为与作为 upstart 服务时相同:即在启动时开始运行,持续运行,并作为特定用户运行。
我需要做什么来获得这个配置?
2个回答

第一个问题

您可以在单元文件的 [Service] 部分中指定指令 User=Group=

第二个问题

要使服务在启动时运行,您不应将其放在您的主目录下。而是将其放在 /etc/systemd/system/ 目录下。这是系统管理员(即您)用来添加新的系统范围服务的目录。

其他目录包括:

  • /usr/lib/systemd/system/ 用于安装单元文件的软件包,尽管在 Debian 和 Ubuntu 中,该目录实际上是 /lib/systemd/system/,因为各种 binlib 目录尚未合并为统一的 /usr/ 前缀。
  • /usr/local/lib/systemd/system/ 用于安装本地编译的软件包的单元文件。

测试该单元

一旦单元文件位于适当的位置,您可以尝试立即启动该单元,只需像往常一样键入systemctl start <UNIT_FILENAME>。无需输入单元的完整路径,它应该可以正常工作。如果扩展名是.service,也不需要指定。

启用单元

在启用单元之前,您需要添加一个[Install]部分,在其中添加指令WantedBy=multi-user.target。此指令指定了服务应在引导过程的哪个阶段启动(如果已启用)。对于大多数服务来说,multi-user.target是合适的。
添加了这些信息后,您可以使用systemctl enable <UNIT_FILENAME>来启用该单元,从此以后,systemd将在指定的阶段自动启动它。

这个方法有效。不过,在systemctl enable命令中,我必须指定服务文件的绝对路径,这一点起初并不明显。此外,启用时出现了一个关于缺少[Install]部分的警告。我忽略了它,但我不确定它是否会影响服务在启动时的能力。 - void.pointer
3“Install”警告实际上非常重要。在“[Install]”部分下没有WantedBy=multi-user.target,它将无法在启动时启动。在.service文件中添加这个之后,你才能够进行enable操作。 - void.pointer
6非常抱歉让您的问题长时间得不到回复。我已经修正了单元文件应该放置的位置,并补充了关于[Install]部分缺失的信息。希望现在对寻找答案的任何人都更有帮助了。 - Yamaho
9当用户名被模板化时,这变得更加容易,即你的服务以something@.service的格式定义了一个文件名,然后像something@username.service一样被enable,设置变成了User=%i,意味着用户不是硬编码的,多个用户可以使用相同的定义。一个例子。 - Walf
2如果我把它放在/etc/systemd/user/下面,它会启动吗? - Khurshid Alam
3你的单元文件应该放在/usr/local/lib/systemd/system目录下,并且你可以使用systemctl enable [service]命令将它们链接到/etc/systemd/system目录中。你不应该直接将文件放在/etc/systemd/system目录下。请参考man systemd,在DIRECTORIES部分查看相关信息。 - fbicknel
3根据Arch发行版的说法,这是不正确的:https://wiki.archlinux.org/index.php/Systemd/User "/etc/systemd/user/ 是系统管理员放置系统范围用户单元的位置。"(并不一定有普遍真实性...我只是希望以最直接的方式为自己完成) - some bits flipped
我不确定我全都理解正确。1. 我安装了一个非root的应用程序,我想将其设置为特定的技术用户自动启动,而不是root用户。我应该把.service文件放在哪里?在引导时,如何告诉系统以该用户而非root用户身份调用systemctl start命令?2. 我希望技术用户能够使用systemctl来启动/停止应用程序。我假设更改/lib/systemd/system/目录的权限不是正确的方法。我该如何实现这一点? - Thomas
关于“_要使服务在启动时运行,您不应将其放在您的主文件夹中_”:这是错误的;对于Unix用户robert来说,在他们的~/.config/systemd/user/nzbget.service位置上有一个名为nzbget.service的用户服务是可以的。然后,robert可以使用systemctl --user enable nzbget来启用此服务。 - Abdull

你可能会对使用systemd的user lingering功能感兴趣。它可以通过loginctl enable-linger USERNAME来启用。
这将导致在启动时为相应的用户启动一个单独的服务管理器,因此您在~/.config/systemd/user中定义的单位将根据您的服务配置在启动和关机时被捕获和处理。
您还可以使用systemctl --user来管理和配置服务,它将操作您的用户服务管理器,而不是系统的服务管理器。

12systemctl --user 是一个很棒的发现。谢谢! - Anwar
@byteborg 也许你可以为 https://unix.stackexchange.com/questions/409900/user-lingering-systemd-dependency-on-postgresql 做出贡献?我需要在用户持续服务中依赖于PostgreSQL,但数据库仍然是系统服务,而不是用户的服务。 - Michał F
1一旦服务开始运行,是否有任何技术可以让用户查看服务的日志?非特权用户无法访问 /var/log/syslog。 - mpr
4请注意,systemctl --user 在 SSH 会话中似乎无法正常工作。 - Mark K Cowan
1@MarkKCowan确实如此,只需确保您可以运行它。在某些情况下,您可能会遇到错误systemd[29239]: PAM无法dlopen(pam_systemd.so):/lib/security/pam_systemd.so: 找不到共享对象文件: 没有那个文件或目录PAM添加错误的模块:pam_systemd.so,当执行systemctl start user@$USER.service时,在这种情况下,只需安装libpam-systemd,然后您将能够使其工作并在启动时启动 - Treviño
1@mpr 你可以看一下 journalctl,非特权用户也可以运行它。 - Terry Brown