内网穿透工具 frp 使用教程

本文最后更新于:2022年7月4日 上午

为了让家中的NAS 可以为不在局域网范围内的我提供服务,而家里又没有公网IP,需要进行内网穿透,frp是一款优秀好用的工具,本文介绍 ssh, http 内网穿透方法与示例。

frp 简介

  • frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。

  • frp目前最新版本为0.38.0,frp目前仍然处于前期开发阶段,未经充分测试与验证,不推荐用于生产环境。

  • 本文记录快速搭建 frp 并使用的方法,更多细节请参考官方文档

  • 官方 github: https://github.com/fatedier/frp

背景

frp 适用于有公网IP需求的用户,如果有需要在互联网中找到自己的电脑,但是电脑又没有公网IPv4地址,又不想用IPv6地址,恰好还有一个空闲的拥有IPv4公网地址的云服务器,那么frp 是使用你需要的工具。

使用条件

  • 内网计算机有在公网 IP 提供服务的需求
  • 有拥有公网 IP 的计算机(可以是云服务器,别人家的电脑等)
  • 如果有http / https 服务需求还要有备案的域名
  • 没有域名也可以配置 tcp 映射完成网站穿透

使用教程

安装

以我的安装了Ubuntu 20.04 的 x86_64 cpu 主机为例,我需要下载 frp版本 _ Linux _ amd64 的安装包:

  • 下载安装包:
1
wget https://github.91chi.fun//https://github.com//fatedier/frp/releases/download/v0.38.0/frp_0.38.0_linux_amd64.tar.gz
  • 解压
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ tar -axvf frp_0.38.0_linux_amd64.tar.gz 

frp_0.38.0_linux_amd64/
frp_0.38.0_linux_amd64/frpc_full.ini
frp_0.38.0_linux_amd64/frps.ini
frp_0.38.0_linux_amd64/frps_full.ini
frp_0.38.0_linux_amd64/LICENSE
frp_0.38.0_linux_amd64/frpc
frp_0.38.0_linux_amd64/systemd/
frp_0.38.0_linux_amd64/systemd/frps@.service
frp_0.38.0_linux_amd64/systemd/frpc.service
frp_0.38.0_linux_amd64/systemd/frps.service
frp_0.38.0_linux_amd64/systemd/frpc@.service
frp_0.38.0_linux_amd64/frpc.ini
frp_0.38.0_linux_amd64/frps

  • 得到这样的文件结构
1
2
frp_0.38.0_linux_amd64$ ls
frpc frpc_full.ini frpc.ini frps frps_full.ini frps.ini LICENSE systemd

其中 frpc 开头的是客户端(client) 的核心文件

其中 frps 开头的是服务器端(server) 的核心文件

systemd 文件夹是建立 systemctl 的示例文件

服务器端

  • 服务器可以购买服务商的云服务主机,最便宜的就行,但是必须有公网IP
配置
  • 此处关心的核心文件为 frpsfrps.ini
  • frps复制到 /usr/bin 目录下(也可以按照个人习惯放置)
1
sudo cp frps /usr/bin
  • frps.ini放到 /etc/frp 目录下
1
2
sudo mkdir /etc/frp
sudo cp frps.ini /etc/frp
  • 修改 frps.ini 文件 (核心步骤
1
sudo vim /etc/frp/frps.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[common]
bind_port = 7000

vhost_http_port = 6988
vhost_https_port = 6989

token=yourtoken

# dashboard 用户名密码,默认都为 admin

dashboard_port = 6999
dashboard_user = admin
dashboard_pwd = admin

log_file = ./frps.log
log_level = info
log_max_days = 3

heartbeat_timeout = 90

privilege_allow_ports = 6000-7000, 3001

max_pool_count = 100

max_ports_per_client = 0

authentication_timeout = 900

tcp_mux = true

其中:

参数 含义
bind_port 表示内网计算机和服务器计算机的通信端口,需要打开外网计算机的端口防火墙限制
vhost_http_port http 服务映射端口,需要打开外网计算机的端口防火墙限制
vhost_https_port https 服务映射端口,需要打开外网计算机的端口防火墙限制
token 协商令牌,客户端和服务器需要一致才可以生效
dashboard_port frp 管理端口,需要打开外网计算机的端口防火墙限制
dashboard_user 管理端口用户名
dashboard_pwd 管理端口密码
log_file 日志文件位置
log_level 日志级别,分为debug, info, warn, error四级
log_max_days 日志保存的天数
heartbeat_timeout 心跳配置
privilege_allow_ports frp内网穿透服务端监听的端口,如果不设置的话,所有端口都可以连接使用,但为为了不占用系统使用的端口号,建议设置允许的监听端口,比如www.chuantou.org提供的内网穿透服务器就是开放50000-60000端口
max_pool_count 连接池的数量,如果frp内网穿透客户端设置的连接池的数量大于下面的数值,就会修改frp客户端的连接池为下面的数值
max_ports_per_client 每个客户端最大可以使用的端口,0表示无限制
authentication_timeout frp内网穿透服务端frps和frp内网穿透的客户端frpc两台电脑的时间差,如果设置为0的话,不校验时间差异,默认校验时间差为900秒。
tcp_mux 是否使用tcp复用,默认为true, frp只对同意客户端的连接进行复用
开启服务
  • 之后我们执行命令:
1
/usr/bin/frps -c /etc/frp/frps.ini

便可以开启服务了

测试
  • 开启后可以访问公网IP:6999查看 frp 的工作状态,也说明我们成功开启了服务器端 frp 服务

开机启动
  • 接下来关闭服务,我们设置服务器端 frps 服务开机启动
  • 将解压的压缩包中systemd文件夹中的 frps.service文件复制到 /usr/lib/systemd/system 文件夹中
  • 如果你的 frps 文件和配置文件都按照我上述步骤完成的不需要修改 frps.service文件,否则需要将文件中 ExecStart 值更改为你执行命令时的指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=Frp Server Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/usr/bin/frps -c /etc/frp/frps.ini
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
  • 重新加载 systemd 并开启服务,设置开机启动:

相关 systemd 知识可以参考 Linux Systemd 实战

1
2
3
4
5
6
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 开启服务
sudo systemctl start frps
# 设置开启启动
sudo systemctl enable frps
  • 至此我们的服务端彻底设置完成

客户端

  • 客户端也需要下载 frp 安装包并解压
配置
  • 将 frpc 文件复制到 /usr/bin
1
sudo cp frpc /usr/bin
  • frpc.ini 文件放到 /etc/frp 文件夹中
1
2
sudo mkdir /etc/frp
sudo cp frpc.ini /etc/frp
  • 修改 frpc.ini 文件 (核心步骤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[common]
server_addr=23.23.23.23
server_port=7000
token=yourtoken

[ssh]
type = tcp
local_ip =127.0.0.1
local_port = 22
remote_port = 6987

[http]
type=http
local_port=4000
custom_domains=test.zywvvd.com

[web]
type = tcp
local_ip = 127.0.0.1
local_port = 80
remote_port = 80

该配置文件主要绑定了两个业务——ssh 和网站服务,其中http为http模式的网页,需要域名,如果没有域名可以直接使用80端口tcp映射完成无域名网页穿透

server_addr 公网服务器的公网IP
server_port 和服务器端配置一致
token 和服务器端配置一致
[ssh] / [http] 服务名称,根据个人情况设置
type 服务类型,包含 tcp, udp, http, https 等,ssh 使用 tcp即可
local_ip 本机IP,建议设置127.0.0.1 ,就不用来回改了
local_port 本地映射端口,其实本质为本地端口数据映射到服务器端端口
remote_port 服务器端端口
custom_domains http 类型必填,需要域名解析到该公网IP上(http 类型服务需要)
域名解析
  • 对于http服务需要域名解析
  • 以我的百度智能云域名为例

  • 将自己的公网 IP 解析到一个 A 记录上即可
开启服务
  • 执行命令
1
/usr/bin/frpc -c /etc/frp/frpc.ini

即可开启客户端服务

ssh 测试
  • 此时 ssh 服务已经可用了
1
2
3
4
# Windows
ssh user_name@公网IP:6987
# linux
ssh user_name@公网IP -p 6987

输入密码即可远程公网ssh访问自己的电脑

http 测试
  • 此时我把我的个人网站挂载在我本机的 4000 端口上
  • 公网访问 test.zywvvd.com:6988 即可看到我本地的网站,说明我们的http穿透成功

web 测试
  • 公网访问公网IP,可以直接访问本地映射到80端口的网页

注意:一个 frp 服务器只可以同一时间有一个 http 服务,有一个绑定 http 服务的客户机后,其余http服务不会被支持

开机启动
  • 接下来关闭服务,我们设置服务器端 frpc 服务开机启动
  • 将解压的压缩包中systemd文件夹中的 frpc.service文件复制到 /usr/lib/systemd/system 文件夹中
  • 如果你的 frpc 文件和配置文件都按照我上述步骤完成的不需要修改 frpc.service文件,否则需要将文件中 ExecStartExecReload值更改为你执行命令时的指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Frp Client Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/etc/frp/frpc -c /etc/frp/frpc.ini
ExecReload=/etc/frp/frpc reload -c /etc/frp/frpc.ini
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
  • 重新加载 systemd 并开启服务,设置开机启动:
1
2
3
4
5
6
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 开启服务
sudo systemctl start frpc
# 设置开启启动
sudo systemctl enable frpc
  • 至此我们的客户端彻底设置完成,也就完成了 ssh 和 http 的内网穿透

服务端配置详细信息

frp 服务端详细配置说明,官方的极简设置只要设置红色 bind_port即可。

稍微复杂点可以选择紫色的条目

基础配置

参数 类型 说明 默认值 可选值 备注
bind_addr string 服务端监听地址 0.0.0.0
bind_port int 服务端监听端口 7000 接收 frpc 的连接
bind_udp_port int 服务端监听 UDP 端口 0 用于辅助创建 P2P 连接
kcp_bind_port int 服务端监听 KCP 协议端口 0 用于接收采用 KCP 连接的 frpc
proxy_bind_addr string 代理监听地址 同 bind_addr 可以使代理监听在不同的网卡地址
log_file string 日志文件地址 ./frps.log 如果设置为 console,会将日志打印在标准输出中
log_level string 日志等级 info trace, debug, info, warn, error
log_max_days int 日志文件保留天数 3
disable_log_color bool 禁用标准输出中的日志颜色 false
detailed_errors_to_client bool 禁用服务端返回详细错误信息给客户端 true
heart_beat_timeout int 服务端和客户端心跳连接的超时时间 90 单位:秒
user_conn_timeout int 用户建立连接后等待客户端响应的超时时间 10 单位:秒

权限验证

参数 类型 说明 默认值 可选值 备注
authentication_method string 鉴权方式 token token, oidc
authenticate_heartbeats bool 开启心跳消息鉴权 false
authenticate_new_work_conns bool 开启建立工作连接的鉴权 false
token string 鉴权使用的 token 值 客户端需要设置一样的值才能鉴权通过
oidc_issuer string oidc_issuer
oidc_audience string oidc_audience
oidc_skip_expiry_check bool oidc_skip_expiry_check
oidc_skip_issuer_check bool oidc_skip_issuer_check

管理配置

参数 类型 说明 默认值 可选值 备注
allow_ports string 允许代理绑定的服务端端口 格式为 1000-2000,2001,3000-4000
max_pool_count int 最大连接池大小 5
max_ports_per_client int 限制单个客户端最大同时存在的代理数 0 0 表示没有限制
tls_only bool 只接受启用了 TLS 的客户端连接 false

Dashboard, 监控

参数 类型 说明 默认值 可选值 备注
dashboard_addr string 启用 Dashboard 监听的本地地址 0.0.0.0
dashboard_port int 启用 Dashboard 监听的本地端口 0
dashboard_user string HTTP BasicAuth 用户名 admin
dashboard_pwd string HTTP BasicAuth 密码 admin
enable_prometheus bool 是否提供 Prometheus 监控接口 false 需要同时启用了 Dashboard 才会生效
asserts_dir string 静态资源目录 Dashboard 使用的资源默认打包在二进制文件中,通过指定此参数使用自定义的静态资源

HTTP & HTTPS

参数 类型 说明 默认值 可选值 备注
vhost_http_port int 为 HTTP 类型代理监听的端口 0 启用后才支持 HTTP 类型的代理,默认不启用
vhost_https_port int 为 HTTPS 类型代理监听的端口 0 启用后才支持 HTTPS 类型的代理,默认不启用
vhost_http_timeout int HTTP 类型代理在服务端的 ResponseHeader 超时时间 60
subdomain_host string 二级域名后缀
custom_404_page string 自定义 404 错误页面地址

TCPMUX

参数 类型 说明 默认值 可选值 备注
tcpmux_httpconnect_port int 为 TCPMUX 类型代理监听的端口 0 启用后才支持 TCPMUX 类型的代理,默认不启用

客户端配置详细信息

基础配置

参数 类型 说明 默认值 可选值 备注
server_addr string 连接服务端的地址 0.0.0.0
server_port int 连接服务端的端口 7000
http_proxy string 连接服务端使用的代理地址 格式为 {protocol}😕/user:passwd@192.168.1.128:8080 protocol 目前支持 http 和 socks5
log_file string 日志文件地址 ./frpc.log 如果设置为 console,会将日志打印在标准输出中
log_level string 日志等级 info trace, debug, info, warn, error
log_max_days int 日志文件保留天数 3
disable_log_color bool 禁用标准输出中的日志颜色 false
pool_count int 连接池大小 0
user string 用户名 设置此参数后,代理名称会被修改为 {user}.{proxyName},避免代理名称和其他用户冲突
dns_server string 使用 DNS 服务器地址 默认使用系统配置的 DNS 服务器,指定此参数可以强制替换为自定义的 DNS 服务器地址
login_fail_exit bool 第一次登陆失败后是否退出 true
protocol string 连接服务端的通信协议 tcp tcp, kcp, websocket
tls_enable bool 启用 TLS 协议加密连接 false
heartbeat_interval int 向服务端发送心跳包的间隔时间 30
heartbeat_timeout int 和服务端心跳的超时时间 90
start string 指定启用部分代理 当配置了较多代理,但是只希望启用其中部分时可以通过此参数指定,默认为全部启用

权限验证

参数 类型 说明 默认值 可选值 备注
authentication_method string 鉴权方式 token token, oidc 需要和服务端一致
authenticate_heartbeats bool 开启心跳消息鉴权 false 需要和服务端一致
authenticate_new_work_conns bool 开启建立工作连接的鉴权 false 需要和服务端一致
token string 鉴权使用的 token 值 需要和服务端设置一样的值才能鉴权通过
oidc_client_id string oidc_client_id
oidc_client_secret string oidc_client_secret
oidc_audience string oidc_audience
oidc_token_endpoint_url string oidc_token_endpoint_url

UI

参数 类型 说明 默认值 可选值 备注
admin_addr string 启用 AdminUI 监听的本地地址 0.0.0.0
admin_port int 启用 AdminUI 监听的本地端口 0
admin_user string HTTP BasicAuth 用户名 admin
admin_pwd string HTTP BasicAuth 密码 admin
asserts_dir string 静态资源目录 AdminUI 使用的资源默认打包在二进制文件中,通过指定此参数使用自定义的静态资源
参数 类型 说明 是否必须 默认值 可选值 备注
type string 代理类型 tcp tcp, udp, http, https, stcp, sudp, xtcp, tcpmux
use_encryption bool 是否启用加密功能 false 启用后该代理和服务端之间的通信内容都会被加密传输
use_compression bool 是否启用压缩功能 false 启用后该代理和服务端之间的通信内容都会被压缩传输
proxy_protocol_version string 启用 proxy protocol 协议的版本 v1, v2 如果启用,则 frpc 和本地服务建立连接后会发送 proxy protocol 的协议,包含了原请求的 IP 地址和端口等内容
bandwidth_limit string 设置单个 proxy 的带宽限流 单位为 MB 或 KB,0 表示不限制,如果启用,会作用于对应的 frpc

本地服务配置

local_ipplugin 的配置必须配置一个,且只能生效一个,如果配置了 plugin,则 local_ip 配置无效。

参数 类型 说明 是否必须 默认值 可选值 备注
local_ip string 本地服务 IP 127.0.0.1 需要被代理的本地服务的 IP 地址,可以为所在 frpc 能访问到的任意 IP 地址
local_port int 本地服务端口 xxxx 配合 local_ip
plugin string 客户端插件名称 见客户端插件的功能说明 用于扩展 frpc 的能力,能够提供一些简单的本地服务,如果配置了 plugin,则 local_ip 和 local_port 无效,两者只能配置一个
plugin_params map 客户端插件参数 map 结构,key 需要都以 “plugin_” 开头,每一个 plugin 需要的参数也不一样,具体见客户端插件参数中的内容

负载均衡和健康检查

参数 类型 说明 是否必须 默认值 可选值 备注
group string 负载均衡分组名称 用户请求会以轮询的方式发送给同一个 group 中的代理
group_key string 负载均衡分组密钥 用于对负载均衡分组进行鉴权,group_key 相同的代理才会被加入到同一个分组中
health_check_type string 健康检查类型 tcp,http 配置后启用健康检查功能,tcp 是连接成功则认为服务健康,http 要求接口返回 2xx 的状态码则认为服务健康
health_check_timeout_s int 健康检查超时时间(秒) 3 执行检查任务的超时时间
health_check_max_failed int 健康检查连续错误次数 1 连续检查错误多少次认为服务不健康
health_check_interval_s int 健康检查周期(秒) 10 每隔多长时间进行一次健康检查
health_check_url string 健康检查的 HTTP 接口 如果 health_check_type 类型是 http,则需要配置此参数,指定发送 http 请求的 url,例如 “/health”

TCP

参数 类型 说明 是否必须 默认值 可选值 备注
remote_port int 服务端绑定的端口 用户访问此端口的请求会被转发到 local_ip:local_port 当type=tcp时,此项必选

UDP

参数 类型 说明 是否必须 默认值 可选值 备注
remote_port int 服务端绑定的端口 用户访问此端口的请求会被转发到 local_ip:local_port

HTTP

custom_domainssubdomain 必须要配置其中一个,两者可以同时生效。

参数 类型 说明 是否必须 默认值 可选值 备注
custom_domains []string 服务器绑定自定义域名 是(和 sub_domain 两者必须配置一个) 用户通过 vhost_http_port 访问的 HTTP 请求如果 Host 在 custom_domains 配置的域名中,则会被路由到此代理配置的本地服务
subdomain string 自定义子域名 是(和 custom_domains 两者必须配置一个) 和 custom_domains 作用相同,但是只需要指定子域名前缀,会结合服务端的 subdomain_host 生成最终绑定的域名
locations []string URL 路由配置 采用最大前缀匹配的规则,用户请求匹配响应的 location 配置,则会被路由到此代理
http_user string 用户名 如果配置此参数,暴露出去的 HTTP 服务需要采用 Basic Auth 的鉴权才能访问
http_pwd string 密码 结合 http_user 使用
host_header_rewrite string 替换 Host header 替换发送到本地服务 HTTP 请求中的 Host 字段
headers map 替换 header map 中的 key 是要替换的 header 的 key,value 是替换后的内容

HTTPS

custom_domainssub_domain 必须要配置其中一个,两者可以同时生效。

参数 类型 说明 是否必须 默认值 可选值 备注
custom_domains []string 服务器绑定自定义域名 是(和 sub_domain 两者必须配置一个) 用户通过 vhost_http_port 访问的 HTTP 请求如果 Host 在 custom_domains 配置的域名中,则会被路由到此代理配置的本地服务
sub_domain string 自定义子域名 是(和 custom_domains 两者必须配置一个) 和 custom_domains 作用相同,但是只需要指定子域名前缀,会结合服务端的 subdomain_host 生成最终绑定的域名

STCP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

SUDP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

XTCP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

参考资料


内网穿透工具 frp 使用教程
https://www.zywvvd.com/notes/environment/nas/frp-usage/frp-usage/
作者
Yiwei Zhang
发布于
2021年11月24日
许可协议