SSH反向连接内网主机+Serveo
什么是 Serveo
Serveo
是一个免费的内网穿透服务,Serveo
可以将本地计算机暴露在互联网上,官方声称其为 Ngrok
的绝佳替代品。
Serveo
其最大优点是使用现有的 SSH
客户端,无需安装任何客户端软件,即可完成端口转发。
Serveo
工作原理很简单:当用户通过 SSH
连接到 Serveo
时会与该网站建立一个远程代理,Serveo
随后会生成一个 公共 URL
,任何人都可以通过这个 URL
访问你的本地计算机。
项目地址: https://serveo.net
autossh使用文档:https://www.everythingcli.org/ssh-tunnelling-for-fun-and-profit-autossh/
使用 Serveo
Serveo
的使用非常简单,只需要可以使用 SSH
客户端并且能连接到互联网的任意系统都行。比如:Linux
、Windows
、MacOS
等系统,就算是 Android
、iOS
也同样没问题。下面我们来看几个最常用的使用实例:
1、开放本地服务到公网
将一个本地应用的 8080 端口映射到公网中。(当然也可以开放本地局域网的其它服务,替换“localhost:端口号”即可,只是毕竟通过隧道转发的原因,速度会相比慢一些)
# 如果要转发其它端口,只需替换端口为其它就可以了 $ ssh -R 80:localhost:8080 serveo.net Hi there Forwarding HTTP traffic from https://heryum.serveo.net Press g to start a GUI session and ctrl-c to quit.
SSH
连接成功后,会随机生成一个 serveo.net
二级域名。随后你就可以使用浏览器访问这个随机生成的二级域名 heryum.serveo.net
间接访问到本地计算机 8080 端口上的服务了。
SSH
初次和一个新服务器建立连接时会有提示,直接选择 yes 即可。
如果你不想使用随机域名,想指定一个固定的二级域名也是可以的。
# 这里指定为 wjoyxt.serveo.net,可以根据自身情况进行替换 $ ssh -R wjoyxt:80:localhost:8080 serveo.net Hi there Forwarding HTTP traffic from https://wjoyxt.serveo.net Press g to start a GUI session and ctrl-c to quit. ... # 上面的域名是简写的,你也可以写出完整的域名。 $ ssh -R wjoyxt.serveo.net:80:localhost:8080 serveo.net
SSH
连接成功后,此时就可以在公网上使用 ywzm.serveo.net
访问到你本地计算机 8080 端口的服务了。
上面的例子中,我们转发的是 HTTP
服务。如果你需要转发的是 TCP
服务,又应该怎么做呢?其实方法也很简单,同样只需设置公网的转发端口和本地端口就可以了。例如:我们需要将本地 3306 端口转发到公网中,使用下面命令即可。
# 可以自行设置公网端口,这里设置为 1492 $ ssh -R 1492:localhost:3306 serveo.net # 如果公网端口设置为 0,就会采用一个随机端口进行转发 $ ssh -R 0:localhost:3306 serveo.net
2、将本地 SSH 重定向到公网
在很多场景下,我们需要远程访问到本地计算机的 SSH
服务。要实现这样的需求也很简单,只需要使用下面的命令。
# 名称为自定义的,这里设置为 myhost $ ssh -R myhost:22:localhost:22 serveo.net Hi there Forwarding SSH traffic from alias "myhost" Press g to start a GUI session and ctrl-c to quit. ...
连接成功后,接下来你就可以从公网上对这个内网计算机的 SSH
进行访问了。
$ ssh -J serveo.net myuser@myhost Hi there myuser@myhost's password: Last login: Mon Dec 24 21:00:32 2019 from 127.0.0.1 ...
-J
选项是在 OpenSSH 7.3
版本才引入的,如果你使用的 SSH
客户端版本较旧,则可以使用 ProxyCommand
选项来替代。
$ ssh -o ProxyCommand="ssh -W myhost:22 serveo.net" user@myhost
一些其它技巧
1、保持 SSH 连接不超时
众所周知,SSH
连接一旦超时就会自动断开,这样就很容易造成服务中断。这里我们只需给 SSH
连接增加一个保活参数 -o ServerAliveInterval=60
就可以了。
# 每隔 60 秒做一次连接保活
$ ssh -o ServerAliveInterval=60 -R 80:localhost:8080 serveo.net
2、对 SSH 连接进行守护
上面的方法虽然可以解决超时的问题,但进程始终是在前台运行的。为了彻底解决这个问题,官方推荐使用 AutoSSH
来进行进程守护。
AutoSSH
是一个用来对 SSH
连接进行监控的程序,可在遇到程序问题或者是网络问题时自动进行重连,以达到长期保持 SSH
稳定连接的目的 。
将 AutoSSH 加入到系统服务:
这里以加入到 Systemd
系统服务为例,此方法适用于 CentOS 7
、Debian 8
、Ubuntu 16
及以上系统版本。首先,我们创建一个 AutoSSH 的 Systemd 服务。
cat > /etc/systemd/system/serveo.service <<EOF
[Unit] Description=autossh After=network.target [Service] Type=simple Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -R wjoyxt:80:localhost:8080 serveo.net ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=always [Install] WantedBy=multi-user.target EOF
AutoSSH
的 -M
参数主要用于指定一个监听端口来监视 SSH
连接状态,这里指定为 0 的主要目的是禁用 AutoSSH
的监控端口。保活依然使用 SSH
自己的 ServerAliveInterval
和 ServerAliveCountMax
选项来完成。
其次,Systemd
系统服务创建完成后,我们启动这个 AutoSSH
的服务并设置为开机自启。
$ systemctl daemon-reload
$ systemctl start serveo
$ systemctl enable serveo
3、如果你无法通过 22 端口连接到 Serveo,官方还预留了 443 端口给你使用
$ ssh -p 443 -R 80:localhost:8080 serveo.net
4、使用自定义的域名 / 子域名
默认情况下,我们都是使用的 Serveo
生成的二级域名进行连接的。如果你想使用自己的域名也是可以的,方法非常简单。只需要在你的域名所在 DNS 中添加一条 A 记录和一条 TXT 记录就可实现。
4.1 添加一条 A 记录
A | wjoyxt | 159.89.214.31
4.2 添加一条 TXT 记录
TXT | wjoyxt | authkeyfp=SHA256:pmc7ZRv7ymCmghUwHoJWEm5ToSTd33ryeDeps5RnfRY
authkeyfp
后面跟的那一串字符是 RSA
密钥指纹,你可以使用 ssh-keygen -l
命令进行查看。
DNS 解析记录增加好后,你就可以使用自定义域名进行连接了。
$ ssh -R wjoyxt.cnblogs.com:80:localhost:3000 serveo.net
至此,Serveo
的基本用法就介绍完了。如果你对它有更多的兴趣,可以去官网进行探索。
利用autossh建立稳定隧道,前提双方互加公钥信任。
# yum install autossh -y
在被控内网主机上运行:
# autossh -M 65533 -f -NR 10000:localhost:22 abc@3322.org [-p 51900] -o "ServerAliveInterval=60" -o "ServerAliveCountMax=3"
autossh的参数与ssh的参数是一致的,但是不同的是,在隧道断开的时候,autossh会自动重新连接而ssh不会。另外不同的是我们需要指出的-M参数,这个参数指定一个端口,这个端口是外网的机器用来接收内网机器的信息,如果隧道不正常而返回信息给内网机器让他实现重新连接。
-M 参数指定的端口是用来监听隧道的状态,与端口转发无关。
-M:You can disable the built-in AutoSSH monitoring port by giving it a value of 0,设为0的话,表示会禁用AutoSSH内置的监视端口(推荐)。
上面的autossh命令会另外开启一个子进程,端口号为 -M 后面的端口号+1 ,此处即 65534 。它会新建一个ssh子进程用来具体实现上面的功能
autossh 主进程 ---- 端口 65533
autossh 子进程 ---- 端口 65534
当用于连接的子进程挂掉后,主进程会重新启动一个子进程进行连接。
使用SSH客户端的ServerAliveInterval和ServerAliveCountMax选项。 ServerAliveInterval会在隧道无通信后的一段设置好的时间后发送一个请求给服务器要求服务器响应。如果服务器在 ServerAliveCountMax次请求后都没能响应,那么SSH客户端就自动断开连接并退出,将控制权交给你的监控程序。这两个选项的设置方法分别是在ssh时加入-o ServerAliveInterval=n和-o ServerAliveCountMax=m。其中n, m可以自行定义。
在进行调试autossh时,可以设置如下系统变量即可打印出详细信息:
export AUTOSSH_PIDFILE=/var/run/autossh.pid export AUTOSSH_POLL=60 export AUTOSSH_FIRST_POLL=30 export AUTOSSH_GATETIME=0 export AUTOSSH_DEBUG=1
经过测试,在出现特殊情况导致重连失败时,可手动kill客户端连接R端口的进程,此处R端口为51901,之后即可恢复正常
例如:
$ ssh root@localhost -o ConnectTimeout=5 -p 51901 "ls /yunwei" ssh: connect to host localhost port 51901: No route to host
# netstat -tulanp|grep 51901
tcp 0 0 127.0.0.1:51901 0.0.0.0:* LISTEN 22865/sshd: root
# kill 22865
首先在被控内网主机上运行:
ssh -f -NR 10000:localhost:22 abc@3322.org [-p 51900]
10000端口:在主控端服务器使用的隧道端口,可任意指定
22端口:被控内网主机的ssh连接端口
-p 2222:连接主控端的ssh连接端口,默认为22的话可省略
abc@3322.org:连接主控端使用的用户名和域名或IP地址
-f 后台执行
-N 仅用作port forwarding,不带执行远程命令
-R Port forwarding,如上,在22端口和10000端口间建立一条通道 (port:host:hostport)
-o option 可以在这里给出某些选项, 格式和配置文件中的格式一样. 它用来设置那些没有命令行开关的选项
命令使用参数
编号 | 参数 | 含义说明 |
---|---|---|
1 | -M |
用于有问题时就会自动重连;服务器 echo 机制使用的端口 |
2 | -D |
本地机器动态的应用程序端口转发 |
3 | -R |
将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口 |
4 | -L |
将本地机(客户机)的某个端口转发到远端指定机器的指定端口 |
5 | -f |
后台运行 |
6 | -T |
不占用 shell |
7 | -n |
配合 -f 参数使用 |
8 | -N |
不执行远程命令 |
9 | -q |
安静模式运行;忽略提示和错误 |
然后在主控端运行:
ssh def@localhost -p 51900
def:被控端服务器上已有用于ssh连接的用户名
进程服务化:
cat > /etc/systemd/system/autossh.service <<EOF
[Unit] Description=autossh After=network.target [Service] #User=wjoyxt Type=simple Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -M 0 -NR 51901:localhost:22 root@39.101.101.166 -p 51900 -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=always [Install] WantedBy=multi-user.target #WantedBy=graphical.target
EOF
解决ssh的"Write failed: Broken pipe"问题
问题现象:
用 ssh 命令连接服务器之后,如果一段时间不操作,再次进入 Terminal 时会有一段时间没有响应,然后就出现错误提示:
Write failed: Broken pipe
只能重新用 ssh 命令进行连接。
解决方法:
方法一:如果您有多台服务器,不想在每台服务器上设置,只需在客户端的 ~/.ssh/ 文件夹中添加 config 文件,并添加下面的配置:
ServerAliveInterval 60
方法二:如果您有多个人管理服务器,不想在每个客户端进行设置,只需在服务器的 /etc/ssh/sshd_config 中添加如下的配置:
ClientAliveInterval 60
方法三:如果您只想让当前的 ssh 保持连接,可以使用以下的命令:
$ ssh -o ServerAliveInterval=60 user@sshserver
ssh-copy-id使用非默认22端口时:ssh-copy-id "-p 5180 wjoyxt@abc.3322.org" (必须要有引号)
cat >> /etc/ssh/sshd_config << EOF
TCPKeepAlive yes 指定系统是否向客户端发送 TCP keepalive 消息。这种消息可以检测到死连接、连接不当关闭、客户端崩溃等异常,保证不会有僵尸程序的发生。
ClientAliveInterval 60 server端每60s就会向client端发送一个keep-alive包, 来保持连接
ClientAliveCountMax 10 指定发送keep-alive包(超时连接)的最大次数,超过该次数后会自动断开连接。
EOF