内网穿透

有时候我们还在开发,想一边开发一边分享给其他人体验和改进,但是又没有公网服务器供别人访问,又不是同一个局域网,该如何做呢?此时就需要进行“内网穿透”,让自己的本地电脑短暂地变成服务器(指定开放端口),使得其他人可以轻松访问。

内网穿透大致有两种:

  • 第三方提供的服务。这类往往有免费的,但是免费的带宽受限且不稳定,基本只有 1~2M 带宽,如 Zerotier、花生壳、DDNSTO、ngrok、natapp
  • 自建服务。这类都需要自身有云服务器,稳定,速度取决与云服务器的带宽,如 nps-npc、frp

1.1 nps-npc(自建)

1.1.1 简介

nps 是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持 tcp、udp 流量转发,可支持任何 tcp、udp 上层协议(访问内网网站、本地支付接口调试、ssh 访问、远程桌面,内网 dns 解析等等……),此外还支持内网 http 代理、内网 socks5 代理、p2p 等,并带有功能强大的 web 管理端。

  • 一台有公网 IP 的服务器(VPS)运行服务端(NPS
  • 一个或多个运行在内网的服务器或者 PC 运行客户端(NPC

image.png

1.1.2 特点

  • Go 语言编写
  • 支持跨平台
  • 支持多种协议的代理
  • web 管理端

1.1.3 使用方法

https://github.com/ehang-io/nps/releases

1.1.4 NPS

1.1.4.1 安装配置

找到自己服务器相应版本的 server:

1
2
3
cd ~     
wget https://github.com/cnlh/nps/releases/download/v0.23.2/linux_amd64_server.tar.gz   tar xzvf linux_amd64_server.tar.gz  
cd ~/nps

在 nps 目录下面会有一个 nps 可执行文件、conf 配置目录和 web 网页目录,我们只需要修改 conf/nps.conf 即可

需要改一下 #web 下面的几个参数,

1
2
3
4
web_host= 服务器IP或者域名     
web_username= admin(登录用户名)  
web_password= 你的密码  
web_port=8080(web管理端口)

修改 #bridge 可以更改 NPC 的连接端口。比如我们拿到一台权限受限的服务器,有防火墙,可能只有部分端口(80,443)可以出网,就需要修改成出网端口。

1
2
3
4
## bridge     
bridge_type=tcp  
bridge_port=443       # 修改连接端口  
bridge_ip=0.0.0.0

1.1.4.2 启动

1
2
3
4
5
#Mac/Linux     
./nps test|start|stop|restart|status  测试配置文件|启动|停止|重启|状态  

#Windows  
nps.exe test|start|stop|restart|status 测试配置文件|启动|停止|重启|状态

1.1.5 NPC

1
./npc -server=你的IP:8024 -vkey=唯一验证密码 -type=tcp  

image.png

新建好客户端后,也可以在 + 中看到,详细的客户端连接命令:

image.png

1.1.6 web 管理端

在客户端界面可以通过 新增 的方式添加客户端连接,每一个连接的 vkey 都是唯一区分的。

每一个客户端,在建立连接后,都可以建立多个不同协议的隧道,这一个个隧道就是不同的代理了。

image.png

通过不同的协议和端口就可以连接代理的内网机器。

1.2 frp(自建)

1.2.1 简介

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

image.png

1.2.2 特点

  • 客户端服务端通信支持 TCP、KCP 以及 Websocket 等多种协议。
  • 端口复用,多个服务通过同一个服务端端口暴露。
  • 跨平台,但是支持的比 nps 少一点
  • 多种插件,提供很多功能

1.2.3 使用方法

下载:https://github.com/fatedier/frp/releases

1.2.3.1 通过 rdp 访问家里的机器

  • 修改 frps.ini 文件,为了安全起见,这里最好配置一下身份验证,服务端和客户端的 common 配置中的 token 参数一致则身份验证通过:
1
2
3
4
5
# frps.ini    
[common]  
bind_port = 7000  
# 用于身份验证,请自行修改,要保证服务端与客户端一致  
token = abcdefgh
  • 启动 frps:./frps -c ./frps.ini
  • 修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x:
1
2
3
4
5
6
7
8
9
10
11
12
# frpc.ini  
[common]
server_addr = x.x.x.x
server_port = 7000
# 用于身份验证,请自行修改,要保证服务端与客户端一致
token = abcdefgh

[rdp]
type = tcp
local_ip = 127.0.0.1
local_port = 3389
remote_port = 6000
  • 启动 frpc:./frpc -c ./frpc.ini
  • 通过 rdp 访问远程的机器,地址为:x.x.x.x:6000

1.2.3.2 开机自启

针对 Windows 系统,为了便于使用,可以配置一下开机的时候静默启动。

  • 在 frpc.exe 的同级目录创建一个 start_frpc.vbs:
1
2
3
'start_frpc.vbs  
'请根据实际情况修改路径
CreateObject("WScript.Shell").Run """D:\Program Files\frp_windows_amd64\frpc.exe""" & "-c" &"""D:\Program Files\frp_windows_amd64\frpc.ini""",0
  • 复制 start_frpc.vbs 文件,打开以下目录,注意将 <USER_NAME> 修改为自己的用户名:C:\Users\<USER_NAME>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
  • 鼠标右击,粘贴为快捷方式即可。

1.2.3.3 通过 SSH 访问公司内网机器

frps 的部署步骤同上。

  • 启动 frpc,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
# frpc.ini  
[common]
server_addr = x.x.x.x
server_port = 7000
# 用于身份验证,请自行修改,要保证服务端与客户端一致
token = abcdefgh

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
  • 通过 SSH 访问内网机器,假设用户名为 test:ssh -oPort=6000 test@x.x.x.x

1.2.3.4 通过自定义域名访问部署于内网的 Web 服务

有时想要让其他人通过域名访问或者测试我们在本地搭建的 Web 服务,但是由于本地机器没有公网 IP,无法将域名解析到本地的机器,通过 frp 就可以实现这一功能,以下示例为 http 服务,https 服务配置方法相同, vhost_http_port 替换为 vhost_https_port, type 设置为 https 即可。

  • 修改 frps.ini 文件,设置 http 访问端口为 8080:
1
2
3
4
5
6
# frps.ini  
[common]
bind_port = 7000
vhost_http_port = 8080
# 用于身份验证,请自行修改,要保证服务端与客户端一致
token = abcdefgh
  • 启动 frps:./frps -c ./frps.ini
  • 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 Web 服务对应的端口, 绑定自定义域名 www.yourdomain.com:
1
2
3
4
5
6
7
8
9
10
11
# frpc.ini  
[common]
server_addr = x.x.x.x
server_port = 7000
# 用于身份验证,请自行修改,要保证服务端与客户端一致
token = abcdefgh

[web]
type = http
local_port = 80
custom_domains = www.yourdomain.com
  • 启动 frpc:./frpc -c ./frpc.ini
  • 将 www.yourdomain.com 的域名 A 记录解析到 IP x.x.x.x,如果服务器已经有对应的域名,也可以将 CNAME 记录解析到服务器原先的域名。
  • 通过浏览器访问 http://www.yourdomain.com:8080 即可访问到处于内网机器上的 Web 服务。

1.2.3.5 对外提供简单的文件访问服务

通过 static_file 插件可以对外提供一个简单的基于 HTTP 的文件访问服务。

frps 的部署步骤同上。

  • 启动 frpc,启用 static_file 插件,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# frpc.ini  
[common]
server_addr = x.x.x.x
server_port = 7000
# 用于身份验证,请自行修改,要保证服务端与客户端一致
token = abcdefgh

[test_static_file]
type = tcp
remote_port = 6000
plugin = static_file
# 要对外暴露的文件目录
plugin_local_path = /tmp/file
# 访问url中会被去除的前缀,保留的内容即为要访问的文件路径
plugin_strip_prefix = static
plugin_http_user = abc
plugin_http_passwd = abc
  • 通过浏览器访问 http://x.x.x.x:6000/static/ 来查看位于 /tmp/file 目录下的文件,会要求输入已设置好的用户名和密码。

1.2.3.6 常用功能

1.4.3.7 统计面板

通过浏览器查看 frp 的状态以及代理统计信息展示。

注:Dashboard 尚未针对大量的 proxy 数据展示做优化,如果出现 Dashboard 访问较慢的情况,请不要启用此功能。

需要在 frps.ini 中指定 dashboard 服务使用的端口,即可开启此功能:

1
2
3
4
5
[common]  
dashboard_port = 7500
# dashboard用户名密码,默认都为admin
dashboard_user = admin
dashboard_pwd = admin

打开浏览器通过 http://[server_addr]:7500 访问 dashboard 界面,用户名密码默认为 admin

1.4.3.7 加密与压缩

这两个功能默认是不开启的,需要在 frpc.ini 中通过配置来为指定的代理启用加密与压缩的功能,压缩算法使用 snappy:

1
2
3
4
5
6
7
# frpc.ini  
[ssh]
type = tcp
local_port = 22
remote_port = 6000
use_encryption = true
use_compression = true

如果公司内网防火墙对外网访问进行了流量识别与屏蔽,例如禁止了 SSH 协议等,通过设置 use_encryption = true,将 frpc 与 frps 之间的通信内容加密传输,将会有效防止流量被拦截。

如果传输的报文长度较长,通过设置 use_compression = true 对传输内容进行压缩,可以有效减小 frpc 与 frps 之间的网络流量,加快流量转发速度,但是会额外消耗一些 CPU 资源。

1.4.3.7 TLS

从 v0.25.0 版本开始 frpc 和 frps 之间支持通过 TLS 协议加密传输。通过在 frpc.ini 的 common 中配置 tls_enable = true 来启用此功能,安全性更高。

为了端口复用,frp 建立 TLS 连接的第一个字节为 0x17。

注意:启用此功能后除 xtcp 外,不需要再设置 use_encryption。

1.4.3.7 代理限速

目前支持在客户端的代理配置中设置代理级别的限速,限制单个 proxy 可以占用的带宽。

1
2
3
4
5
6
# frpc.ini  
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwidth_limit = 1MB

在代理配置中增加 bandwidth_limit 字段启用此功能,目前仅支持 MB 和 KB 单位。

1.4.3.7 范围端口映射

在 frpc 的配置文件中可以指定映射多个端口,目前只支持 tcp 和 udp 的类型。

这一功能通过 range: 段落标记来实现,客户端会解析这个标记中的配置,将其拆分成多个 proxy,每一个 proxy 以数字为后缀命名。

例如要映射本地 6000-6005, 6007 这 6 个端口,主要配置如下:

1
2
3
4
5
6
# frpc.ini  
[range:test_tcp]
type = tcp
local_ip = 127.0.0.1
local_port = 6000-6006,6007
remote_port = 6000-6006,6007

实际连接成功后会创建 8 个 proxy,命名为 test_tcp_0, test_tcp_1 … test_tcp_7

1.3 ngrok(第三方)

1.3.1 体验先行

国内的使用体验不是很好,即便有梯子,也不那么好用,之前折腾了半天,最后换成 natapp 一下子就搞定了

1.3.2 使用流程

  1. 进入 ngrok 官网 https://ngrok.com/download 下载 ngrok

  2. 注册一个账号,登陆账号进入管理后台,获取 Token,即左侧的 Your Authtoken

  3. 打开命令行工具

  4. 切换到 ngrok 可执行文件所在目录,执行:ngrok authtoken {{Token}}

  5. 然后就可以开启内网穿透服务了,输入以下命令:ngrok http 8080

    这样就可以实现将内网 8080 端口映射到外网域名,可以进行访问了

1.3.3 相关链接

  1. 自建 ngrok 服务实现内网穿透
  2. ngrok 实现内网穿透,端口映射,无需公网 ip 实现内网穿透
  3. 手把手教你搭建 ngrok 服务-轻松外网调试本机站点

1.4 natapp(第三方)

1.4.1 体验先行

总体体验不错,有免费和收费两种通道,免费通道感觉速度也很快,但是需要实名认证。目前主要使用它来做简单的内网穿透。

1.4.2 使用流程

  1. 进入 官网,注册并下载客户端

    image-20220821004721200

  2. 根据 快速入门文档,购买免费隧道,并获取 authtoken

  3. 修改客户端执行权限 chmod x natapp

  4. 执行命令以启动代理:./natapp -authtoken=xxxxxxx

1.4.3 相关链接

1.5 ew(自建,不推荐)

1.5.1 简介

EW 是一套便携式的网络穿透工具,具有 SOCKS v5 服务架设和端口转发两大核心功能,可在复杂网络环境下完成网络穿透。但是,现在工具已经不更新了

图片

1.5.2 特点

  1. 轻量级,C 语言编写
  2. 可以设置多级代理
  3. 跨平台
  4. 但是只支持 Socks5 代理

1.5.3 使用方法

以下所有样例,如无特殊说明代理端口均为 1080,服务均为 SOCKSv5 代理服务.

该工具共有 6 种命令格式(ssocksd、rcsocks、rssocks、lcx_slavelcx_listenlcx_tran)。

1.5.3.1 正向 SOCKS v5 服务器

1
./ew -s ssocksd -l 1080

1.5.3.2 反弹 SOCKS v5 服务器

这个操作具体分两步:

  • 先在一台具有公网 ip 的主机 A 上运行以下命令:./ew -s rcsocks -l 1080 -e 8888
  • 在目标主机 B 上启动 SOCKS v5 服务 并反弹到公网主机的 8888 端口:./ew -s rssocks -d 1.1.1.1 -e 8888

成功。

1.5.4 多级级联

工具中自带的三条端口转发指令, 它们的参数格式分别为:

1
2
3
./ew -s lcx_listen -l  1080   -e 8888    
./ew -s lcx_tran -l 1080 -f 2.2.2.3 -g 9999
./ew -s lcx_slave -d 1.1.1.1 -e 8888 -f 2.2.2.3 -g 9999

通过这些端口转发指令可以将处于网络深层的基于 TCP 的服务转发至根前,比如 SOCKS v5。首先提供两个“二级级联”本地 SOCKS 测试样例:

1.5.4.1 lcx_tran 的用法

1
2
./ew -s ssocksd  -l 9999  
./ew -s lcx_tran -l 1080 -f 127.0.0.1 -g 9999

1.5.4.2 lcx_listenlcx_slave 的用法

1
2
3
./ew -s lcx_listen -l 1080 -e 8888  
./ew -s ssocksd -l 9999
./ew -s lcx_slave -d 127.0.0.1 -e 8888 -f 127.0.0.1 -g 9999

再提供一个“三级级联”的本地 SOCKS 测试用例以供参考

1
2
3
4
./ew -s rcsocks -l 1080 -e 8888   
./ew -s lcx_slave -d 127.0.0.1 -e 8888 -f 127.0.0.1 -g 9999
./ew -s lcx_listen -l 9999 -e 7777
./ew -s rssocks -d 127.0.0.1 -e 7777

数据流向: SOCKS v5 -> 1080 -> 8888 -> 9999 -> 7777 -> rssocks