New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

调试利器-SSH隧道 #11

Open
gwuhaolin opened this Issue Nov 3, 2017 · 16 comments

Comments

Projects
None yet
@gwuhaolin
Owner

gwuhaolin commented Nov 3, 2017

在开发微信公众号或小程序的时候,由于微信平台规则的限制,部分接口需要通过线上域名才能正常访问。但我们一般都会在本地开发,因为这能快速的看到源码修改后的运行结果。但当涉及到需要调用微信接口时,由于不和你在同一个局域网中的用户是无法访问你的本地开发机的,就必须把修改后的代码重新发布到线上域名所在的服务器才能去验证结果。每次修改都重新发布很繁琐也很浪费时间。

本文将教你如何通过 SSH 隧道把本地服务映射到外网,以方便调试,通常把这种方法叫内网穿透。

阅读完本文后,你能解决以下常见问题:

  • 开发微信公众号等应用时把本地服务映射到外网,加速调试流程;
  • 把你正在开发的本地服务分享给互联网上其它人访问体验;
  • 在任何地方通过互联网控制你家中在局域网里的电脑;

最终目的

把运行在本地开发机上的 HTTP 服务映射到外网,让全世界都能通过外网 IP 服务到你本地开发机上的 HTTP 服务。例如你本地的 HTTP 服务监听在 127.0.0.1:8080,你有一台公网 IP 为 12.34.56.78 的服务器,通过本文介绍的方法,可以让全世界的用户通过 http://12.34.56.78:8080 访问到你本地开发机上的 HTTP 服务。

总结成一句话就是:把内网端口映射到外网。

前提条件

为了把内网服务映射到外网,以下资源为必须的:

  1. 一台有外网 IP 的服务器;
  2. 能在本地开发机上通过 ssh 登入到外网服务器。

要满足以上条件很简单:

  • 对于条件1:购买一台低配 Linux 服务器,推荐国外的 DigitalOcean
  • 对于条件2:对于 Mac、Linux 开发机是内置了 ssh 客户端的,对于 Windows 可以安装 Cygwin

实现原理

要实现把内网端口映射到外网,最简单的方式就是通过 SSH 隧道。

SSH 隧道就像一根管道,能把任何2台机器连接在一起,把发送到其中一台机器的数据通过管道传输到另一台机器。假如已经通过 SSH 隧道把本地开发机和外网服务器连接在了一起,外网服务器端监听在 12.34.56.78:8080,那么所有发给 12.34.56.78:8080 的数据都会通过 SSH 隧道原封不动地传输给本地开发机的 127.0.0.1:8080,如图所示:

SSH隧道

也就是说,去访问 12.34.56.78:8080 就像是访问本地开发机的 127.0.0.1:8080,本地开发机上的 8080 端口被映射到了外网服务器上的 8080 端口。

如果你的外网服务器 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 8080:127.0.0.1:8080 username@12.34.56.78

如果想同时映射多个端口则可以执行:

ssh username@12.34.56.78 -R 8080:127.0.0.1:8080 -R 8081:127.0.0.1:8081

可以看出实现 SSH 隧道的命令相对于 SSH 登入多出来 -R 8080:127.0.0.1:8080,多出的这部分的含义是:
在远程机器(12.34.56.78)上启动 TCP 8080端口监听着,再把远程机器(12.34.56.78)上8080端口映射到本地的127.0.0.1:8080
执行完以上命令后,就可以通过 12.34.56.78:8080 去访问本地的 127.0.0.1:8080 了。

通常把这种技术叫做 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

通过 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 隧道后,还是无法访问 12.34.56.78:8080,那么很有可能是外网服务器上的 SSH 没有配置对。为此你需要去外网服务器上修改 /etc/ssh/sshd_config 文件如下:

GatewayPorts yes

这个选项的意思是,SSH 隧道监听的服务的 IP 是对外开放的 0.0.0.0,而不是只对本机的 127.0.0.1。不开 GatewayPorts 的后果是不能通过 12.34.56.78:8080 访问,只能在外网服务器上通过 127.0.0.1:8080 服务到本地开发机的服务。

修改好配置文件后,你还需要重启 sshd 服务来加载新的配置,命令如下:

service sshd restart

如果使用以上方法还是无法访问 12.34.56.78:8080,请检查你外网服务器的防火墙配置,确保 8080 端口是对外开放的。

其它代替方案

除了 SSH 隧道能实现内网穿透外,还有以下常用方法。

frp

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。
frp 有以下特性:

  • frp 比 SSH 隧道功能更多,配置项更多;
  • frp 也需要一台外网服务器,并且需要在外网服务器上安装 frps,在本地开发机上安装 frpc;

ngrok

ngrok 是一个商用的内网穿透工具,它有以下特点:

  • 不需要有外网服务器,因为 ngrok 会为你提供;
  • 只需要在本地开发机安装 ngrok 客户端,和注册 ngrok 账户;
  • 按照服务收费;

这些代替方案的缺点在于都需要再额外安装其它工具,没有 SSH 隧道来的直接。
想了解更多可以访问它们的主页。

阅读原文

@gwuhaolin gwuhaolin added the 网络 label Nov 3, 2017

@liuzheng644607

This comment has been minimized.

Show comment
Hide comment
@liuzheng644607

liuzheng644607 commented Nov 6, 2017

涨姿势

@simon8410

This comment has been minimized.

Show comment
Hide comment
@simon8410

simon8410 commented Nov 7, 2017

💯

1 similar comment
@VectorHo

This comment has been minimized.

Show comment
Hide comment
@VectorHo

VectorHo commented Nov 7, 2017

💯

@gitzhou

This comment has been minimized.

Show comment
Hide comment
@gitzhou

gitzhou Nov 7, 2017

用过ngrok还觉得蛮方便的 多谢解惑 学习了

gitzhou commented Nov 7, 2017

用过ngrok还觉得蛮方便的 多谢解惑 学习了

@zhugw

This comment has been minimized.

Show comment
Hide comment
@zhugw

zhugw Nov 8, 2017

多谢 ssh隧道能映射其他端口吗? 如 3306 (mysql )mongo (27017) 之类

zhugw commented Nov 8, 2017

多谢 ssh隧道能映射其他端口吗? 如 3306 (mysql )mongo (27017) 之类

@wujunze

This comment has been minimized.

Show comment
Hide comment
@wujunze

wujunze Nov 8, 2017

感谢博主分享 我自建的Ngrok用起来很方便👍 不过ngrok1.7有内存泄漏问题 准备换frp试试😀

wujunze commented Nov 8, 2017

感谢博主分享 我自建的Ngrok用起来很方便👍 不过ngrok1.7有内存泄漏问题 准备换frp试试😀

@singchia

This comment has been minimized.

Show comment
Hide comment
@singchia

singchia Nov 9, 2017

好方法长见识了,不过应该不是内网穿透,因为不是用nat实现的,像是让目标机器上sshd除了使用22端口外再另外开启端口x,从端口x的流量都复用了原来22的ssh长连接,到了源机器再做的tcp proxy。

singchia commented Nov 9, 2017

好方法长见识了,不过应该不是内网穿透,因为不是用nat实现的,像是让目标机器上sshd除了使用22端口外再另外开启端口x,从端口x的流量都复用了原来22的ssh长连接,到了源机器再做的tcp proxy。

@chapin666

This comment has been minimized.

Show comment
Hide comment
@chapin666

chapin666 Nov 10, 2017

不错 lanproxy 也可以

chapin666 commented Nov 10, 2017

不错 lanproxy 也可以

@sdhjl2000

This comment has been minimized.

Show comment
Hide comment
@sdhjl2000

sdhjl2000 commented Nov 10, 2017

666

@zhugw

This comment has been minimized.

Show comment
Hide comment
@zhugw

zhugw Nov 15, 2017

奇怪 经试验 我本地必须加上 -NTf 才起作用

另外这种方式不支持3306 Mysql服务

zhugw commented Nov 15, 2017

奇怪 经试验 我本地必须加上 -NTf 才起作用

另外这种方式不支持3306 Mysql服务

@tanchao90

This comment has been minimized.

Show comment
Hide comment
@tanchao90

tanchao90 Nov 18, 2017

个人感觉 ngrok 足以满足个人开发。

tanchao90 commented Nov 18, 2017

个人感觉 ngrok 足以满足个人开发。

@Kingson4Wu

This comment has been minimized.

Show comment
Hide comment
@Kingson4Wu

Kingson4Wu commented Dec 28, 2017

💯

@xiaofan8421

This comment has been minimized.

Show comment
Hide comment
@xiaofan8421

xiaofan8421 Jan 19, 2018

个人目前使用的是frp,周末尝试一下ssh转发。THS...

xiaofan8421 commented Jan 19, 2018

个人目前使用的是frp,周末尝试一下ssh转发。THS...

@eedba

This comment has been minimized.

Show comment
Hide comment
@eedba

eedba Mar 13, 2018

frp路过. 其它的相对来说要么收费,要么比较麻烦了.

eedba commented Mar 13, 2018

frp路过. 其它的相对来说要么收费,要么比较麻烦了.

@songguangyu

This comment has been minimized.

Show comment
Hide comment
@songguangyu

songguangyu Aug 14, 2018

发布到测试机 绑定host不行吗?

songguangyu commented Aug 14, 2018

发布到测试机 绑定host不行吗?

@Say-healer

This comment has been minimized.

Show comment
Hide comment
@Say-healer

Say-healer Sep 4, 2018

涨姿势了,回头试试。

Say-healer commented Sep 4, 2018

涨姿势了,回头试试。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment