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

Gab*_*ern 27 tmux sshd

摘要:我试图弄清楚为什么我的 tmux 会话在我与 ssh 断开连接时会死掉

详情

我在 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 +++
Run Code Online (Sandbox Code Playgroud)

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

Pav*_*rda 17

理论

包括 systemd 在内的一些 init 系统提供了一个功能来终止属于该服务的所有进程。该服务通常会启动单个进程,该进程通过分叉创建更多进程,这些进程也可以这样做。所有这些过程通常被视为服务的一部分。在 systemd 中,这是使用cgroups完成的。

在 systemd 中,当服务默认停止时,属于服务的所有进程都会被杀死。SSH 服务器显然是服务的一部分。当您连接到服务器时,SSH 服务器通常会分叉并且新进程处理您的 SSH 会话。通过从 SSH 会话进程或其子进程分叉,其他服务器端进程将启动,包括您的screentmux

Killmode 和套接字激活

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

解决方案

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

KillMode=process设置也可能对 classic 有用ssh.service,因为它避免在服务器停止或重新启动时终止SSH 会话进程或screentmux进程。

未来笔记

这个答案显然获得了一定程度的普及。虽然它适用于 OP,但由于systemd-logind 开发或配置,它可能会在未来对某人不起作用。如果您遇到与此答案中的描述不同的行为,请查看有关 logind 会话的文档。

  • 感谢您的详细回复。切换到 sshd.service 解决了这个问题。 (3认同)

mir*_*los 5

您是否将 systemd 与 SSH 的套接字激活一起使用?

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

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

  • 链接已关闭,如果有链接中的信息,答案会更有用。 (3认同)
  • @PavelŠimerda 是的,我认为这是隐含的,但现在编辑了帖子以使其更加明确。 (2认同)

小智 5

我在 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"