frp 的本质:工作在端口转发/反向代理层。内网侧 frpc 主动连接公网侧 frpsfrps 监听公网端口,并把 TCP/UDP/HTTP 等流量通过已建立的通道转发到内网服务。

本文档面向下面这个环境:

1
2
3
4
5
6
7
8
云服务器(有公网 IP)
公网 IP: 1.2.3.4
运行 frps

本地服务器(没有公网 IP 或不想暴露公网)
局域网 IP: 192.168.10.2
本地测试服务: 127.0.0.1:8080
运行 frpc

目标是:外部访问 1.2.3.4:18080 时,流量转发到本地服务器的 127.0.0.1:8080

适用场景

  • 临时把本地测试服务暴露给外部人员访问。
  • 接收第三方 webhook 回调,例如 GitHub、微信、支付平台回调。
  • 本地没有公网 IP,但需要短期公网访问入口。
  • 外部访问者不能或不方便安装 VPN 客户端。

不适用场景

  • 长期暴露数据库、Redis、管理后台等高风险服务。
  • 公司内部开发/测试人员访问内网服务。
  • 想把多台机器组成统一私有网络。
  • 想让测试环境整体出网走生产服务器。

这些场景更适合 WireGuard、Tailscale、Nginx 反代或专门的 API Gateway。

运行流程

1
2
3
4
5
6
7
外部访问者
↓ 访问 1.2.3.4:18080
云服务器 frps
↓ frp 数据通道
本地服务器 frpc

127.0.0.1:8080

frp 能穿透内网,是因为 frpc 会从本地服务器主动连接公网云服务器上的 frps。外部连接到 frps 的映射端口后,frps 再把数据转给已经连上来的 frpc

下载和安装

到 frp GitHub Releases 下载与系统架构匹配的版本:

1
https://github.com/fatedier/frp/releases

本文不固定具体 frp 版本号。安装或升级前先看 GitHub Releases 的 latest release 和 release notes,再选择稳定版本。云服务器和本地服务器必须使用同一个 frp 版本,避免 frps / frpc 协议或配置格式不一致。

下面示例假设解压后放在:

1
/opt/frp

常见目录:

1
2
3
4
/opt/frp/frps
/opt/frp/frpc
/opt/frp/frps.toml
/opt/frp/frpc.toml

云服务器配置 frps

编辑:

1
sudo vim /opt/frp/frps.toml

基础配置:

1
2
3
4
bindPort = 7000

auth.method = "token"
auth.token = "replace-with-a-long-random-token"

含义:

  • bindPort = 7000frpc 连接 frps 的控制端口。
  • auth.token:客户端和服务端共享的认证 token,必须改成随机强字符串。

创建 systemd 服务:

1
sudo vim /etc/systemd/system/frps.service

内容:

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=frp server
After=network.target

[Service]
Type=simple
ExecStart=/opt/frp/frps -c /opt/frp/frps.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

启动:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo systemctl status frps

云服务器安全组至少开放:

1
2
TCP 7000   frpc 连接 frps
TCP 18080 对外映射的测试服务端口

如果只给固定来源访问,建议在安全组里限制来源 IP。

本地服务器配置 frpc

编辑:

1
sudo vim /opt/frp/frpc.toml

示例:把云服务器 18080 转到本地 8080

1
2
3
4
5
6
7
8
9
10
11
12
serverAddr = "1.2.3.4"
serverPort = 7000

auth.method = "token"
auth.token = "replace-with-a-long-random-token"

[[proxies]]
name = "test-web"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 18080

创建 systemd 服务:

1
sudo vim /etc/systemd/system/frpc.service

内容:

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=frp client
After=network.target

[Service]
Type=simple
ExecStart=/opt/frp/frpc -c /opt/frp/frpc.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

启动:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
sudo systemctl status frpc

验证

本地服务器确认服务存在:

1
curl http://127.0.0.1:8080

从外部访问云服务器映射端口:

1
curl http://1.2.3.4:18080

查看日志:

1
2
journalctl -u frps -f
journalctl -u frpc -f

HTTP 域名访问

如果希望用域名访问,常见做法是:

1
2
3
4
5
6
7
8
9
外部用户
↓ https://test.example.com
Nginx on 云服务器
↓ 127.0.0.1:18080
frps

frpc

本地测试服务

Nginx 负责 TLS、域名、访问控制和日志;frp 只负责把流量转回本地服务。

安全建议

  • 不要把 MySQL、Redis、SSH、后台管理端直接映射到公网。
  • auth.token 必须使用高强度随机字符串。
  • 映射端口尽量只开放给固定来源 IP。
  • 对外 HTTP 服务建议前面加 Nginx、HTTPS、Basic Auth 或 IP 白名单。
  • 临时演示结束后及时关闭映射端口和 frpc
  • 记录每个 remotePort 的用途和负责人,避免端口长期无人维护。

和 WireGuard 的区别

frp 是端口映射:

1
1.2.3.4:18080 -> 127.0.0.1:8080

WireGuard 是私有网络:

1
开发电脑 -> VPN -> 10.77.0.2:8080

如果访问者都是公司内部人员,优先用 WireGuard。只有访问者不能安装 VPN 客户端,或者必须给第三方平台回调时,才用 frp 暴露公网入口。

常见问题

外部访问端口不通

优先检查:

  • 云服务器安全组是否开放 remotePort
  • frps 是否正常运行。
  • frpc 是否连接成功。
  • 本地服务是否监听在 localIP:localPort

frpc 连接失败

优先检查:

  • serverAddr 是否为云服务器公网 IP。
  • serverPort 是否与 frps.tomlbindPort 一致。
  • auth.token 是否一致。
  • 云服务器安全组是否开放 bindPort

端口冲突

如果 remotePort 已被占用,换一个端口,或先查看占用:

1
sudo ss -lntp

参考

迭代记录

  • 2026-05-26:复核 frp GitHub release 信息;明确本文不固定版本号,安装前以 latest release / release notes 为准,并强调 frpsfrpc 使用同一版本。