与 ssh 断开连接时 tmux 会话被终止

与 ssh 断开连接时 tmux 会话被终止

概括:我试图找出为什么当我与 ssh 断开连接时我的 tmux 会话会终止

细节:

我在 Arch Linux 系统上安装了 tmux。当我启动 tmux 会话时,我可以与其分离,然后在 ssh 会话处于活动状态时再次连接。但是如果我结束 ssh 会话,那么 tmux 会话就会被终止。

我知道这不是正常行为,因为我有其他系统,即使 ssh 会话结束,tmux 会话也会继续运行,并且我可以在建立新的 ssh 连接后附加到 tmux 会话。有问题的系统和正常工作的系统具有非常相似的配置,因此我不确定要检查什么。

我正在运行 tmux 版本 1.9a。有问题的系统(我有 root 访问权限)的 Linux 内核版本为 3.17.4-1,正常工作的系统的内核版本为 3.16.4-1-ARCH(我没有 root 权限)系统)。我怀疑内核版本是问题的根源,但这只是我注意到的一个差异。

我想我应该问问是否有人见过类似的问题并知道可能的解决方案。

导致问题的具体步骤是:

  1. ssh 到机器
  2. 运行tmux以启动 tmux
  3. ctrl-B D分离(此时我可以重新连接tmux attach
  4. 关闭 ssh 会话(此时 tmux 会话已终止,当我在不同终端中以 root 身份登录时,我能够观察到这一点)
  5. 重新连接 ssh 并运行tmux attach,我收到消息no sessions并运行tmux ls返回failed to connect to server: Connection refused。这是有道理的,因为服务没有运行。对我来说没有意义的是为什么当我从 ssh 会话断开连接时它会在步骤 4 中被终止。

跟踪数据:

为了回应其中一条评论,我使用 strace 来查看 tmux 服务器进程进行的系统调用。看起来当我退出 ssh 会话(通过输入exit或 使用ctrl-d)时,tmux 进程将被终止。这是 strace 输出的最后部分的片段。

poll([{fd=4, events=POLLIN}, {fd=11, events=POLLIN}, {fd=6, events=POLLIN}], 3, 424) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=1, si_uid=0} ---
sendto(3, "\17", 1, 0, NULL, 0)         = 1
+++ killed by SIGKILL +++

我将其与 tmux 正常工作的不同系统进行了比较,并且在该系统上,即使我退出后,tmux 进程也会继续运行。所以根本原因似乎是当我关闭 ssh 会话时 tmux 进程被终止。我需要花一些时间对此进行故障排除以找出原因,但我想我会更新我的问题,因为 strace 建议很有用。

答案1

理论

一些 init 系统(包括 systemd)提供了杀死属于该服务的所有进程的功能。该服务通常启动一个进程,该进程通过分叉创建更多进程,这些进程也可以这样做。所有此类流程通常被视为服务的一部分。在 systemd 中,这是使用以下命令完成的cgroups

在systemd中,默认情况下,当服务停止时,属于该服务的所有进程都会被终止。 SSH 服务器显然是服务的一部分。当您连接到服务器时,SSH 服务器通常会分叉,新进程会处理您的 SSH 会话。通过从 SSH 会话进程或其子进程派生,可以启动其他服务器端进程,包括您的进程屏幕或者多路复用器

Killmode 和套接字激活

可以使用指令更改默认行为KillMode。据我所知,上游项目不包含任何.service文件,因此这些文件因发行版而异。通常有两种方法可以在您的系统上启用 SSH。一种是经典的ssh.service,它维护一个长期运行的 SSH 守护进程,监听网络。另一种是通过套接字激活,由ssh.socket依次启动[email protected],仅运行一个 SSH 会话。

解决方案

如果您的进程在会话结束时被终止,则您可能正在使用套接字激活,并且当 systemd 注意到 SSH 会话进程退出时,它会被 systemd 终止。在这种情况下有两种解决方案。一是通过使用ssh.service代替来避免使用套接字激活ssh.socket。另一种是KillMode=processService的部分设置[email protected]

KillMode=process设置对于 classic 也可能很有用ssh.service,因为它可以避免终止 SSH 会话进程或屏幕或者多路复用器服务器停止或重新启动时的进程。

未来笔记

这个答案显然获得了一定程度的受欢迎。虽然它对 OP 有效,但由于以下原因,它可能对未来的某人不起作用系统登录 开发或配置。如果您遇到的行为与本答案中的描述不同,请检查有关登录会话的文档。

答案2

我在 Ubuntu 16.04 (kde neon) 上的 tmux 和 screen 上遇到了同样的问题。当 ssh 会话断开连接时, screen / tmux 被终止。

长话短说,systemd 将默认设置更改为killuserprocess=yes,因此在离开 ssh 会话后,由它创建的每个进程都将被终止。

轻松修复(经过数小时的尝试)使用此命令运行 screen/tmux

屏幕用

systemd-run --scope --user screen

对于 Tmux

systemd-run --scope --user tmux

您可以创建一个别名以使其更容易

alias tmux= "systemd-run --scope --user tmux"

答案3

您是否使用 systemd 来激活 SSH 的套接字?

如果是的话,有一个已知问题。根据 systemd 支持者的说法,这实际上是一个功能——当会话终止时,systemd 会杀死会话产生的所有进程。 (我可以看到这是有用的,但是在 GNUscreen或 的tmux情况下,你绝对当然,在用户可能运行后台进程的大多数其他情况下也不想这样。)

如果是这样,尝试从 切换sshd.socketsshd.service

答案4

我发现以下内容可以使用https://pastebin.com/2cifCXGk(从该参考文献复制的答案)。

创建文件 /etc/systemd/system/[电子邮件受保护]内容:

[Unit]
Description=Start tmux in detached session
Documentation=man:tmux(1)

[Service]
Type=forking
User=%I
ExecStart=/usr/bin/tmux new-session -s %u -d
ExecStop=/usr/bin/tmux kill-session -t %u

[Install]
WantedBy=multi-user.target

然后为每个用户启用该服务:

sudo systemctl enable tmux@${USER}.service
sudo systemctl start tmux@${USER}.service
sudo systemctl daemon-reload

或者,您可以将此文件放置在 systemd/User 目录中(不带User=%I),例如~/.config/systemd/user/tmux.service。这样,tmux 服务将在您登录时启动,除非您还启用了 systemd 用户实例的自动启动。

相关内容