故事背景:我有一台云服务器,一台公司内网服务器,因为公司没有公网ip,但是又有公网访问的需求,所以打算通过frp进行内网映射。
frp是采用CS架构,即client-server,也就说需要一个固定的公网ip去转发服务作为frp的服务端,虽然每个宽带都是有一个ip的,但是这个ip是不固定的,除非运营商明确告诉你这是固定ip;然后被转发的服务器上需要一个frp客户端去接收和响应来自frp服务端的请求。 frp的github项目开源地址:github.com/fatedier/fr… 百度云下载地址:pan.baidu.com/s/1ZEaH9uJY… 提取码:ryg4
我是通过云服务器的公网固定ip作为frp的服务端,公司内网服务器作为客户端进行穿透。简单的描述一下过程:内网服务器部署一个服务,然后通过frp将内服务器的服务和端口映射到公网的端口上,从而实现访问云服务器公网的ip+端口,进而访问到内网服务器,这里的云服务器做一个转发的功能。 示意图如下:
开始实操:
下载frp
打开github页面,找到frp_0.59.0_linux_amd64.tarz(有新版本为什么不用?因为用这个之后的版本,报了一个客户端配置文件remoteport的错误,不知道怎么解决,有知道的大佬请指点我一下~)
你是什么平台的就用哪个,里面都有一个客户端和服务端
下载下来以后解压会得到以下文件:
- frps前缀的是服务端文件,frps.exe是执行文件,frps.toml是配置文件,以此类推frpc前缀就是客户端文件。主机作为哪个端就只需要哪个端的文件,别的可以删除,不删也可以。
- LICENSE不用管
部署服务端
登录自己的云服务器之后,为这些文件创建目录,我的目录是/www/wwwroot/frp/frp_0.59.0_linux_amd64,自己的目录可以随便放到哪个地方取什么名字,只要在下面配置文件的时候,把我的目录替换成自己的目录即可。
frp配置文件说明官方文档:gofrp.org/zh-cn/docs/…
- frp服务端配置文件frps.toml(#号后面代表注释)
# frp服务需要绑定使用的端口
bindPort = 7100
# 0.0.0.0 代表监听当前ip
bindAddr = "0.0.0.0"
# 服务端监听 KCP 协议端口,用于接收配置了使用 KCP 协议的 frpc 连接。
kcpBindPort = 7100
# webSever是frp的web服务,可以监控一些连接的情况,不要这个也不会影响使用
# 0.0.0.0 代表监听当前ip
webServer.addr = "0.0.0.0"
# web服务绑定使用的端口
webServer.port = 7500
# web的登录账号
webServer.user = "username"
# web的登录密码
webServer.password = "password"
# 日志记录位置,这里是linux系统的路径,Windows的路径有所不同,不了解的百度或者gpt
log.to = "/www/wwwroot/frp/frps.log"
# 日志记录等级
log.level = "info"
# 日志记录最大天数
log.maxDays = 3
# 允许通过的端口,即访问公网ip的哪些端口会转发到客户端,只有客户端指定了的端口才会被使用
allowPorts = [
# 给定一个允许访问的端口范围,即访问6000~7000都是会被服务端监听的
{start = 6000, end=7000}
# 或者可以指定一个端口
# {simple:6001}
]
- 启动服务
在配置了配置文件以后其实已经可以启动服务了,在frp目录下执行
frps -c frps.toml
但是如果关闭了终端窗口,这个服务就停止了,所以我们需要一种方式来帮我们自启动并且可以后台执行这个服务。官方提供的方法是采用linux系统的systemd服务,这边也是采用同样的方式。 新建一个服务文件: vim /etc/systemd/system/frps.service 编辑内容
[Unit]
# 服务描述
Description = frp.server
# 指定该服务在网络服务和系统日志服务启动之后启动。
After = network.target syslog.target
# 表示该服务弱依赖于网络服务目标,即使网络服务启动失败,这个服务也会尝试启动。
Wants = network.target
[Service]
- `ExecStart = /www/wwwroot/frp/frp_0.59.0_linux_amd64/frpc -c /www/wwwroot/frp/frp_0.59.0_linux_amd64/frps.toml`:
- `ExecStop = /bin/kill $MAINPID`:
- `Restart = always`:
# 服务类型为简单类型,意味着启动后立即进入运行状态,没有复杂的启动过程。
Type = simple
# 指定服务启动时执行的命令,即启动 frp 客户端程序`frpc`并指定配置文件路径为`/www/wwwroot/frp/frp_0.59.0_linux_amd64/frps.toml`。
这里的目录需要更改为你自己服务器frp文件实际所在的目录
ExecStart = /www/wwwroot/frp/frp_0.59.0_linux_amd64/frps -c /www/wwwroot/frp/frp_0.59.0_linux_amd64/frps.toml
# 当服务停止时,使用`kill`命令终止主进程。
ExecStop = /bin/kill $MAINPID
# 表示服务在退出、异常或被系统终止时总是自动重启。
Restart = always
[Install]
# 表示这个服务被多用户系统目标所需要,当系统启动到多用户模式时,会自动启动这个服务。
WantedBy = multi-user.target
保存以后进行刷新
- systemctl daemon-reload 刷新配置
- systemctl start frps 启动服务
- systemctl status frps 查看服务状态
当服务显示active(running)的时候说明服务已经成功启动了,此时可以通过访问公网ip+frp的web服务端口(即7500端口)查看监控信息
在用户名和密码那里输入你在frps.toml中填写的webServer.user 和webServer.password
看到这个页面说明已经成功部署好服务端
部署客户端
同样的,不管是Windows还是linux,在一个你自己想要的地方创建文件夹,把frpc文件和frpc.toml文件放到该目录下,区别是Windows和linux所使用的文件不同,也就是你从github下载的文件要对应上。
我这里写了一个简单的node服务用来做测试,它开放一个3000端口,当你访问它时,它返回一些文字信息。这里我也给出源文件,但是不了解的同学想要运行这个服务,可以用抖音的豆包助手,他也是一个ai助手,你可以提问他该如何启动一个node项目,照着做就可以了。 这个项目是一个文件夹,里面有一个app.js文件和一个package.json文件
const express = require('express');
const os = require('os');
const app = express();
app.get('/', (req, res) => {
console.log("someone request")
res.send('you are in the home page')
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
{
"name": "demo",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^4.21.0"
}
}
在这个目录下执行,npm install以及node app.js就可以看到项目启动了,它会在控制台首先打印 Server running on port 3000 当有人请求这个接口时,它会在控制台打印someone request
如果你在浏览器访问这个接口,会显示
frp客户端配置文件
# 你的云服务器公网ip
serverAddr = "127.1.2.7"
# 你的frp服务端绑定使用端口
serverPort = 7100
# 如果登录到服务端失败,客户端将退出。这可以确保在无法连接到服务端时,客户端不会继续运行而产生错误或不可预测的行为。
loginFailExit = true
# 日志配置,同服务端
log.to = "./frpc.log"
log.level = "info"
log.maxDays = 3
# 代理规则,如果需要多个代理,直接复制然后修改其中的内容即可
[[proxies]]
# 代理名称
name = "test-tcp"
# 代理类型,有tcp、udp、http、https等等,详见官方文档
type = "tcp"
# 客户端的ip
localIP = "127.0.0.1"
# 客户端服务监听的端口,因为我的node服务绑定了3000端口,所以这里填一样的
localPort = 3000
# 远程端口,就是你访问公网ip+远程端口,它就会转发到客户端的服务
remotePort = 6100
启动frp客户端服务
与启动frp服务端服务同理,可以采用systemd的方式,也可以直接启动:frpc -c frpc.toml systemd的作用就是在服务崩溃的时候自动重启,直接启动的话,服务崩了就需要手动重启
开放防火墙
当你完成了以上所有步骤时,记得开放对应的防火墙。 frp服务端占用7100和7500端口,那么服务端对应的云服务器就需要先开放7100端口和7500端口。因为frp客户端中把远程端口绑定到了6100,所以云服务器还需要开放6100端口,这样才能接收到请求并进行转发。
frp客户端占用了3000端口,所以也要开放3000端口才能接收请求和响应。
至此,你已完成了穿透的所有步骤。可以通过公网ip+6100端口访问到内网服务器的服务了。 例如公网ip是127.1.2.7,那么你只需要访问http://127.1.2.7/6100 就可以收到内网服务的响应了
如果你是前端项目,可以用nginx进行反向代理,你把项目通过nginx代理到哪个端口,同样的也可以通过frp穿透到该端口实现访问。 例如你把vue项目通过nginx代理到8080端口,那么你在frpc.toml的配置中:
[[proxies]]
name = "test-tcp"
type = "tcp"
localIP = "127.0.0.1"
# 改为和nginx代理端口一样
localPort = 8080
remotePort = 6100
假设公网ip是127.1.2.7,那么你只需要访问http://127.1.2.7/6100, 就可以访问到你的vue项目
此教程只做个人经验分享,仅供参考,如有错误,请大佬指点~另外,此篇教程是参考了B站up主UKFC战队的frp内网穿透简单教程视频www.bilibili.com/video/BV1Jf… 在此感谢这位大佬的分享