平时需要经常用到 SSH,比如登录远程服务器,用 Git 推送和更新代码等。建立一次 SSH 连接可能并不需要多久长时间,但是如果要频繁登录同一台服务器,就未免显得有些繁琐和浪费时间。如果是用用户名和密码登录,每次都要输入密码就更加让人崩溃。还有使用 Git 的时候,短时间内可能需要经常
git pull
和 git push
,如果每次操作都需要重新建立连接,等待过程就让人心生厌恶了。
实际上,SSH 有个「鲜为人知」的特性可以做到重用连接,只有在第一次登录的时候会创建新的连接,后续的会话都可以重用这个已经存在的连接。这样,后续的登录就会非常快,而且不需要输入密码认证。配置也很简单,直接上代码。
修改
~/.ssh/config
文件,添加如下配置:Host *
ControlMaster auto
ControlPath /tmp/ssh_mux_%h_%p_%r
ControlPersist 600
意思也很好理解:
Host *
这一行表示下面这些配置和规则影响到的 host,*
表示所有的远程 host 都生效。如果要指定某个(些)特定的 host,可以使用类似 Host *.example.com
的配置。ControlMaster auto
这个选项告诉 SSH 客户端尝试重用现有的连接(master connection)。ControlPath
指定了这个连接的 socket 保存的路径,这里配置的是在 /tmp 目录,实际上可以在任何有读写权限的路径下。/tmp/ssh_mux_%h_%p_%r
配置了 socket 文件名,%h
表示远程主机名(host),%p
表示远程 SSH 服务器的端口(port),%r
表示登录的远程用户名(remote user name)。这些 socket 可以随时删掉(rm
),删除后首次会话又会创建新的 master 连接。曾经遇到过这种情况,本地断网了,打开的几个远程终端都卡死,网络恢复后也一直这样,甚至打开新的终端也登录不上。这个时候只需要把之前的 socket 文件都删掉,重新登录就可以了。ControlPersist
这个选项比较重要,表示在创建首个连接(master connection)的会话退出后,master 连接仍然在后台保留,以便其他复用该连接的会话不会出现问题。这个特性在使用 Git 的时候就非常有用,在频繁提交和拉代码的时候,每次 SSH 会话都是很短暂的,如果 master 连接能保持在后台,后续的操作就会如丝般顺滑。
只需要添加上面几行配置,SSH 的体验就瞬间上升了好几个档次,简直是懒人必备.
------------------------------------------------------------
从这里看到 ssh 的 Control master 特性之后,就在
会话连接复用,对于以交互操作的使用,很不错的!对低延迟的服务器可能只是少了用户认证过程,但对于连接国外服务器,少了 TCP 握手、SSH 握手与认证等来来回回的过程,连接会快非常多的,尤其是对于常用的服务器,比如 GitHub 之类的,提速非常明显。
然后,问题就来了:系统挂起再恢复之后,大部分连接会 stalled,需要手工断开连接。即使配置了超时,它也不一定及时。于是我想,既然 netctl-auto 之类的服务能够在挂起系统时适当处理,那么我是不是也能写一个用户级的 systemd 服务来处理这件事情呢?
于是我按系统级的配置方法弄好了,结果什么也没有发生……后来才明白,只有系统级的 sleep.target,没有用户级的啊。
在 Arch Linux 官方论坛看到有人这么尝试,让系统级的 systemd 调用用户级的 systemd。配置有点不对,但是想法是非常好的!
于是就有了我现在用的方案:
启用(enable)
然后就可以让用户级的服务
------------------------------------------------------------
ssh 会话复用及用户级的sleep.target
从这里看到 ssh 的 Control master 特性之后,就在
~/.ssh/config
里启用了这个特性:
1
2
3
4
| ControlPath ~/.ssh/master-%r@%h:%p ControlMaster auto ControlPersist yes Compression yes |
然后,问题就来了:系统挂起再恢复之后,大部分连接会 stalled,需要手工断开连接。即使配置了超时,它也不一定及时。于是我想,既然 netctl-auto 之类的服务能够在挂起系统时适当处理,那么我是不是也能写一个用户级的 systemd 服务来处理这件事情呢?
于是我按系统级的配置方法弄好了,结果什么也没有发生……后来才明白,只有系统级的 sleep.target,没有用户级的啊。
在 Arch Linux 官方论坛看到有人这么尝试,让系统级的 systemd 调用用户级的 systemd。配置有点不对,但是想法是非常好的!
于是就有了我现在用的方案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| [Unit] Description=sleep.target of a systemd user session Before=sleep.target StopWhenUnneeded=yes [Service] Type=oneshot User=%I Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/bus RemainAfterExit=yes ExecStart=/usr/bin/systemctl --user start sleep.target ExecStop=/usr/bin/systemctl --user stop sleep.target [Install] WantedBy=sleep.target |
user-sleep@1000.service
之后,系统挂起时,就会调用 ID 为 1000 的用户的用户级 systemd,也 reach sleep.target 啦。当然这个用户级的 sleep.target 也得自己写:
1
2
3
4
5
| [Unit] Description=Sleep Documentation=man:systemd.special(7) DefaultDependencies=no StopWhenUnneeded=yes |
WantedBy=sleep.target
啦.
from http://lilydjwg.is-programmer.com/2016/3/8/ssh-session-reuse-and-user-level-sleep-target-for-systemd.196900.html
相关帖子:http://briteming.blogspot.com/2014/03/ssh-config-file.html
相关帖子:http://briteming.blogspot.com/2014/03/ssh-config-file.html