当前位置: 首页 > Linux

搭建稳定的ssh隧道

时间:2023-04-06 02:42:23 Linux

背景网上有现成的autossh工具,专门用来建立稳定的ssh连接,但是测试效果不好,失败率高(可能是不正确的原因造成的)配置)。另一方面,在windows上安装autossh比较麻烦,需要自己编译。在Linux中使用以下方案可以节省额外的软件安装。端口转发示例以内网穿透为例。假设内网有一台树莓派(以下简称客户端),你想使用一个外网IP的服务器(以下简称服务器)创建端口转发,实现外网访问。内网树莓派的ssh服务。在树莓派上执行:ssh-NT-R1122:127.0.0.1:22username@serverIP执行后可以在服务器上登录树莓派的ssh:sshpi@127.0.0.1-p1122由于TCP连接不稳定,所以基于TCP的ssh端口转发连接也不稳定。如果网络断开,可能会提示:Connectiontoxxx.xxx.xxx.xxxclosedbyremotehost。断开连接后重新连接非常简单。ssh命令退出后,再次执行命令建立连接。伪代码如下:while(true){`ssh-NT-R1122:127.0.0.1:22username@serverIP`}但是执行ssh命令需要输入密码。首先配置ssh免密码登录,在客户端执行:$ssh-keygen$ssh-copy-idusername@serverIP输入密码后,免密码登录配置完成,接下来执行ssh命令无需输入密码即可连接到服务器。下面使用systemctl实现断线重连和开机自动运行。在客户端创建systemctl服务配置文件:sudovi/usr/lib/systemd/system/ssh-link.service写入如下内容:[Unit]Description=sshportforwardingservice.[Service]Type=simpleExecStart=/bin/sh-c'ssh-NT-R1122:127.0.0.1:22username@serverIP'Restart=alwaysRestartSec=10User=piGroup=pi[Install]WantedBy=multi-user.target其中:User和Group用于执行ssh-keygen命令的用户和组。restart=always表示ssh命令退出后,等待RestartSec=10秒,再执行。保存后运行:sudosystemctlstartssh-link查看运行状态,正常情况如下:$sudosystemctlstatusssh-linkssh-link.serviceLoaded:loaded(/usr/lib/systemd/system/ssh-link.service;坏;供应商预设:已启用)活动:活动(运行)自Sun2020-11-0823:00:33CST;3s前......开机自启动配置boot:$sudosystemctlenablessh-linkCreatedsymlink/etc/systemd/system/multi-user.target.wants/ssh-link.service→/usr/lib/systemd/系统/ssh-link.service。此时可以重启客户端,一般情况下,重启后ssh端口转发连接会自动建立。心跳检测前面提到,ssh命令退出后,systemctl会重新执行ssh命令建立连接。但是在某些特殊情况下,实际上连接断开了,但是ssh命令并没有结束。比如服务器突然断电/网线被拔掉,服务器没有发送TCP复位包,所以客户端不知道连接断开,也不会退出ssh命令。同理,如果客户端突然断电,服务器也不知道客户端“挂了”。如果客户端随后重新连接到网络并创建ssh端口转发,则可能表明服务器端口已被使用(因为服务器上的先前ssh会话仍然保持)。其实TCP连接是有心跳检测机制的,也就是TCPKeepAlive,但是默认每2小时发一个心跳包,太长了。服务器ssh配置编辑服务器上的sshd配置文件/etc/ssh/sshd_config,配置如下参数:ClientAliveInterval10ClientAliveCountMax3其中:ClientAliveInterval:该参数表示如果服务器N次没有收到客户端的数据包连续几秒,服务器会发送消息给客户端发送消息。ClientAliveCountMax:表示如果服务端发送N次数据,客户端没有收到响应,则认为连接已经断开,服务端将结束会话,关闭监听端口。上面的配置表示,如果服务端连续10秒没有收到客户端的数据,就会主动向客户端发送数据。连续3次向客户端发送数据后,没有收到回复就断开了连接。这意味着服务器将在网络断开后最多30秒内关闭ssh会话。保存后需要重启sshd服务:sudosystemctlrestartsshdclientconfiguration通过上面的配置,服务端可以检测到client是否存活。同样的,也需要修改客户端的配置,让客户端可以检测到服务器是否存活。在客户端编辑配置文件/etc/ssh/ssh_config,配置如下参数:ServerAliveInterval10ServerAliveCountMax3保存后,在客户端重启ssh:sudosystemctlrestartssh经过以上配置,就建立了一个稳定的ssh端口转发连接(已经经过几个月的实际测试,断线后会自动重连)。