建立稳定安全的SSH隧道
本文将教你如何通过 SSH 隧道把本地服务映射到外网,以方便调试,通常把这种方法叫内网穿透。
目的
把运行在本地开发机上的 SSH 服务(或其他服务如HTTP等)映射到外网,让全世界都能通过外网 IP 服务到你本地开发机上 的SSH、HTTP 服务。例如你本地的 HTTP 服务监听在 127.0.0.1:22
,你有一台公网 IP 为 12.34.56.78
的服务器,通过本文介绍的方法,可以让全世界的用户通过 http://12.34.56.78:22
访问到你本地开发机上的 SSH 服务。
前提条件
为了把内网服务映射到外网,以下资源为必须的:
- 一台有外网 IP 的服务器;
- 能在本地开发机上通过
ssh
登入到外网服务器。
要满足以上条件很简单:
- 对于条件1:购买一台低配 Linux 服务器,推荐国外的 DigitalOcean;
- 对于条件2:对于 Mac、Linux 开发机是内置了 ssh 客户端的,对于 Windows 可以安装 Cygwin。
公网IP申请
去网上申请服务器,一般都会收费,如阿里云、腾讯云、百度云等。在这里推荐由世纪互联运营的微软Azure云服务器,1元体验一个月,申请与部署方式很简单,而且服务器配置与带宽很高,可惜的是就能使用一个月,其实学服务器开发的大学朋友们也可以申请一个练练手,毕竟这是一次难得的实践机会嘛!申请免费使用网址如下https://www.azure.cn/pricing/1rmb-trial-full/。
下面这个操作尤为重要,部署成功服务器后,务必参照微软的文档为服务器添加入站与出站规则,也就是哪些类型的数据包可以进出你的服务器,那些类型的数据包会被防火墙拦截,这个步骤决定着伪装的数据包是否能够进入到我们的VBS。然后我们需要建立linux虚拟机,性能不需要太好,因为她的功能只是一个桥接的作用。虚拟机申请完成后我们就会得到系统自动分配的一个公网IP地址,通过远程连接软件我们可以远程连接到这台公网的服务器。我们想要作的是将内网中的机器映射到外网,然后我们可以在公网上通过连接这台服务器连接到我们的这台内网计算机。最简单的实现方式就是利用SSH隧道进行端口映射。
实现原理
SSH 隧道就像一根管道,能把任何2台机器连接在一起,把发送到其中一台机器的数据通过管道传输到另一台机器。假如已经通过 SSH 隧道把本地开发机和外网服务器连接在了一起,外网服务器端监听在 12.34.56.78:8080
,那么所有发给 12.34.56.78:8080
的数据都会通过 SSH 隧道原封不动地传输给本地开发机的 127.0.0.1:8080
,如图所示:
也就是说,去访问 12.34.56.78:22
就像是访问本地开发机的 127.0.0.1:22
,本地开发机上的 22 端口被映射到了外网服务器上的 22 端口。
如果你的外网服务器 IP 配置了域名解析,例如 yourdomin.com
会通过 DNS 解析为 12.34.56.78
,那么也可以通过 yourdomin.com:8080
去访问本地开发机上的服务。这样就做到了访问外网地址时其实是本地服务返回的结果。
备注:通过 SSH 隧道传输数据时,数据会被加密,就算中间被劫持,黑客也无法得到数据的原内容。所以 SSH 隧道还有一个功能就是保证数据传输的安全性。
实现步骤
把本地开机和外网服务器通过 SSH 隧道连接起来就和在本地开发机 SSH 登入远程登入到外网服务器一样简单。
先来回顾以下 SSH 远程登入命令,假如想在本地远程登入到 12.34.56.78
,可以在本地开发机上执行以下命令:
ssh username@12.34.56.78
而实现 SSH 隧道只需在本地开发机上执行:
ssh -R 2000:127.0.0.1:22 username@12.34.56.78
如果想同时映射多个端口则可以执行:
ssh username@12.34.56.78 -R 2000:127.0.0.1:22 -R 8081:127.0.0.1:8081
可以看出实现 SSH 隧道的命令相对于 SSH 登入多出来 -R 8080:127.0.0.1:22
,多出的这部分的含义是:
在远程机器(12.34.56.78
)上启动 TCP 8080端口监听着,再把远程机器(12.34.56.78
)上8080端口映射到本地的127.0.0.1:22
。
执行完以上命令后,就可以通过 12.34.56.78:8080
去访问本地的 127.0.0.1:22
了。
通常把这种技术叫做 SSH 远程端口转发(remote forwarding)。
其实不限于只能把本地开发机上运行的服务映射到外网服务器上去,还可以把任何本地开发机可以访问的服务映射到外网服务器上去。例如在本地开发机上能访问 github.com:80
,在本地开发机上执行:
ssh -R 8080:github.com:80 username@12.34.56.78
就能通过 12.34.56.78:8080
去访问 github.com:80
了。
保持运行
在执行完上面介绍的 SSH 隧道命令后,你会发现登入到了外网服务器上去了,如果你登出外网服务器,就会发现 12.34.56.78:8080
无法访问了。导致这个问题的原因是你登出外网服务器时,在外网服务器上本次操作对应的 SSH 进程也跟着退出了,而这个退出的进程曾负责监听在 8080 端口进行转发操作。
为了让 SSH 隧道一直保持在后台执行,有以下方法。
通过 SSH 自带的参数
SSH 还支持这些参数:
- N参数:表示只连接远程主机,不打开远程shell;
- T参数:表示不为这个连接分配TTY;
- f参数:表示连接成功后,转入后台运行;
因此要让 SSH 隧道一直保持在后台执行,可以通过以下命令:
ssh -NTf -R 8080:127.0.0.1:8080 username@12.34.56.78
OpenSSH基于安全的理由,如果用户连线到SSH Server后闲置一段时间,SSH Server会在超过特定时间后自动终止SSH连线。
用 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隧道不会调线就需要在网络不稳定的时候让他自己去自动连接,重新建立通信隧道。然后时刻保持连接,这个时候AutoSSH这个小软件就是个不错的选择。
通过 AutoSSH
SSH 隧道是不稳定的,在网络恶劣的情况下可能随时断开。如果断开就需要手动去本地开发机再次向外网服务器发起连接。
AutoSSH 能让 SSH 隧道一直保持执行,他会启动一个 SSH 进程,并监控该进程的健康状况;当 SSH 进程崩溃或停止通信时,AutoSSH 将重启动 SSH 进程。
使用AutoSSH 只需在本地开发机上安装 AutoSSH ,方法如下:
- Mac 系统:
brew install autossh
; - Linux 系统:
apt-get install autossh
;
安装成功后,在本地开发机上执行:
autossh -N -R 8080:127.0.0.1:8080 username@12.34.56.78
就能完成和上面一样的效果,但本方法能保持 SSH 隧道一直运行。
可以看出这行命令和上面的区别在于把 ssh
换成了 autossh
,并且少了 -f
参数,原因是 autossh 默认会转入后台运行。
其它代替方案
除了 SSH 隧道能实现内网穿透外,还有以下常用方法。
frp
frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。
frp 有以下特性:
- frp 比 SSH 隧道功能更多,配置项更多;
- frp 也需要一台外网服务器,并且需要在外网服务器上安装 frps,在本地开发机上安装 frpc;
ngrok
ngrok 是一个商用的内网穿透工具,它有以下特点:
- 不需要有外网服务器,因为 ngrok 会为你提供;
- 只需要在本地开发机安装 ngrok 客户端,和注册 ngrok 账户;
- 按照服务收费;
这些代替方案的缺点在于都需要再额外安装其它工具,没有 SSH 隧道来的直接。
想了解更多可以访问它们的主页。
总结
举两个例子具体说明一下ssh隧道建立的具体命令参数
ssh的确很强大,可以很方便的实现从本地端口到远程端口的映射,通常情况下使用 -L 或者 -R参数,例如:
ssh xxx@xxx.xxx -L 8023:RemoteIP:23
-L 将本地的某个端口映射到远程主机的某个端口上,上例中就是将本地的8023端口映射到远程主机的23号端口上,这样就可以直接telnet本机的8023端口来访问远程主机了。
但是需要说明的是RemoteIP可以是127.0.0.1,此时127.0.0.1指的是远程计算机,而非本机地址。
-R 则正好与-L相反,它将远程主机的某个端口映射到本地的某个端口上,例如:
ssh xxx@xxx.xxx -R 8023:LocalIP:23
上例将远程主机的8023端口映射到本机的23号端口,这样远程主机就可以telnet 自己的8023端口来访问本地主机了。
最后-D参数将在本地开启一个socks5代理端口,该端口接收到的数据将通过加密隧道传输到远程主机,并有远程主机代理发出,例如:
ssh xxx@xxx.xxx -D 7070
上例在本地开启一个7070号socks5代理,浏览器等应用程序可以使用该端口通过远程主机访问网络。
需要说明的是,-D参数开启的socks代理,在我的机器上好像只有Chrome能使用,IE不能使用,原因未明,估计是DNS解析的问题。
开发中经常需要外网服务映射到本机内网服务的需要,便于调试。
以前都是同事帮着配,这两天自己也看了一下 ssh 端口转发。 同事分分钟钟搞定的事情,自己折腾了 2 天, 真是弱爆了。
最初老想不明白一件事,为什们外网服务器能够找到我的内网机器,现在才明白原来走的是 ssh 隧道。
需求我的内网机器 192.168.9.100, 我的阿里云外网 123.56.86.52, 现在需要所有对 123.56.86.52 80 端口的访问都映射到 192.168.9.100 的 80 端口。
显然 123.56.86.52 访问不到 192.168.9.100, 但 192.168.9.100 能访问到 123.56.86.52 , 所以很简单 ssh 建立一个远程端口转发就行了。
1 在 192.168.9.100 上执行
ssh -N -v -R 3000:127.0.0.1:80 root@123.56.86.52
-R 表示远程转发, 这句话的意思是 通过 ssh 连接到 123.56.86.52,让 123.56.86.52 监听自己的 3000 端口, 所有通过 3000 端口的数据都通过 ssh 转发到 127.0.0.1 的 80 端口。
这里 127.0.0.1 就是 192.168.9.100 这个机器。 在 ssh 连接的时候通道就建立了, 以后所有的通信都走的是这个通道。
2 既然 123.56.86.52 已经监听在 3000 端口了, 接下来就非常简单了, 服务器上用 nginx 做一个反向代理, 把 80 端口代理到 3000 端口就行了
参考文献
https://github.com/gwuhaolin/blog/issues/11
https://www.cnblogs.com/zlgxzswjy/p/9796671.html
https://www.cnblogs.com/wumz/p/9721666.html
https://blog.csdn.net/u013511989/article/details/79972435
http://www.ha97.com/4070.html
https://www.cnblogs.com/kevingrace/p/6110842.html
建立稳定安全的SSH隧道相关推荐
- 使用 autossh 建立反向 SSH 隧道管理个人计算机
假设你有这样一个需求:你在家中有一台 Linux/Unix 设备,可以是路由器.NAS 或者台式机,存有自己常用工具或者数据,想要在自己外出时也能随时访问.那么你现在的目的和我一样了,你所需要的是少许 ...
- 使用cpolar建立固定的SSH隧道
一直以来,不同的操作系统都在相互竞争,而竞争的结果,就每种操作系统都占领了自己的一片天地.虽然现在的家用电脑大多使用Windows操作系统,但服务器领域大多使用占用资源更少的Linux系统,更不用说苹 ...
- SSH隧道详解与使用AutoSSH实现稳定的内网穿透
一.前言 SSH 是一种建立在应用层基础上的安全协议,利用SSH进行数据传输时也是较为可靠和安全的.当有明文数据传输时,为保障其安全,可以利用SSH隧道对其进行加密安全传输,本文中讲到的SSH隧道用法 ...
- 建立SSH隧道(SSH端口转发)
ssh隧道功能,也就是端口转发功能非常好用,可以实现一些代理功能或者是穿透内网功能. ssh的端口转发(或者叫做隧道)命令分为三种: 本地:ssh -C -f -N -g -L listen_port ...
- 用ssh隧道建立加密代理
putty可以很轻易地建立ssh隧道,实现加密代理.这个方法你需要有一台外部的 sshd 服务器.在自己的电脑上利用 putty 连接 sshd 服务器,建立ssh隧道. 在putty中设置连接时选择 ...
- java 建立ssh隧道_如何使用IntelliJ和JDBC SSH隧道并连接到数据库?
我在使用IntelliJ和JDBC连接到服务器上托管的数据库时遇到问题.使用命令行,命令: ssh username@server -L 11100:ct1:28017 -N 成功创建隧道并执行命令: ...
- linux ssh连接交换机_linux SSH 隧道
一 什么是SSH隧道 首 先看下面这张图,我们所面临的大部分情况都和它类似.我们的电脑在右上角,通过公司带有防火墙功能的路由器接入互联网(当然可能还有交换机什么的在中间连 接着你和路由器,但是在我们的 ...
- SSH隧道与内网穿透
SSH参数解释 -L port:host:hostPort 解释:将本地机器某个端口转发到远端指定机器的指定端口 原理:本地机器分配了一个socket监听port端口,一旦端口上有了连接,该连接就经过 ...
- SSH隧道本地转发远程转发
参考了:https://baijiahao.baidu.com/s?id=1716487922632955537&wfr=spider&for=pc 由于经常用到,找的麻烦,碰巧看到这 ...
最新文章
- JQuery $post函数
- R语言获得所有Aesthetics(美学映射)参数:使用长表输出、使用宽表输出
- Git:如何在项目提交历史中查找已删除的文件?
- DirectX标准规定 DirectX和OpenGL的不同
- 金融模型python_盘点金融领域里常用的深度学习模型
- pythonweb接口优化_python-web后台限制接口调用频率
- 2021c语言教程,全国计算机等级考试二级教程——C语言程序设计(2021年版)
- member pm.php,Dedecms 会员中心注入漏洞5
- C语言之结构体和共用体
- TP5 ZipArchive 的坑
- iOS-详解没有dSYM文件 如何解析iOS崩溃日志
- java print argc_【转】main 函数参数 argc argv env 与命令行
- 【北京-亚运村】这7家公司推荐给你
- matlab检验矩阵是否可逆,有限域上矩阵是否可逆的检验
- uni-app接入友盟
- Android系统GPS定位实现
- 基层管理者必备的能力和素质
- [ 数据集 ] COCO 数据集介绍
- 如何正确选择python的版本
- Nexus3忘记admin密码时的解决办法
热门文章
- 什么是is research?
- Changes at Different Environment?
- Java JDK11快速下载地址
- 安装JDK时提示 IllegalArgumentException:Invalid characters in hostname的解决方法
- cocos2d-x win8下的环境配置和建立项目
- git学习------gt;Git 分支管理最佳实践
- org.hibernate.exception.SQLGrammarException: Error calling Driver#connect
- Linux查看端口使用状态及启动
- NetBeans 时事通讯(刊号 # 43 - Feb 03, 2009)
- 继续VISTA下网卡驱动问题