概括:我试图找出为什么当我与 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 权限)系统)。我怀疑内核版本是问题的根源,但这只是我注意到的一个差异。
我想我应该问问是否有人见过类似的问题并知道可能的解决方案。
导致问题的具体步骤是:
- ssh 到机器
- 运行
tmux
以启动 tmux ctrl-B D
分离(此时我可以重新连接tmux attach
- 关闭 ssh 会话(此时 tmux 会话已终止,当我在不同终端中以 root 身份登录时,我能够观察到这一点)
- 重新连接 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=process
在Service
的部分设置[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
情况下,你绝对不当然,在用户可能运行后台进程的大多数其他情况下也不想这样。)
答案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 用户实例的自动启动。