告别本地开发环境!Java程序员使用FRP实现远程开发环境搭建
# 写在文章开头
个人闲置了一台6核16GB的笔记本,结合内置的Linux子系统,所以打算基于内网穿透技术打造一台高性能的个人服务器。
本文将从网络通信的角度分析内外网通信的工作原理,并基于一台2核2GB云服务器实现内网笔记本Linux子系统的网络连接,构建一个高性价比的个人服务器解决方案。
我是 SharkChili ,Java 开发者,Java Guide 开源项目维护者。欢迎关注我的公众号:写代码的SharkChili,也欢迎您了解我的开源项目 mini-redis:https://github.com/shark-ctrl/mini-redis。
为方便与读者交流,现已创建读者群。关注上方公众号获取我的联系方式,添加时备注加群即可加入。
# 内外网络转发原理
# nat的科普介绍
学过计算机网络基础的同学应该都知道,公网IPv4地址是非常稀缺的资源,所以现在主流的互联网都采用NAT(Network Address Translation)即网络地址转换技术。NAT的工作原理是通过一台路由器将内网私有IP地址转换为公网IP地址,让内网机器和外网服务器进行通信。
常见的NAT技术有两种:
- 静态NAT
- NAPT技术
我们先来说说静态NAT技术,即固定配置好的一对一静态IP映射,当内网IP需要和外网进行通信时,将内网IP地址(一般为192.168.x.x、10.x.x.x、172.16-31.x.x网段)转换为公网IP,将网络报文转发到公网目标主机上。
如下图,假设现在内网有一台172.20.54.50的主机,需要访问外部101开头的网络,其报文转发过程为:
- 指定源IP为内网172开头的地址,目标IP为101开头的外网地址
- 报文转发至路由器,路由器通过静态NAT映射将报文源地址转换为路由器外网地址1.1.1.1
- 将源地址转换后的报文通过外部网关转发到目标主机上
同理,目标主机收到报文回复后,也会发送一个源地址为101开头的公网IP,目标地址为1.1.1.1的报文,由路由器根据映射配置将目标地址转换为内网172地址,再转发给目标内网主机

另一种是NAPT(Network Address Port Translation)即网络地址端口转换技术,NAPT技术通过转换IP地址和端口号,使多个内网主机共享一个公网IP地址。
例如我们现在有两台内网机器,其IP分别是172.10.1.1和172.10.1.2,此时两台主机都需要和外部服务器进行通信,路由器就会利用NAPT技术将源端口和源IP转换为公网的IP和端口与外部通信,同时还会建立一张转换表项维护映射信息。
例如现在内网的机器172.20.10.1要和外部1.1.1.1的服务器进行通信,对应的执行过程为:
- 将172.20.10.1报文对应的源IP和端口转换为公网IP和端口1.1.1.1:5096
- 路由器将这个映射关系存储到转换表中
- 公网1.1.1.1服务器收到这个报文并回复
- 公网路由器收到响应,根据转换表将目标地址和端口转换为内网地址和端口
- 内网主机收到回复报文

# 内网穿透的工作机制
NAT使得内网的机器可以通过地址映射转换的方式让内网机器和外网服务端建立通信,但外网的机器如果想访问内部网络服务器要如何做到呢?答案就是内网穿透技术。
内网穿透技术有多种实现方式:
- UDP打洞
- 反向代理(本文的FRP就是基于这种工作机制)
- 中继服务器
- STUN/TURN/ICE协议
这里我们重点说一下反向代理,该技术通过内网服务器主动和公网服务器建立连接构成一条通道,确保公网请求能够通过公网代理服务器转发到内网机器上。
以本文运用的FRP来说,假设我们希望内网SSH协议22端口映射到公网的5022端口上,其工作流程为:
- 客户端基于frpc(FRP client)配置客户端端口映射
- 服务端基于frps(FRP server)完成服务端配置并启动,监听7000端口(默认监听端口号为7000)
- 客户端主动和frps建立连接,双方完成协定的端口映射,公网服务器建立5022端口监听外部SSH请求
- 收到SSH客户端连接请求,frps将请求发送给frpc
- frpc转发给内网SSH服务
- 响应报文按照相反路径返回

# 内网穿透服务架构说明
有了上述网络基础知识的铺垫,此时我们就可以基于一台云服务器即可让外部访问我们的内网机器,在此之前请读者明确如下条件是否准备充分:
- 一台Windows笔记本,且内置了Ubuntu系统(如果用虚拟机桥接Linux系统也行)
- 一台云服务器(笔者用2核2GB的服务器)
- Linux子系统已配置SSH服务和MySQL服务(MySQL可选,本文也会做相应的配置演示)
内网穿透技术有很多种,这里笔者选用的是一款叫FRP的工具,它是采用Go语言编写的内网穿透工具,支持TCP、UDP等常见网络通信协议,部署也非常方便。
本次案例利用FRP打通内网服务器和云服务器的隧道,并将内网的SSH服务和MySQL通过5022和8306端口发布到公网进行访问:

# 个人服务器配置
# frp安装与配置
基于上述的架构说明,我们开始本次的配置,首先访问frp的github地址下载安装包,访问地址为:https://github.com/fatedier/frp/releases
以笔者的服务器为例,对应的下载版本为0.64.0,完成下载后将其上传至云服务器:

完成解压并重命名为frp方便后续操作:
# 解压程序包
tar -zxvf frp_0.64.0_linux_amd64.tar.gz
# 重命名文件夹
mv frp_0.64.0_linux_amd64 frp
2
3
4
进入frp文件夹执行vim frps.toml编辑服务器配置文件,配置内容也比较简单绑定7000端口监听frp客户端的连接请求即可:
bindPort = 7000
完成配置后,我们可以通过前台启动方式查看是否正常启动,若输出没有任何报错,则执行下一步systemd配置:
./frps -c ./frps.toml
# 后台systemd启动
因为frps是要长期运行的,为避免关闭SSH会话后进程被杀死,这里我们需要配置将其配置为systemd的方式启动并设置为开机自启,在此之前请确认您的服务器是否已安装systemd,若没有安装则执行如下指令:
# 使用 yum 安装 systemd(CentOS/RHEL)
yum install systemd
# 使用 apt 安装 systemd(Debian/Ubuntu)
apt install systemd
2
3
4
5
6
执行sudo vim /etc/systemd/system/frps.service配置frps服务,对应配置模板如下,一般情况下,读者只需要将ExecStart下的frps路径和toml配置文件路径即可:
[Unit]
# 服务名称,可自定义
Description = frp server
After = network.target syslog.target
Wants = network.target
[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /path/to/frps -c /path/to/frps.toml
[Install]
WantedBy = multi-user.target
2
3
4
5
6
7
8
9
10
11
12
13
14
完成后我们就可以通过以下指令管理frps:
# 启动frp
sudo systemctl start frps
# 停止frp
sudo systemctl stop frps
# 重启frp
sudo systemctl restart frps
# 查看frp状态
sudo systemctl status frps
2
3
4
5
6
7
8
9
最后我们配置一下开机自启即可:
sudo systemctl enable frps
# 开放监听端口
因为我们frps服务端是通过监听7000端口和frpc客户端建立连接,默认情况下云服务器是没有开放该端口的,所以在进行客户端配置前,我们需要到控制台修改网络安全组入方向的配置开放一下7000端口:

# 内网笔记本安装与配置
# 端口映射配置
因为笔者需要将Windows内部的Linux子系统Ubuntu开放,所以一切配置工作都会在Ubuntu中进行,首先还是下载FRP程序包,步骤和服务端配置类似,这里就不多赘述了,这里着重说明一下客户端文件frpc.toml的配置:
- serverAddr:设置为云服务器的ip
- serverPort:也就是我们上文设置的监听端口
- 每个[[proxies]]配置代表配置一条端口对应,对应笔者的配置分别代表将ssh服务即22端口映射到云服务器的5022,对应mysql的3306端口映射到8306端口
serverAddr = " x.x.x.x"
serverPort = 7000
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 5022
[[proxies]]
name = "mysql"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3306
remotePort = 8306
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 开放端口与连通性测试
完成客户端配置后,读者需要再次回到云服务器将5022和8306端口开放以方便验证连通性,同时为了方便,建议读者可直接将Windows主机的防火墙关闭或者开放22和3306端口,让frps服务端可以和映射端口建立连接。
在完成上述的配置步骤后,通过下面这段脚本将frpc客户端启动,此时就可以测试ssh和mysql的连通性了:
./frpc -c frpc.toml
2
# systemd启动
完成这些配置后也可以参考服务端配置方式将其设置为systemd启动,通过sudo vim /etc/systemd/system/frpc.service编辑配置文件,将启动frpc命令改为启动客户端的命令即可:
[Unit]
# 服务名称,可自定义
Description = frp client
After = network.target syslog.target
Wants = network.target
[Service]
Type = simple
# 启动frpc的命令,需修改为您的frpc的安装路径
ExecStart = /home/sharkchili/frp/frpc -c /home/sharkchili/frp/frpc.toml
[Install]
WantedBy = multi-user.target
2
3
4
5
6
7
8
9
10
11
12
13
完成后我们执行如下指令完成frpc启动和开机自启:
sudo systemctl start frpc
sudo systemctl enable frpc
2
# Windows盒盖不关机配置
到此我们的笔者本已经可以作为服务器使用了,为了让其长期运行我们需要将其设置为盒盖不关机的,关于windows的电源设置,读者可以参考这篇文章:https://zhuanlan.zhihu.com/p/613581298
# 关闭win10自动更新
同理windows还有一个自动更新的小毛病,读者也可以参考这篇文章关闭自动更新,让服务器稳定长期运行:https://zhuanlan.zhihu.com/p/391195241
# 小结
本文深入介绍了内外网主机的通信原理和内网穿透技术,同时也详细演示了如何基于FRP让内网机器主动和公网服务器建立一条安全通道,让外部机器可以通过公网服务器访问内网服务。需要补充的是,通过这种方式就会使得我们的内网服务器在公网暴露,所以读者们一定要谨慎设置好SSH和MySQL的密码,并配置FRP的安全认证机制,避免安全问题。
我是 SharkChili ,Java 开发者,Java Guide 开源项目维护者。欢迎关注我的公众号:写代码的SharkChili,也欢迎您了解我的开源项目 mini-redis:https://github.com/shark-ctrl/mini-redis。
为方便与读者交流,现已创建读者群。关注上方公众号获取我的联系方式,添加时备注加群即可加入。
# 参考
WIN10系统如何彻底永久关闭自动更新?建议收藏!:https://zhuanlan.zhihu.com/p/391195241 (opens new window)
内网穿透:打破网络限制的利器,内外网概念、穿透原理、实际操作方法步骤:https://jishuzhan.net/article/1948556687765450753 (opens new window)
frp内网穿透原理及配置记录:https://blog.engine.wang/posts/frp-notes/ (opens new window)
十分钟教你配置frp实现内网穿透:https://blog.csdn.net/u013144287/article/details/78589643 (opens new window)
内网穿透原理总结与工具推荐:https://juejin.cn/post/6844904169497690120 (opens new window)
- 02
- 深入Redis SCAN源码:反向迭代算法的设计与实现06-01
- 03
- Go语言常见面试题解析(上)语言基础与核心概念05-20