在linux下使用ssh连接服务器的时候,有没有感觉到下面的不方便:
- ssh连接在一段时间没有使用时,出现假死,并前导致当前终端都不能用,只能Kill掉;
- 即使在内网环境下,每次建立ssh连接都需要花费好长时间,如5s以上;
- 在已经连接到服务器A时,想再打开一个到服务器A的连接又要再次等待、输入密码,没有Windows下类似工具可以直接复制一个当前连接那么方便;
- 当从外网,通过跳板,连接到一个内网服务器时,需要经过多次ssh跳转,这种情况在拷贝文件时尤显不便。
其实这些问题,并非ssh本身的缺陷,而是ssh的默认配置决定上面的ssh行为。ssh提供大量的配置选项,通过修改这些配置项,可以改变ssh的行为,用以满足我们的需求,方便使用。
连接假死 -- 连接长时间不用,出现假死,导致不可用
原因:在ssh客户端长时间没有任何操作,ssh服务端会假设ssh连接已断开,从而释放ssh连接。由于ssh客户端默认并未使用tcp长连接,所以不会知道服务端已断开,只能出现假死状态。
相关配置项:
ServerAliveCountMax 3 ServerAliveInterval 60
ServerAliveInterval,指定ssh客户端在没有收到ssh服务端响应时,超过多长时间会自动向服务端发送一条alive消息,让服务端知道它还活着。ServerAliveInterval默认值为0,ssh就不会向服务端发送alive消息。这里将其设为60,即超过60秒,ssh就会自动发送alive消息。
ServerAliveCountMax,指定在没有收到服务端响应时,ssh客户端的最大重试次数,当重试最大次数后,服务端依然没有相应,那么ssh客户端会自动退出。默认值为3,所以可以不用设置。
建立连接时间过长
ssh连接时间过长,建立时间5秒以上。具体原因还不太清楚,现象没有复现。将SendEnv注销掉,似乎解决问题。猜测原因在于建立连接时,ssh服务端接收客户端传递过来的环境变量并设置相应的环境需要花费比较长的时间。
相关配置项:
SendEnv LANG LC_*
SendEnv,指定建立连接时,ssh客户端需要传递给ssh服务端的环境变量,服务端在接收到这些环境变量时,会用这些环境变量初始化ssh会话的环境。
连接复用
假如已经存在一个到服务器A的ssh连接,需要再打开一个终端新建一个到服务器A连接,为避免重新等待和输入密码,可以使用ssh的连接复用功能。在使用连接复用功能时,需要区分下会话与ssh连接的不同。在默认的情况下,每当我们建立一个到服务器的ssh连接时,会同时建立一个ssh连接和会话,通过会话进行交互,这里一个会话使用一个独立的ssh连接。使用连接复用时,每当新建一个新的ssh连接时,实际上只是新建了一个会话,这个会话共用了之前的ssh连接。所以在开启一个新的连接时,无需等待和验证了。
相关配置项:
ControlMaster auto ControlPath ~/.ssh/master-%[email protected]%h:%p ControlPersist yes
ControlMaster,设置建立多个与一个服务器的会话(ssh连接)时,是否公用一个网络连接。可选择值有yes、no、auto、ask、autoask。这里设置成auto,即已存在一个共用网络连接时,直接复用该网络连接,否则创建一个新的共用网络连接,进行复用。
ControlPath,设置到服务器的ssh连接的共享socket路径,这里要保证连接每一个服务器的socket路径的唯一性。这个%r表示连接服务器的用户名,%h表示连接服务器的主机名,%p表示连接服务器的端口号。
ControlPersist,设置在退出一个会话时,是否释放对应的ssh连接。默认值no,所以在退出会话时,ssh连接也会释放。这里需要连接复用,所以将其设为yes,即退出会话时,其ssh连接会永久保留。(也可以设个时间,如1h,ssh连接会保留一个小时)
复用连接的相关指令:
ssh -O check [email protected] #检查是否存在可用共享连接 ssh -O stop [email protected] #新建连接时不再使用现有共享ssh连接,但不影响现有的会话,当最后一个基于该ssh连接的会话退出时,ssh连接将释放 ssh -O exit [email protected] #强制释放当前ssh连接,如果存在会话,也将强制退出。
简化跳板登录
假设不能直接访问host2,需要先登录host1,然后再从host1登录host2。使用如下配置可直接通过host1上的tunnel登录host2,而无需关注host1的存在。
Host host2 ProxyCommand ssh [email protected] nc %h %p
相关配置项:
ProxyCommand,该参数指定一条命令,其中%h、%p替换与ControlPath相同。该命令在本地shell中执行,它的输入和输出会重定向到当前的ssh指令中,通过上面指令,相当于在host1上用nc建立了一个tunnel,然后本地ssh通过该tunnel连接到host2上。
SOCKS代理
ssh -CfND 1080 [email protected]
命令参数:
-D [bind_address:]port
端口转发
ssh -CfNL myip:8080:host.example.com:80 host.example.com
命令参数:
-L [bind_address:]port:host:hostport
执行远程命令
ssh host.example.com command
管道连接远程命令
tar -cz content | ssh host.example.com 'tar -xz'
无密码登录
ssh-keygen ssh-copy-id host.example.com