张火火和西西弗一起推石头

以执念对抗不完美

基于frp的内网穿透搭建指南

目录

一、前言介绍

二、正文

        1、准备事项

        2、服务端配置

        3、客户端配置

        a、Windows端配置

        b、Linux端配置

        c、p2p配置

三、总结


一、前言介绍

        由于全球ipv4地址资源的紧张,大多数中国用户并不能得到一个ipv4的地址(电信一个静态的ipv4地址一年大概要30k+¥),而博主身为一个穷学生便更不可能拥有。因为在家中搭建了一台文件服务器,但是在学校并不能访问,很是苦恼;因为在寝室购置了一台PC,但是因为长时间出没在教室、图书馆等场所并不能使用到寝室的PC,而笔记本的性能并不能满足所有的需求。为了解决当下的问题,满足当前的需求,内网穿透这一方法进入了视野。

        目前市场上能够实现内网穿透的产品十分之多,例如花生壳、Team viewer等。不过他们都有一些共同特点,或是价格昂贵,或是速度奇慢,或是安全堪忧,并不适合个人用户。所以,frp成为了极佳的一个选项。这是在GitHub上开源的一个项目,有众多的用户一同监督维护,现在已经比较成熟了。更值得一提的是,市面上很多内网穿透的工具其实都是对frp的一个装封。这里贴上frp的仓库地址:fatedier/frp: A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet. (github.com)

二、正文

        1、准备事项

        由于内网穿透的实现需要一台云服务器来对不同内网的两台客户端进行通信对接(包括创建p2p连接前的udp握手请求),所以需要先准备一台云服务器。我这里准备的是一台阿里云最低配的VPS,配置规格为:1核,2GiB,1Mbps。安装的是CentOS7.9 。

        前往frp的仓库,下载对应的release:Releases·download (github.com)

        我在VPS上选择的是linux 64位0.42.0版本:linux 64位0.42.0。由于git配置较为麻烦,所以这里提供一个新的方法:使用MobaXterm将压缩包上传至VPS。

        2、服务端配置

        默认当前正于压缩包处在同一目录下,使用的是linux 64位0.42.0版本 。

        依次输入以下命令:



1.  mkdir /opt/frp    #在opt目录下创建frp目录
    
2.  mv frp_0.42.0_linux_amd64.tar.gz /opt/frp    #将压缩包移动到frp目录中
    
3.  cd /opt/frp    #移动到frp目录下
    
4.  tar -zxvf frp_0.42.0_linux_amd64.tar.gz    #解压
    
5.  #如果解压报二进制文件错误,基本就是下错版本,重新下载操作系统对应的版本
    
6.  cd frp_0.42.0_linux_amd64.tar    #进入目录
    
7.  ll    #查看当前目录中的所有文件
    
8.  rm -r 文件名    #将所有frpc开头的文件都删除,这是客户端的文件,不需要
    
9.  vi frps.ini    #配置frp服务端
    

         此处的服务端配置及下文的客户端配置都以实现远程桌面连接和SSH连接这一功能为例。

        服务端配置:



1.  [common]
    
2.  bind_port = 7000
    
3.  bind_udp_port = 7001
    
4.  auto_token = 123456
    

6.  dashboard_port = 7500
    
7.  dashboard_user = admin
    
8.  dashboard_pwd = admin
    

        配置讲解:



1.  [common]
    
2.  bind_port = 7000    #绑定的端口,frp将会监听7000的端口
    
3.  bind_udp_port = 7001    #绑定的udp端口,frp将会在7001监听udp请求
    
4.  auto_token = 123456    #类似密码,只有客户端与服务端token相同时才会连接
    
5.  #以下为frp监控板的配置
    
6.  dashboard_port = 7500    #绑定监控板的访问端口
    
7.  dashboard_user = admin    #设置用户名
    
8.  dashboard_pwd = admin    #设置用户密码
    

        开放防火墙端口:



1.  firewall-cmd --zone=public --add-port=7000/tcp --permanent    #开放7000端口,其他端口也依次开放
    
2.  firewall-cmd --reload    #重新加载防火墙
    
3.  firewall-cmd --list-all    #查看防火墙信息,检查所需端口是否开放
    

./frps -c ./frps.ini    #运行frps

  

 当出现图示信息时说明frp服务端成功运行

        接下来开始配置开机自启动。

vi /lib/systemd/system/frps.service    #创建并编辑frps.service服务文件

         填入以下配置:



1.  [Unit]
    
2.  Description=frps service
    
3.  After=network.target syslog.target
    
4.  Wants=network.target
    
5.  [Service]
    
6.  TimeoutStartSec=30
    
7.  ExecStart='ADDRESS'/frps -c 'ADDRESS'/frps.ini    #注意'ADDRESS'处填frp的目录地址,如本文中应为:/opt/frp/frp_0.42.0_linux_amd64
    
8.  ExecStop=/bin/kill $MAINPID
    
9.  [Install]
    
10. WantedBy=multi-user.target
    

        写入服务后需要进行一遍重载:

systemctl daemon-reload

        基本操作命令:



1.  systemctl start frps    #启动frps
    
2.  systemctl stop frps    #停止frps
    
3.  systemctl status frps    #查看frps运行状态
    
4.  systemctl enable frps    #设置frps开机自启动
    
5.  systemctl disable frps    #取消frps开机自启动
    

        至此,服务端配置完成。

        可以通过访问:公网ip:7500 来访问frp服务端监视板。7500为先前dashboard绑定的端口号。

        3、客户端配置

        a、Windows端配置

        下载windows端的frp:Windows_arm_64_0.42.0

        解压文件夹。删除所有frps开头的文件,这是服务端的文件。

        打开frpc.ini,填入:

`   1.  [common]      2.  server_addr = xxx.xxx.xx.xxx      3.  server_port = 7000      4.  auto_token = 123456       6.  [stcp_rdp]      7.  type = stcp      8.  sk = 123456      9.  bind_addr = 127.0.0.1      10. bind_port = 3389      11. use_encryption = false      12. use_compression = false       14. [stcp_ssh]      15. type = stcp      16. sk = 123456      17. bind_addr = 127.0.0.1      18. bind_port = 22      19. use_encryption = false      20. use_compression = false        `

![](https://img2023.cnblogs.com/blog/3078251/202407/3078251-20240704221329170-1448678963.png)

         此处的是被访问客户端A的配置,详细讲解如下:

`   1.  [common]      2.  server_addr = xxx.xxx.xx.xxx    #你的VPS公网ip      3.  server_port = 7000    #VPS绑定的端口号      4.  auto_token = 123456    #VPS中设置的token值       6.  [stcp_rdp]    #服务名称      7.  type = stcp    #数据传输类型      8.  sk = 123456    #被访问端和访问端需要有相同的sk值,类似密码      9.  bind_addr = 127.0.0.1    #绑定ip,此处127.0.0.1返回的是本机的ip地址      10. bind_port = 3389    #绑定本地端口,远程桌面默认端口为3389      11. use_encryption = false    #关闭数据加密,你也可以开启      12. use_compression = false    #关闭压缩数据,可开启       14. [stcp_ssh]      15. type = stcp      16. sk = 123456      17. bind_addr = 127.0.0.1      18. bind_port = 22      19. use_encryption = false      20. use_compression = false        `

![](https://img2023.cnblogs.com/blog/3078251/202407/3078251-20240704221329170-1448678963.png)

        同上,配置访问端客户端B:

`   1.  [common]      2.  server_addr = xxx.xxx.xx.xxx      3.  server_port = 7000      4.  auto_token = 123456       6.  [stcp_rdp_visitor]      7.  role = visitor      8.  type = stcp      9.  server_name = stcp_rdp      10. sk = 123456      11. bind_addr = 127.0.0.1      12. bind_port = 7600      13. use_encryption = false      14. use_compression = false       16. [stcp_ssh_visitor]      17. role = visitor      18. type = xtcp      19. server_name = stcp_ssh      20. sk = 123456      21. bind_addr = 127.0.0.1      22. bind_port = 57600      23. use_encryption = false      24. use_compression = false        `

![](https://img2023.cnblogs.com/blog/3078251/202407/3078251-20240704221329170-1448678963.png)

        详细解释:

`   1.  [common]      2.  server_addr = xxx.xxx.xx.xxx      3.  server_port = 7000      4.  auto_token = 123456       6.  [stcp_rdp_visitor]      7.  role = visitor    #角色,访问者      8.  type = stcp      9.  server_name = stcp_rdp    #服务端名称      10. sk = 123456      11. bind_addr = 127.0.0.1      12. bind_port = 7600    #使用本地7600端口来访问远程端口      13. use_encryption = false      14. use_compression = false       16. [stcp_ssh_visitor]      17. role = visitor      18. type = xtcp      19. server_name = stcp_ssh      20. sk = 123456      21. bind_addr = 127.0.0.1      22. bind_port = 57600      23. use_encryption = false      24. use_compression = false        `

![](https://img2023.cnblogs.com/blog/3078251/202407/3078251-20240704221329170-1448678963.png)

        两方客户端进入cmd,进入解压后的文件夹。输入

frpc -c frpc.ini    #启动frp客户端

        你可以进入frp的监视板查看连接的客户端数量。

        通过cmd来启动过于繁琐,所以可以写一个启动脚本来快速启动。

        创建一个txt文件,填入:



1.  Set ws = CreateObject("Wscript.Shell") 
    
2.  ws.run "cmd /c 'ADDRESS'\frpc -c 'ADDRESS'\frpc.ini",vbhide
    
3.  #'ADDRESS'为frp文件夹的路径
    

        保存后将文件拓展名改为.vbs,双击即可运行。若要结束运行,可以通过任务管理器来结束进程。

        连接远程桌面:绑定的ip地址:绑定的端口号

         ssh连接同理。

        b、Linux端配置

        与linux服务端配置相同,不过删除的是frps开头的文件。

        配置frpc.ini与在windows下的配置相同,此处略。

        开机自启服务配置:



1.  [Unit]
    
2.  Description=frpc service
    
3.  After=network.target syslog.target
    
4.  Wants=network.target
    
5.  [Service]
    
6.  TimeoutStartSec=30
    
7.  ExecStart='ADDRESS'/frpc -c 'ADDRESS'/frpc.ini    #注意'ADDRESS'处填frp的目录地址,如本文中应为:/opt/frp/frp_0.42.0_linux_amd64
    
8.  ExecStop=/bin/kill $MAINPID
    
9.  [Install]
    
10. WantedBy=multi-user.target
    

         其余操作与在服务端上相同。

        以上使用的都是加密tcp模式stcp,所有的流量都是流经VPS,像我1Mbps的VPS无法完成流畅的远程桌面访问或是快速地下载远程文件服务器的文件。于是p2p成为了刚需。

        c、p2p配置

        当前frp的最新版本为0.42.0,支持p2p打洞连接,即使用xtcp模式。但是这个模式并不完善,很多NAT类型并不能穿透成功。

        NAT类型一览:

        Full Cone NAT(完全锥型NAT)

 

所有从同一个私网IP地址和端口(IP1:Port1)发送过来的请求都会被映射成同一个公网IP地址和端口(IP:Port)。并且,任何外部主机通过向映射的公网IP地址和端口发送报文,都可以实现和内部主机进行通信。这是一种比较宽松的策略,只要建立了私网IP地址和端口与公网IP地址和端口的映射关系,所有的Internet上的主机都可以访问该NAT之后的主机。

        Restricted Cone NAT(限制锥型NAT)

 

所有从同一个私网IP地址和端口(IP1:Port1)发送过来的请求都会被映射成同一个公网IP和端口号(IP:Port)。与完全锥型NAT不同的是,当且仅当内部主机之前已经向公网主机发送过报文,此时公网主机才能向私网主机发送报文。

        Port Restricted Cone NAT(端口限制锥型NAT)

 

与限制锥型NAT很相似,只不过它包括端口号。也就是说,一台公网主机(IP2:Port2)想给私网主机发送报文,必须是这台私网主机先前已经给这个IP地址和端口发送过报文。

        Symmetric NAT(对称NAT)

        所有从同一个私网IP地址和端口发送到一个特定的目的IP地址和端口的请求,都会被映射到同一个IP地址和端口。如果同一台主机使用相同的源地址和端口号发送报文,但是发往不同的目的地,NAT将会使用不同的映射。此外,只有收到数据的公网主机才可以反过来向私网主机发送报文。这和端口限制锥型NAT不同,端口限制锥型NAT是所有请求映射到相同的公网IP地址和端口,而对称NAT是不同的请求有不同的映射。

        完全锥型NAT是最好穿透的,对称NAT是最难穿透的。正常情况下对称NAT是无法被穿透的。

        这里贴一个NAT检测的程序,大家可以先自行检测一下自己网络的NAT类型:NAT类型检测

        frp客户端的p2p配置如下(以远程桌面配置为例):

        (被访问端 :



1.  [p2p_rdp]
    
2.  type = xtcp    #frp中的p2p模式是xtcp,其余与stcp基本相似
    
3.  sk = 123456
    
4.  local_ip = 127.0.0.1
    
5.  local_port = 3389
    
6.  use_encryption = false
    
7.  use_compression = false
    

        (访问端:



1.  [p2p_rdp_visitor]
    
2.  role = visitor
    
3.  type = xtcp
    
4.  server_name = p2p_rdp
    
5.  sk = 123456
    
6.  bind_addr = 127.0.0.1
    
7.  bind_port = 57600
    
8.  use_encryption = false
    
9.  use_compression = false
    

        在我尝试之后发现,使用笔记本电脑连接手机热点时,电脑的NAT类型是对称式NAT;寝室的电脑处在校园网下,检测结果是端口限制锥型NAT。经过测试,并不能成功穿透。寝室电脑与家中文件服务器的网络都是端口限制锥型NAT,经过测试,也不能成功穿透。在校园环境下使用frp进行p2p网络穿透以失败告终。

        在GitHub上frp的issues里面查找了一下关于p2p的穿透问题,发现很多人都有着相同的问题,但是作者说现在的p2p模式并不完善,现在没有太多精力进一步改善,可能会在日后的开发中发现问题并改善(其实就是懒...)。不过还是发现许多人成功穿透的经历,总结了一下,基本要具备以下条件才能穿透:

        i、一边是公网IP。

        ii、一边是完全锥型NAT(另一边即使是对称NAT也可以成功穿透)。

        iii、端口限制锥型NAT需要将UDP握手的端口5000:65535通过路由转发至指定的电脑IP。

        其他详细分析可以自行去issues里查看:Issues · fatedier/frp (github.com)

        因为进行p2p穿透的时候,发出的UDP握手包容易被运营商Qos掉,所以基于UDP进行p2p穿透的frp稳定性并不高。基于TCP进行p2p穿透成功率就会提升很多,博主现在已经找到一个项目可以实现TCP下的p2p内网穿透,详细的介绍可以等我下一篇的博客噢。

三、总结

         基于frp的内网穿透搭建整体比较简单,只要掌握基本的linux系统操作、基本的网络知识便可以实现。比较推荐stcp这一类模式,不像tcp模式,直接将内网端口暴露到公网,大大增加了安全隐患,同时也会占用VPS的端口。frp还有许多模式可以进行配置,比如http等,具体可以看它的说明文档:frp/README.md。另外,下载release里面的frps_full.ini, frpc_full.ini 这类文件中包含的是全部的配置案例,注释是英文的,有兴趣可以去看一下。

        因为frp是基于UDP的p2p穿透,所以成功率并不高,只能使用像加密TCP等方式来远程访问,但这有个明显的弊端,即所有流量都要流经VPS。如本文开头可知,我的VPS仅有1Mpbs带宽,这种小水管完全满足不了流畅访问的需求。现在面临两种选择,一种选择等待frp的进一步更新p2p模式,增加对更多NAT类型的穿透,另一种便是选择其他的p2p穿透工具,比如基于TCP的p2p穿透。关于基于TCP的p2p穿透可以等我下一篇的博客。

        总体而言,frp创建的连接比较稳定,由于其开源透明的特点,安全性也可以得到保障,不失为极佳的内网穿透的选择。

        感谢各位的阅读!

posted @ 2024-07-04 22:13  zbyisgudi  阅读(3003)  评论(0编辑  收藏  举报