使用反向ssh从外网访问内网主机的方法详解

由于我们自己使用的电脑未必有外网ip,因此我们需要一个有固定外网ip的服务器(随便搞个腾讯云,阿里云的小机子就行),然后用这台服务器与内网的机子进行通信,我们到时候要先登陆自己的服务器,然后再利用这个服务器去访问内网的主机。
1、准备好有固定ip的服务器A,以及待访问的内网机器B。两者都开着sshd服务,端口号默认都是22。顺便做好ssh免密码登陆。
2、内网主机B主动连接服务器A,执行以下命令:
 >$ ssh -NfR 10000:localhost:22 username@servername -p 22
这条命令的意思是在后台执行(-f),不实际连接而是做port forwarding(-N),做反向ssh(-R),将远程服务器的10000端口映射成连接本机(B)与该服务器的反向ssh的端口。
附:这里有必要加强一下记忆,这个端口号一不小心就容易搞混

man文档中的参数命令是这样的:

-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket

bind_address以及其后面的port是指远程主机的ip以及端口,host以及其后的hostport是指本机的ip和端口。由于ssh命令本身需要远程主机的ip(上上条命令中的servername),因此这个bind_address原则上是可以省略的。
执行完这条命令,我们可以在服务器A上看到他的10000端口已经开始监听:
~]$ ss -ant | grep 10000
LISTEN 0 128 127.0.0.1:10000 *:*
3、在上面的操作中,这个1111端口就已经映射成了内网主机B的22端口了,现在我们只要ssh到自己的这个端口就行了。在服务器A中执行:
 >$ ssh username@localhost -p 10000
这样就成功的登陆了内网的主机了。
功能优化
上面的做法其实有一个问题,就是反向ssh可能会不稳定,主机B对服务器A的端口映射可能会断掉,那么这时候就需要主机B重新链接,而显然远在外地的我无法登陆B

这其实有一个非常简单的解决方案,就是用autossh替代步骤2中的ssh:
C:\ > autossh -M 2222 -NfR 10000:localhost:22 username@servername -p 22
后面的参数跟ssh都一样,只是多了一个-M参数,这个参数的意思就是用本机的2222端口来监听ssh,每当他断了就重新把他连起来。。。不过man文档中也说了,这个端口又叫echo port,他其实是有一对端口的形式出现,第二个端口就是这个端口号加一。因此我们要保证这个端口号和这个端口号加一的端口号不被占用。

有时,我们会想在局域网外访问局域网内的机器。这时,我们可以使用SSH的反向连接来实现。
设备A:位于局域网内,可以访问代理服务器B。 假设该设备IP:A.A.A.A,用户名userA
设备B:位于局域网外,作为访问设备A的代理服务器,不可访问A。假设该设备IP:B.B.B.B,用户名userB
设备C:想要访问A的设备,可以访问B,无法直接访问A。假设该设备IP:C.C.C.C,用户名userC

目标:设备C可以通过SSH访问局域网内设备C

条件:三台设备都需要包含SSH客户端,A,B设备需要包含SSH服务端。

在A设备上建立A设备到B设备的反向代理:

ssh -fCNR <port_b1>:localhost:22 userB@B.B.B.B

例如:ssh -fCNR 10000:localhost:22 userB@B.B.B.B (此时B设备上已经可以通过ssh -p 10000 userA@localhost连接到设备A)

<port_b1>:建立在B机器上,用来代理设备A机器22端口的端口。

userB@B.B.B.B :B机器的用户名和IP地址。

在B设备上建立B设备到A设备的正向代理:(这样做的目的是为了实现和外网的通信)

ssh -fCNL *:<port_b2>:localhost:<port_b1> userB@localhost

例如:ssh -fCNL *:10001:localhost:10000 userB@localhost

<port_b2>:用作本地转发的端口,用来和外网通信,并将数据转发到<port_b1>,实现从其他机器可以访问。

*代表可以接受来自任意机器的访问。

现在C机器上可以通过B机器SSH到A机器

ssh -p<port_b2> userA@B.B.B.B

参数介绍

-f 后台运行-C 允许压缩数据-N 不执行任何命令-R 将端口绑定到远程服务器,反向代理-L 将端口绑定到本地客户端,正向代理