预计所需阅读时间:9分钟

一、背景

之前用Flask、Django做网页开发,开发环境在梧桐基本能完成大部分的测试,但如果要接入第三方服务,例如支付宝、微信公众号等,就需要用到内网穿透技术。内网穿透NAT最大的作用是,让外网的连接能访问到没有公网IP的内部IP的内部端口。通过内网穿透,运行在本地5000端口的服务,在外部其他人也可以通过输入特定IP: 端口形式访问到,这也是接入第三方服务的必要条件,因为第三方服务要先找到你的服务器所有地。

之前是使用https://natapp.cn/网站的服务,它有免费版,每次要打开他们提供的一个程序,访问它提供的域名,即可通过外部的域名接入本地某个端口的服务。因为是免费,每次都域名都会动态变化,所以第三方服务接入的配置也要随之变化,只能作为暂时的测试。要想测试更持久,或者让外部能稳定访问本地服务,那就可尝试去搭建自己的NAT服务。

要搭建自己的NAT服务,需要准备一台有公网IP的服务器,一般的有独立IP的VPS服务器能满足要求。

二、为什么选择frp

这里我用frp搭建自己的NAT服务,它有以下优点

  • 开源,维护频繁。
  • 支持 TCP、UDP、HTTP、HTTPS、STCP 等协议。
  • GoLang开发占用内存小,代理稳定。
  • 配置简单方便,自定义插件化配置以及可开发自己业务需求的插件。
  • 提供安全地暴露内网服务、加密与压缩、底层通信可选 kcp 协议、端口复用、负载均衡、健康检查、URL 路由、范围端口映射、请求的 header处理等众多功能。

另外如果使用了APPNODE运维面板,则可以通过里面的软件管理一键安装服务端。

可以在浏览器通过访问《远程IP:端口》的形式,默认端口是7500,访问frp服务的运行状态与代理统计信息。

在本地,可以通过浏览器材访问《127.0.0.1:端口》的形式,默认是7400,访问本地服务穿透状态、生效中的配置、热更新配置。

三、服务端配置

1.开放端口

首先要配置防火墙,让frp相关的端口能够通行:

  • 开放TCP端口,7000至7010端口,7000端口是 frp服务端代理通信的默认端口,7001至7010端口可代理内网服务器的TCP应用程序的端口,如果不够使用可将端口继续延长。
  • 开放TCP端口,7777与7778端口,方便进行 HTTP 与HTTPS代理,因云服务器80与443端口已经被其他应用程序占用。
  • 开放UDP端口,开放7002端口,如果有需要提供点对点内网穿透可开启。

以上端口开启不是指定,可自定义灵活配置。

2.下载frp

然后,下载各系统编译好的包。frp的GitHub releases地址是:https://github.com/fatedier/frp/releases,如果用的是64位服务器,可以下载frp_0.34.1_linux_amd64.tar.gz(版本号要更新)

3.配置frps.ini

下载完成后,解压打开文件夹,找到 frps.ini 文件进行配置服务端代理规则,frpc 开头的文件代理服务器上面不会用,在配置内网的服务器上面会用到。

frps.ini 配置基本内容如下,仅供参考:

[common]
# 设置服务器地址及通信端口
bind_addr = 0.0.0.0
bind_port = 7000

# 设置默认的UDP端口,kcp绑定的是udp端口,可以和 bind_port 一样
bind_udp_port = 7002
kcp_bind_port = 7001

# 监听7777与7778端口,进行 HTTP 与 HTTPS 代理,HTTP 与 HTTPS 端口可以成设置一样
vhost_http_port = 7777
vhost_https_port = 7778

# 设置查看仪表板服务地址及端口,dashboard_addr不设置,默认与 bind_addr一样,如果不设置 dashboard_port 端口不会开启这个服务
dashboard_addr = 0.0.0.0
dashboard_port = 7500

# 设置仪表盘服务的登录的账号与密码,如果不设置就默认都是admin,密码要改成更复杂的
dashboard_user = admin
dashboard_pwd = 123456

# 设置云服务器的域名,方便简单的配置代理出去的服务可以通过子域名的方式访问
subdomain_host = yourdomain.com

# 设置Token, 尽量配置复杂些,配置frpc会用到
token = 123456789

# 设置日志文件记录路径,最好提前建好这个文件
log_file = ./logs/frps.log
# 设置日志记录级别,分别有trace, debug, info, warn, error
log_level = info
# 设置日志记录最大天数
log_max_days = 7

KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据包的发送方式,以 callback的方式提供给 KCP。 连时钟都需要外部传递进来,内部不会有任何一次系统调用。本文传输协议之考虑UDP的情况。启用后需要在 frp 客户端中设置使用 KCP 传输才会生效。如果不太了解的话,就只使用TCP的两个端口就可以了。

4.启动frps

输入以下命令,启动frps内网穿透服务:

./frps -c ./frps.ini

四、客户端配置

1.下载frp

frp的GitHub releases地址是:https://github.com/fatedier/frp/releases,如果本地用的是64位Windows系统,可以下载frp_0.34.1_windows_amd64.zip(版本号要更新)

2.配置frpc

下载完成后,解压打开文件夹,找到 frpc.ini 文件进行配置服务端代理规则。frps开头的文件在内网的客户端机器用不上。

frpc.ini的配置如下,仅供参考:

[common]
# 云服务器的IP地址及 frps 里面设置的通信端口
server_addr = x.x.x.x
server_port = 7000

# 授权 token 与 frps 配置的一样
token = 123456789

# 设置日志文件记录路径
log_file = ./logs/frps.log
# 设置日志记录级别,分别有trace, debug, info, warn, error
log_level = info
# 设置日志记录最大天数
log_max_days = 7

# 设置可在浏览器里面配置热更新的服务
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_pwd = 123456

# tcp 范围 7001-7010

# RDP,即Remote Desktop 远程桌面,Windows的RDP默认端口是3389,协议为TCP
#[rdp]
#type = tcp
#local_ip = 127.0.0.1           
#local_port = 3389
#remote_port = 7777
#subdomain = rdp

# SMB,即Windows文件共享所使用的协议,默认端口号445,协议TCP,本条规则可实现远程文件访问。
#[smb]
#type = tcp
#local_ip = 127.0.0.1
#local_port = 445
#remote_port = 7777

# 代理本机 SSH
#[ssh]
#type = tcp
#local_ip = 127.0.0.1
#local_port = 22
#remote_port = 7777

# 设置本地端口8126 HTTP服务的代理
# 可通过frps里面配置的subdomain_host 域名
# 访问 test.yourdomain.com 加 HTTP 代理端口,即 http://test.yourdomain.com:7777
[web01]
type = http
local_ip = 127.0.0.1
local_port = 8126
subdomain = test

然后要在自己的域名DNS记录那里添加,cname记录,前缀是text,指向自己的主域名yourdomain.com,这样才可以用二级域名的方式来访问。

五、Https配置

将内网穿透的 HTTP 服务配置成 HTTPS 主要有两种方法:

  • 通过 frpc 的 https2http 插件将本地 HTTP 服务启用 HTTPS,通过这种方式比较方便简单对需要 HTTPS 的服务进行可控性的配置,但如果各个内外服务器需要 HTTPS 穿透的服务很多的话,就需要给每一个穿透服务生成并配置一个证书,这样就比较繁琐了。
  • 通过生成泛域名证书,在外网服务器上面进行配置 Nginx ,将内网穿透出来的 Web 服务进行代理转发。

第二种方式进行 HTTPS 配置比较好用,如果用APPNODE面板在添加SSL证书时,加上泛域名*.yourdomain.com即可,再更新SSL证书。

如果是在https://www.sslforfree.com/这类网站生成证书的,也可以加上泛域名,这样这个SSL证书就能对不同的二级域名生效,最后可以通过https://test.yourdomain.com:7778 加密访问内网服务。