唠唠闲话

FRP 的两个实践:

  1. 不使用 VPN 直接访问校园网内网(TODO)
  2. 将内服务映射到公网,灵活访问和管理内网服务:「Nginx 双域名管理内网服务

内网穿透简介

互联网上两个不同的主机进行通信首先需要知道对方 IP。根据 IP 协议,只有分配了公网 IP 的设备才能在互联网上通信和传输数据。而中国人口/设备众多,分配到的 IPv4 资源又少,因此绝大部分情况是通过路由器/交换机转换公网 IP 后才上网。

位于路由器/交换机后的设备一般是内网设备,分配的IP地址以 192.168/172.16/10.0 开头,属于内网 IP。要让内网设备对外提供服务,就需要进行内网穿透。

常见穿透工具包括:Ngrok, FRP, ZeroTier 等,本文介绍 FRP 的使用。

相关阅读
利用frp工具实现内网穿透、随时随地访问内网服务
frp 内网穿透教程
内网穿透系列:ZeroTier技术初级


FRP 简介

FRP 是什么

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

基本原理

20230618223449

如上图所示:

  • 在带有公网 ip 的云服务器上部署 frp 的服务端 frps
  • 在需要穿透的内网服务器上部署 frp 的客户端 frpc
  • 每个客户端都会有一个配置文件用于和服务器连接
  • 公网服务器充当代理服务器,用户访问 公网ip + 端口号时,公网服务器的 frps 服务会根据端口号,自动转发到对应的内网服务器上,从而访问到内网服务

FRP 配置及使用

教程使用 v0.52.3,配置文件为 .toml 格式,旧版教程参见 旧版 一节。

下载 FRP

访问 frp 发行地址,根据系统选择下载:

20231217210538

一般的 Linux 系统为 amd 架构,不确定可以通过输入 arch 命令查看,如果返回 x86_64 则为 amd 架构。

命令行的下载方式:

1
2
wget -c https://github.com/fatedier/frp/releases/download/v0.52.3/frp_0.52.3_linux_amd64.tar.gz
tar -zxvf frp_0.52.3_linux_amd64.tar.gz && rm frp_0.52.3_linux_amd64.tar.gz

将服务端和客户端分开,方便管理:

1
2
3
4
cd frp_0.52.3_linux_amd64
mkdir client server
mv frpc* client
mv frps* server

其中 server 文件夹放到公网服务器,client 文件夹放到内网服务器。

配置服务端

以下是一个简单的配置文件,参数见注释,完整的配置文件见 frps_full_example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bindAddr = "0.0.0.0"
bindPort = 7000
# 监控流量页面
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "username"
webServer.password = "password"

# 授权码
auth.method = "token"
auth.token = "yourtoken"

# 去除访问限速
transport.tcpMux = false

# frp日志配置
log.to = "/home/user/software/frp/frps.log"
log.level = "info"
log.maxDays = 3

这里有几个参数需要根据需要手动修改:

  1. bindPort:frp 服务端监听的端口,也即服务入口,建议修改
  2. auth.token:授权码,这个授权码之后在客户端还会用到
  3. webServer.port:监控流量页面的端口,建议修改
  4. webServer.user:监控流量页面的用户名
  5. webServer.password:监控流量页面的密码
  6. log.to:日志文件路径,根据需要修改

其中 auth.token 可通过 pwgen -s 32 1 生成,这是连接服务用的密钥,安全考虑务必修改。

服务端自启动

server 目录上传到公网服务器,创建 frps.server 文件:

1
2
cd /lib/systemd/system
sudo vim frps.service

内容编写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=frps service
After=network.target syslog.target
Wants=network.target

[Service]
Type=simple
ExecStart=/home/user/software/frp/frps -c /home/user/software/frp/frps.toml
Restart=always
RestartSec=15s

[Install]
WantedBy=multi-user.target

其中 ExecStart 填写 frps 的实际路径和配置文件路径。

编写完成后,执行

1
2
sudo systemctl enable frps
sudo systemctl start frps

后续如果更改了配置文件,执行下边命令重启服务:

1
2
sudo systemctl daemon-reload
sudo systemctl restart frps

通常,我们可以通过下边命令查看服务状态

1
sudo systemctl status frps  # 查看服务状态

客户端配置

client 目录上传到内网服务器,如下编辑 frpc.toml,参数见注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
serverAddr = "公网IP地址"
serverPort = 7000

webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "username"
webServer.password = "password"
# 授权码
auth.method = "token"
auth.token = "yourtoken"
# 设置心跳
auth.additionalScopes = ["HeartBeats"]
# 去除访问限速
transport.tcpMux = false
# frp日志配置
log.to = "/home/user/software/frp/frpc.log"
log.level = "info"
log.maxDays = 3

其中 serverAddr 为公网服务器的 IP,其他内容与服务端配置文件保持一致。此外,对于需要添加服务,比如 ssh 穿透,在 frpc.toml 中添加相应 proxies 字段,比如

1
2
3
4
5
6
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 2222

客户端的自启动类似配置。

监控设置

默认地,通过 IP + 端口访问监控页面。如果有域名可以在 Nginx 中添加如下配置:

1
2
3
4
5
6
7
server{
listen 80;
server_name your_domain;
location /{
proxy_pass http://localhost:7500;
}
}

其中 your_domain 为你的域名,7000 为服务端的 webServer.port 端口。

心跳设置

如果不设置心跳,frp 创建的连接可能在间隔较长时间后会断开,重新连接需刷新几次才能成功。为了避免这种情况的出现,可以在服务端输入 crontab -e,添加定时任务

1
* * * * * curl localhost:8080 --max-time 5  >/dev/null 2>&1

这里创建了一个 curl 请求,定时访问服务器的 8080,而该 8080 端口穿透为内网服务,这样每分钟就会发送一次心跳,避免连接断开。

客户端 toml 文件添加相应的 proxies 字段:

1
2
3
4
5
6
[[proxies]]
name = "heartbeat"
type = "tcp"
localIP = "127.0.0.1"
localPort = 80
remotePort = 8080

FRP 配置及使用 | 旧版

以下为 0.49.0 版本的配置,使用 .ini 文件,新版使用 .toml 文件。

下载 FRP

服务端和客户端使用的都是同一份文件,只是配置文件和启动文件不同。因此只需要下载一份文件,并按类型分成两份。

下载地址:https://github.com/fatedier/frp/releases

服务器是 x86_64 架构,因此下载 linux_amd64 版本,如下图

20230617141352

通过命令行下载并解压:

1
2
3
wget -c https://github.com/fatedier/frp/releases/download/v0.49.0/frp_0.49.0_linux_amd64.tar.gz
tar -xvf frp_0.49.0_linux_amd64.tar.gz
mv frp_0.49.0_linux_amd64 frp

查看目录:

1
2
3
4
5
6
7
8
.
├── frpc
├── frpc_full.ini
├── frpc.ini
├── frps
├── frps_full.ini
├── frps.ini
└── LICENSE

这些文件分成两部分。

  1. 客户端,也即内网的服务器,需要 frpc 和 frpc.ini
  2. 服务端,也即公网的服务器,需要 frps 和 frps.ini
  3. 剩下的两个文件用于查看支持的所有配置项,可以不用管

将两类文件分别打包

1
2
3
mkdir client server
mv frpc* client
mv frps* server

配置服务端

server 目录上传到公网服务器,如下编辑 frps.ini,参数见注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[common]
# frp监听的端口,默认是7000,可以改成其他的
bind_port = 7000
# 授权码,请改成更复杂的,这个token之后在客户端会用到
token = e10adc3949ba59abbe56e057f20f883e
# 开启HTTP
#vhost_http_port = 8088
# 去除TCP速度限制
tcp_mux = false

# frp管理后台端口,请按自己需求更改
dashboard_port = 7500
# frp管理后台用户名和密码,请改成自己的
dashboard_user = admin
dashboard_pwd = admin123456
enable_prometheus = true

# frp日志配置
log_file = /home/frp/frp/frps.log
log_level = info
log_max_days = 3

其中授权码可以用 pwgen 命令来生成,这个授权码之后在客户端还会用到。

1
2
sudo apt install pwgen -y
pwgen -s 32 1

运行服务:

1
./frps -c frps.ini

打开服务器的 7500 端口,即 dashboard_port 的设置值,输入设置的账户和密码,登录后即可看到 frp 的状态。

服务端自启动

把 frps 添加为系统服务,这一来当系统重启时,Frps 服务会自动启动,并且不需要手动再次启动。

frps, frps.ini 文件放到系统目录下,比如

1
2
3
sudo mv frps /usr/bin/ # frps 可执行文件
sudo mkdir /etc/frp
sudo mv frps.ini /etc/frp/ # 配置文件

然后新建文件:frps.service,内容如下:

1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=frps service
After=network.target syslog.target
Wants=network.target

[Service]
Type=simple
ExecStart=/usr/bin/frps -c /etc/frp/frps.ini

[Install]
WantedBy=multi-user.target

这里 ExecStart 的路径要和 frps 的路径一致。

将文件复制到自启服务项:

1
sudo cp frps.service /usr/lib/systemd/system/

设置自启动,并启动服务

1
2
3
systemctl enable frps  # 允许自启动
# 执行成功会提示“Created symlink /etc/systemd/system/multi-user.target.wants/frps.service → /usr/lib/systemd/system/frps.service.”
systemctl start frps # 启动客户端服务

客户端配置

服务端配置后,就可以配置客户端了。

client 目录上传到内网服务器,如下编辑 frpc.ini,参数见注释。

1
2
3
4
5
6
7
8
9
10
11
12
[common]
server_addr = 180.xxx.xxx.xxx # 服务端所在的公网ip地址
server_port = 7000 # 服务端默认端口号,与服务端配置文件保持一致
token = e10adc3949ba59abbe56e057f20f883e
# 去掉速度限制
tcp_mux = false

[overleaf]
type = tcp # 注意:这个地方一律填写tcp
local_ip = 192.168.1.211 # gitlab所在内网服务器的ip地址
local_port = 8081 # 本地访问端口号
remote_port = 8081 # 映射到云服务器的端口号

第一处 common 是公共配置,第二处 overleaf 是需要映射的服务,可以根据服务命令,但注意不能与已有服务名称重复。(比如在多台服务器上配置 [ssh] 的穿透,则给服务器命名 [ssh-1][ssh-2] 避免冲突)

同样地,本地执行 ./frpc -c frpc.ini 即可启动客户端。

P.S. 建议使用 tmux 在后台启动服务

1
2
3
tmux new -s frpc
./frpc -c frpc.ini
# Ctrl + B + D 退出