端口映射内网穿透方案探索
# 前言
最近要开始搞持续构建,已经买了一台黑苹果主机放在公司当服务器,接下来需要穿透内网,做端口映射。之前实现过 SSH 反向隧道穿透 NAT,但太简陋了,也很慢,就算用 autossh 还是很容易断,需要探索新的方案。
# 花生壳
网上很多人说的都是说花生壳的内网穿透,这也从侧面说明花生壳的内网穿透使用起来应该是比较容易的。但这个实在没意思,傻瓜式操作。重点是,花生壳已经收费了,每个月还限制流量1G。对于网站来说,1个G能干什么,卖萌么。
如果对于穿透原理不是很执着,又不想操这个心自己折腾,花生壳内网版会是个很不错的选择。
# n2n
Github:
- https://github.com/ntop/n2n
- https://github.com/meyerd/n2n (development branch)
n2n 是在数据链路层实现的一套 P2P 协议,包括 super node 和 edge node。它是开源的,遵循 GPL v3 协议,可运行于 Linux,Windows,Android,甚至是 Openwrt 之上。
我在 CentOS 上编译完 N2N,创建了 super node。但在 MacOS 上编译失败了,遇到了一个 openssl 的报错:
$ make
Scanning dependencies of target scm
[ 3%] Building C object CMakeFiles/scm.dir/unix-scm.c.o
[ 6%] Linking C static library libscm.a
[ 6%] Built target scm
Scanning dependencies of target doc
[ 10%] Generating doc/edge.8.gz
[ 13%] Generating doc/supernode.1.gz
[ 17%] Generating doc/n2n_v2.7.gz
[ 17%] Built target doc
Scanning dependencies of target n2n
[ 20%] Building C object CMakeFiles/n2n.dir/n2n.c.o
/Users/bingo/Desktop/n2n/n2n_v2/n2n.c:458:65: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
snprintf( out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu", (a[0] & 0xff),
~~~ ^~~~~~~~~~~~~
%d
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/secure/_stdio.h:57:62: note: expanded from macro
'snprintf'
__builtin___snprintf_chk (str, len, 0, __darwin_obsz(str), __VA_ARGS__)
^~~~~~~~~~~
/Users/bingo/Desktop/n2n/n2n_v2/n2n.c:459:17: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
(a[1] & 0xff), (a[2] & 0xff), (a[3] & 0xff), sock->port );
^~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/secure/_stdio.h:57:62: note: expanded from macro
'snprintf'
__builtin___snprintf_chk (str, len, 0, __darwin_obsz(str), __VA_ARGS__)
^~~~~~~~~~~
/Users/bingo/Desktop/n2n/n2n_v2/n2n.c:459:32: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
(a[1] & 0xff), (a[2] & 0xff), (a[3] & 0xff), sock->port );
^~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/secure/_stdio.h:57:62: note: expanded from macro
'snprintf'
__builtin___snprintf_chk (str, len, 0, __darwin_obsz(str), __VA_ARGS__)
^~~~~~~~~~~
/Users/bingo/Desktop/n2n/n2n_v2/n2n.c:459:47: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
(a[1] & 0xff), (a[2] & 0xff), (a[3] & 0xff), sock->port );
^~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/secure/_stdio.h:57:62: note: expanded from macro
'snprintf'
__builtin___snprintf_chk (str, len, 0, __darwin_obsz(str), __VA_ARGS__)
^~~~~~~~~~~
4 warnings generated.
[ 24%] Building C object CMakeFiles/n2n.dir/n2n_keyfile.c.o
[ 27%] Building C object CMakeFiles/n2n.dir/wire.c.o
[ 31%] Building C object CMakeFiles/n2n.dir/minilzo.c.o
[ 34%] Building C object CMakeFiles/n2n.dir/twofish.c.o
[ 37%] Building C object CMakeFiles/n2n.dir/transform_null.c.o
[ 41%] Building C object CMakeFiles/n2n.dir/transform_tf.c.o
[ 44%] Building C object CMakeFiles/n2n.dir/transform_aes.c.o
/Users/bingo/Desktop/n2n/n2n_v2/transform_aes.c:12:10: fatal error: 'openssl/aes.h' file not found
#include "openssl/aes.h"
^
1 error generated.
make[2]: *** [CMakeFiles/n2n.dir/transform_aes.c.o] Error 1
make[1]: *** [CMakeFiles/n2n.dir/all] Error 2
make: *** [all] Error 2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
即使我用 Homebrew 安装了最新版本的 OpenSSL,并且 link 让 shell 默认使用 Homebrew 安装的 OpenSSL,确定环境没问题后,依然还是报这个错误。
谷歌无果,查到的资料基本都是关于 iOS 使用 CocoaPods 安装 openssl 依赖的时候出现的错误。
很搞笑的是,百度用「n2n macOS」作为关键词,搜出来的结果居然只有两三条相关的,一条是 「有人在 OS X 下编译 n2n 成功的么? - V2EX」,还有一条是「有在osx系统下使用n2n vpn的没?」,而且时间是在2013和2014年,也就是三四年过去了,都没有人用了?
也许它只是不支持 MacOS 而已,不满足我的需求,我选择放弃 n2n。
# localtunnel
官网: https://localtunnel.github.io/www/ Github: https://github.com/localtunnel/localtunnel
# 安装
$ npm install -g localtunnel
/usr/local/bin/lt -> /usr/local/lib/node_modules/localtunnel/bin/client
+ localtunnel@1.8.3
2
3
# 使用
lt --port 8888
your url is: https://nlatvemdpo.localtunnel.me
2
# 评论
每次跑起来,域名主机名都是随机的,不能自定义域名,只支持 HTTP 协议的隧道,并且很慢,时不时502报错,直接淘汰。搞不懂 star 数为什么会有五千多,看来写 js 的群体人数真的不少啊,抱团点赞,维护 js 的生态圈?
# PageKite
官网 http://pagekite.net/
# 安装
$ curl -s https://pagekite.net/pk/ |sudo bash
+ curl https://pagekite.net/pk/pagekite.py
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 169k 100 169k 0 0 60694 0 0:00:02 0:00:02 --:--:-- 60686
+ chmod +x /usr/local/bin/pagekite.py
+ '[' '' '!=' '' ']'
~~~~'~~~~~,~~~~~~'~~~~</>
Welcome to PageKite!
PageKite has been installed to /usr/local/bin/pagekite.py !
Some useful commands:
$ pagekite.py --signup # Sign up for service
$ pagekite.py 80 NAME.pagekite.me # Expose port 80 as NAME.pagekite.me
For further instructions:
$ pagekite.py --help |less
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 使用
$ pagekite.py 8888 dankal.pagekite.me
# 评论
稍微比较稳定,支持 HTTPS。去到官网后台管理才发现,原来是收费的!那我要你何用?各种限制,平均一个月也要二三十块,我还不如用花生壳呢。
# ngrok
官网 https://www.ngrok.cc 控制台 https://www.ngrok.cc/user.html
有免费版和收费版
免费版 | 收费版 | |
---|---|---|
服务器 | 香港免费服务器 | 香港200M VIP服务器 |
内存 | 16G | 16G |
硬盘 | 32G | 32G |
地区 | 香港 | 香港 |
带宽 | 10M | 200M |
# 安装
客户端下载 https://www.ngrok.cc/#down-client,选择对应的平台下载。
# Mac OSX 64Bit版本
$ wget http://hls.ctopus.com/sunny/darwin_amd64.zip
2
# 使用
需要先在控制台新建隧道
隧道域名: dankal
自定义域名: build-app.dankal.cn
隧道端口: -
http验证用户名: -
http验证密码: -
开通日期: 2017-09-09 14:56:12
服务器地址: server.ngrok.cc(路由器链接的时候填写,请不要暴露此地址,避免服务器遭受攻击,谢谢)
2
3
4
5
6
7
拿到对应隧道的 ID 后,使用客户端目录下的 sunny 脚本执行:
$ ./sunny clientid e807a9ffdd555f09
Sunny-Ngrok 官 网 www.ngrok.cc (Ctrl+C 退 出 )
隧 道 状 态 在 线
版 本 2.1/2.1
转 发 http://build-app.dankal.cn -> 127.0.0.1:8888
Web界 面 127.0.0.1:4040
# Conn 36
Avg Conn Time 22906.71ms
2
3
4
5
6
7
8
9
# 评论
很稳定,支持自定义域名,但自定义域名会比前缀域名速度慢很多,暂时不支持 https。免费版勉强可以用,但是带宽感觉会不够用。收费版的话,又不想花钱。
能不能自己搭建?答案是肯定的。但是,ngrok 1.x 已经不再开源,而 2.x 已经商业化不开源。而且 1.x 有 bug,比如内存泄漏,其功能也较少。所以,评估过后,我决定不踩进去了,直接跳过,继续选择其它方案。
# frp
frp 是一个高性能的反向代理应用,可以轻松地进行内网穿透,对外网提供服务,支持 TCP、UDP、HTTP、HTTPS 等协议类型,并且 web 服务支持根据域名进行路由转发。
Github: https://github.com/fatedier/frp Releases: https://github.com/fatedier/frp/releases
# 安装
可以直接下载编译好的压缩包,在上面的 Releases 页面中找到对应平台的压缩包,解压后就可以直接使用,或者自己用 GO 语言编译。
# 使用
关于 frp 的配置,我会再写一篇文章详细介绍。这里先略过 ini 文件的配置,直接启动 frp 服务。
# 服务端
$ ./frps -c frps.ini
# 客户端
$ ./frpc -c frpc.ini
# 评论
frp 是我目前发现最合适的端口映射方案,免费,稳定。配置灵活方便,支持的功能也很多,这正是我想要的!
# 后话
经过一段时间的摸索和评估,最终我采用了 frp 来做端口映射穿透内网。无论是公司的黑苹果主机服务器,还是我的树莓派服务器,都会使用 frp 来做端口映射。