frp内外穿透

雲文 雲文

NAT环境下,内网的机器是无法被外部访问到的。比如下面的LaptopA和B,都不能被公网的7.7.7.7访问到的。

8683f0676f35742ff1a20342afb78f5e_nat-overview-1

在路由器的帮助下,才能实现双向通讯。但是大部份情况下,家用路由器不支持将Laptop暴露给外网。

6b2c8bf57ab4e7ff93f6fb88dbc1dba7_nat-overview-2

这个时候,如果有一个服务能够直接穿透家用路由器而直接用TCP链接,把Laptop:xxxx和7.7.7.7:xxxx等效起来,那么就相当于直接把laptop暴露在公网了。

image-20230803203907612

frp则是这样的工具,能够完美的实现这个技能。在它的帮助下,能够让访问7.7.7.7:8080的时候,相当于在访问laptop:8080。

如果laptop:8080上面是个http服务的话,那么相当于在laptop:8080上面搭建了一个公网可以访问的web服务,只不过它的访问地址是7.7.7.7:8080。而frp更是直接内置了,一个静态的web服务器插件:static_file,可以直接提供静态文件的web服务。

因为laptop经常关机,所以它的应用场景只能是对可用性要求不高的环境,比如说图床,当然如果搭配公开的cloudlare这样的的CDN,那么一个月开机一次,就足够支持一般的图床应用了。

比如说可能是个基于laptop:8080的图床等等服务,再也不需要云空间的存储要求。

frp分为服务器端frps和客户端frpc,服务器端frps运行在7.7.7.7上面,客户端frpc运行在laptop上面。

这个体系中,frp不仅仅会监听对外服务的8080端口,而且自己也需要一个frp自己的端口用于服务器端frps和客户端frpc通讯,

frpc客户端与frps服务端在frp端口建立链接后,会根据客户端frpc的配制,决定如何将客户端frpc的资源暴露于7.7.7.7这个frps服务器端。所以frp服务器真正提供服务的端口,其实是由frp客户端来指定的。

安装之后,frpc和frps各有自己的ini格式的配置文件,启动命令非常相似

  • frpc -c frpc.ini #启动Laptop上面的客户端
  • frps -c frps.ini #启动7.7.7.7上面的服务器端

比如说frps.ini中,指定frps和frpc自己的通讯端口是7000.

[common]
bind_port = 7000

frpc.ini

[common]
server_addr = 7.7.7.7
server_port = 7000

[test_static_file]
type = tcp
remote_port = 8080

#这个由frp的静态服务插件来实现http静态服务,当然也可以用别的服务来实现。比如说端口转发等等。
plugin = static_file
# 要对外暴露的文件目录
plugin_local_path = C:/Documents/sites/frp_sites/pub

服务器和客户端启动之后,访问 http://7.7.7.7:8080,就可以直接访问Laptop上面 C:/Documents/sites/frp_sites/pub 里面的文件了。

比如说laptop://C:/Documents/sites/frp_sites/pub/hello.png,可以通过http://7.7.7.7:8080/hello.png来访问。

这个配制中,还是非常的原始,只可以适用于演示。

实际上上面这个配制,任何frp客户端都可以连接frps上去,这非常的不安全。所以需要在frpc和frps之间进行认证,frp支持的认证方法有token和oidc,oidc的认证略微复杂,直接使用token来设置密码最简单。

在上面的frps.ini和frpc.ini的common节中,同时加入:

authentication_method = token
token = 47866af5-cc5f-4798-a658-8a39bb61f53e

借用电影疯狂的石头的话说,7.7.7.7:7000可不是公共厕所,想来就来 :) 。

这样frpc和frps就会进行连接认证了。

进一步的,http://7.7.7.7:8080/hello.png,这样的URL实在太丑陋了,所以Nginx做反向代理,我们新建一个站点: frp.a.com 。

设置DNS,将frp.a.com指向7.7.7.7之后,

使用http://frp.a.com/hello.png,就可以非常友好的访问laptop://C:/Documents/sites/frp_sites/pub/hello.png了。

server {
    server_name frp.a.com;
    listen 80 ;
    location / {
        proxy_pass  http://7.7.7.7:8080;
    }
}

这个地方,还有点点可以改进的地方,既然http://7.7.7.7:8080/hello.png这样的网址,对外部来说已经不需要了,那么能不能换成只能Nginx内部 访问的网址,比如说 http://127.0.0.1:8080?

当然是可以的,这个时候需要在服务器端的frps.ini中配制指定:

pproxy_bind_addr = 127.0.0.1

这个设置,会让frp只监听127.0.0.1:8080,而不是服务器的*:8080。这样frp只接受乃至服务器本身的连接,外部不可访问7.7.7.7:8080了,就更加的安全了。

image-20230803211441880

如果是windows,希望把frp运行在后台服务中,而不是一个丑陋的cmd黑框框,可以使用nssm来帮助实现

更多的frp服务器端和客户端配制参见:

  1. https://gofrp.org/docs/reference/server-configures/
  2. https://gofrp.org/docs/reference/client-configures/