远程办公,调试接口,利用家里内网闲置服务器,just frp it.
⚠️ 安全考虑部分放在文末,但要先提出来
如何理解内网穿透
抛开技术细节不谈,如何理解穿透呢,大概可以这么认为:正常情况下,我们无法访问到内网的环境,但我们可以在一台公网机器上部署frps,需要被穿透的内网机器作为frpc向公网机器注册自己的网络连接信息,换言之就是,frpc启动并且向frps注册之后,frps建立并负责维持和frpc的连接,这时之前无法与内网机器建立连接的机器,就可以通过公网服务器frps来与各个内网环境建立连接,frps就像一个代理
安装
Frp不需要安装,直接下载release包,存放到合适的位置即可(对于客户端和服务端都是一样的)
解压后的目录大概应该长这样
frp 的部署架构大概是,需要一台公网可以自由访问的服务器作为 frp 的server (frps), 其他待穿透的环境,如内网服务器,作为客户端(frpc), frps 只需要关注客户端程序frpc
和 对应的配置文件 frpc.ini
,同样的服务端只需要关注 frps 和 frps.ini,这个对应关系十分简洁明了
从一些典型用例开始
我想开放内网的http服务到外网环境…
类似场景枚举
- 我有一组内网部署的静态页面(如官网)想开放到公网给客户做演示
- 我内网有一些公共基建服务,如 gitlab / confluence / jenkins 希望开放到公网以供同事在公司以外的环境使用(当然这需要公司相关的安全准许)
- 我内网部署的 api 服务,希望开放到公网以供远程调试
- …
以上的场景本质上都是http层的服务对外暴露,要达到以上目的,我们需要准备以下内容:
- 内网服务,此处我们以对外暴露内网部署的 rest-api 为例,我们假设 api 已经部署在
内网服务器
的8080端口 - 一台公网服务器,云服务器或实体机器,只要公网能访问即可
- 一个能解析到指定公网服务器的域名(或子域名 / 三级域名)
- frp package, 可以从frp官网下载,分别发送到内网服务器和公网服务器各一份
第一步,先在公网服务器配置frp服务端 (记作frps)。
先来搞定配置文件,拷贝 frps.ini 或者直接在上面改都行。默认的配置文件应该看起来是这样的
1 | [common] |
默认的配置文件只配置了frp server的运行端口,也就是启动后 frps 在远程服务器上占用7000端口运行,frpc 的注册和交互都与这个端口进行
我们还需要配置一个 vhost_http_port
用来指明,当外网通过云服务器与内网连接的时候,是通过哪个端口进行的,这里我们暂取一个5000
1 | [common] |
此时启动 frps ,并指定配置文件即可
./frps -c frps.ini
当然,这样启动的话,程序是前台启动的,会始终占据当前会话的输入输出,并且如果会话结束,这个程序也就停止了,所以一般类似的情况,我们都会用 nohup 将程序以后台的方式启动,更进一步,为了简化之后的启动过程,并且避免忘记指令的烦恼,我们可以写成一个 start.sh 脚本供一键使用
1 | nohup ./frps -c dzm_frps.ini & |
给这个赋下权并执行即可,至此 frps 服务端侧的配置就完成了,只要公网服务器一直保持运行,就没它什么事情了。
第二步,配置域名指向公网服务器
在域名提供商的后台配置一下,将域名(或子域名)指向公网服务器的ip地址,记录类型选A记录
如何验证配置成功,在Linux / Mac / win10 cmd 上有 nslookup
命令,可以查到域名的解析结果,如果 address 这栏显示的是公网服务器的地址,就表示配置成功了,这步根据域名提供商的差异,可能会有一定延迟
第三步,在部署了待穿透的api的内网服务器上配置 frp 客户端 (记作 frpc)
同样先看配置文件 frpc.ini
1 | [common] |
ssh 及以下的那部分暂时先不用关注,可以 comment out
上面 [common] 这栏表示,我们的客户端 frpc 要向这个地址和这个端口发起注册请求,这两栏分别填公网服务器公网ip地址,及第一步中配置的bind_port
,bind_port在我们这例中是 7000
然后为我们的内网 api 增加一段配置:
1 | [common] |
[api] 只是一个名字,随意起,不要与之前用过的重复即可
type 表明我们是一个 http 连接的穿透,照填即可
local_port 表明的是 api 服务在内网机器本地的端口
custom_domains 是第二步中配置的域名,根据自己的情况替换
最后使用启动frps类似的方法启动frpc即可,如果这时你去查看frps的日志(启动目录下的 nohup.out文件),你就会看到有客户端发起连接的提示
这时,访问 api.yourdomain.com:5000
就等于访问了内网的8080
至此,需求已经满足。
这中间发生了什么呢,大概就是,我访问api.yourdomain.com:8080
, DNS 把域名和端口解析成 ip+port 即 x.x.x.x:8080, 这时frps 接到请求,然后顺便检查域名,将域名匹配到注册了这个域名的 frpc,并与之建立连接,这时请求就顺着注册记录来到了内网,内网将这个请求发送到8080进行处理
整体路径:
(公网环境) api.yourdomain.com:5000 👉 x.x.x.x:5000 (DNS) 👉 frps(通过某种连接技术维持和内网的连接并负责路由) 👉 frpc 👉 127.0.0.1:8080 (内网环境)
如果我还有另一个服务在内网 9090 (如confluence)也想开放到公网 …
在内网机器的frpc配置上增加一段,并为其准备一个新的域名(子域名)即可:
1 | [common] |
保存,重启 frpc 后,自动向frps重新注册,frps全程不需要动
我想从外网ssh连接到内网服务器…
TBC. 之后再介绍
关于安全问题
frp 在我看来是一种临时或对一些不是十分重要的网络服务
的穿透方案,如给客户做演示,临时开放内网接口等场景,出于安全考虑,最好能用完即关闭,以护内网环境周全;企业级网络环境划分,重要网络位置的对外暴露,请参考其他更加安全和周密的VPN产品或网络解决方案
对于 frp 穿透的服务
- 不重要的服务,或作为大众演示目的的服务,可以直接开放
- 具备一定信息敏感性的服务,请使用frp提供的鉴权加护后开放
- 高权限高影响的服务,请考虑不要使用frp穿透开放
- 请保证公网机器的环境安全,瓮城不保,内城难安
- 请根据情况在企业安全人员的许可下操作
◉ End.
参考资料:
如博文有叙述不妥以及不准确的地方, 望各位看客不吝赐教, 感谢.