Featured image of post FRP 内网穿透实战:让公网 VPS 暴露内网 SSH、MySQL 与 Web 服务

FRP 内网穿透实战:让公网 VPS 暴露内网 SSH、MySQL 与 Web 服务

用 frp 0.20~0.43 把内网服务映射到公网,含 systemd、systemctl 守护、跨平台客户端、HTTP/HTTPS/TCP/UDP 代理、配置文件模板与多用户批量部署示例

背景

家里或公司内网的机器没有公网 IP,外面想 SSH 进去、连 MySQL、访问内网 Web 系统——传统的方案是路由器做端口映射,或者买花生壳这种商业服务。frp(Fast Reverse Proxy)用一台有公网 IP 的 VPS 作为"中转",让任何内网服务"看起来"跑在公网 IP 上,部署简单,开源免费

适用场景

  • 远程办公,需要从公网 SSH 进内网开发机
  • 临时把内网 MySQL 暴露给第三方调试
  • 异地访问家里的 NAS、摄像头、Git 服务
  • 没有公网 IP 的云主机需要对外提供 Web 服务

前置知识

  • 一台有公网 IP 的 VPS(带宽建议 ≥ 5Mbps)
  • Linux 基础(systemd、iptables)
  • 一点网络常识(端口、TCP/UDP)

注意:frp 把内网服务"反向"暴露到公网,任何能连到 frps 端口的人都能访问。请务必:

  1. 使用 token 鉴权
  2. 配合 fail2ban 或 ACL 限制来源 IP
  3. 暴露 SSH 等高危服务时启用 stcp/xtcp 加密模式

一、frp 工作原理

1
2
[公网客户端]  ──>  frps (公网 VPS :7000)  ──>  frpc (内网机器)
                    ↑ 中转、反向代理            ↑ 主动连接建立隧道

关键点

  • frps(server)跑在公网 VPS,监听 bind_port(默认 7000)
  • frpc(client)跑在内网机器,主动连到 frps,建立长连接
  • 公网客户端访问 VPS_IP:remote_port,frps 把流量通过已建立的隧道转发给 frpc,再由 frpc 转发到内网的 local_ip:local_port

支持的代理类型(frp 0.20+):

类型用途备注
tcp纯 TCP 端口映射SSH、MySQL、Redis、自定义协议
udp纯 UDP 端口映射DNS、游戏、VoIP
httpHTTP 应用支持改 Host Header、basic auth
httpsHTTPS 应用配合证书
stcp安全 TCP(需两边都跑 frpc)不在服务端暴露端口,访问者也需密钥
xtcp点对点穿透流量不经过服务器中转,UDP 打洞

二、安装

2.1 下载二进制

frp 0.43.0(2022-02 发布,长期维护版本):

1
2
3
4
5
6
7
# Linux x86_64
curl -O https://github.com/fatedier/frp/releases/download/v0.43.0/frp_0.43.0_linux_amd64.tar.gz
tar -zxvf frp_0.43.0_linux_amd64.tar.gz -C /usr/local/games
mv /usr/local/games/frp_0.43.0_linux_amd64 /usr/local/games/rp

# Windows 客户端
# https://github.com/fatedier/frp/releases/download/v0.43.0/frp_0.43.0_windows_amd64.zip

2024-05 更新提示:frp 已迭代到 0.60+,大版本(v0.50+)开始推 TOML 配置,0.43 仍是 INI 经典格式。本篇示例兼顾 0.43(INI)和 0.50+(TOML)。

2.2 Docker 部署

1
2
3
4
5
6
7
8
9
# 服务端
docker run -d --restart=always --network host \
  -v /etc/frp/frps.ini:/etc/frp/frps.ini \
  --name frps snowdreamtech/frps

# 客户端
docker run -d --restart=always --network host \
  -v /etc/frp/frpc.ini:/etc/frp/frpc.ini \
  --name frpc snowdreamtech/frpc

--network host 让 frpc 直接监听内网服务端口,避免 Docker 端口映射的复杂性。


三、配置详解(INI 经典格式)

3.1 服务端 frps.ini

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[common]
bind_addr = 0.0.0.0
bind_port = 7000
# 鉴权令牌,客户端必须一致
token = your_strong_token_here
# Dashboard 端口(可选,浏览器看连接状态)
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = your_dashboard_pwd
# 日志
log_file = /var/log/frps.log
log_level = info
log_max_days = 7
# 允许的端口范围(防止被滥用)
allow_ports = 2000-3000,5000-6000,6000-10000

关键参数

  • token 必设,防止别人白嫖你的 VPS
  • allow_ports 限制客户端能使用的 remote_port 段
  • dashboard_port 默认关闭,开启后通过浏览器看连接状态

3.2 客户端 frpc.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
30
31
32
33
34
[common]
server_addr = x.x.x.x        # frps 的公网 IP
server_port = 7000
token = your_strong_token_here

# SSH 暴露
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

# MySQL 暴露
[mysql]
type = tcp
local_ip = 127.0.0.1
local_port = 3306
remote_port = 3307

# Web 服务(HTTP 代理)
[web]
type = http
local_port = 8080
local_ip = 127.0.0.1
custom_domains = your.domain.com
locations = /

# 加密模式(推荐用于敏感服务)
[secret_ssh]
type = stcp
# 只有知道 sk 的人才能连
sk = abcdefgh
local_ip = 127.0.0.1
local_port = 22

四、HTTPS / Web 应用场景

 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
# frps.ini(服务端)
[common]
bind_addr = 0.0.0.0
bind_port = 7000
vhost_http_port = 80
vhost_https_port = 443
token = your_strong_token_here

# frpc.ini(客户端)
[common]
server_addr = x.x.x.x
server_port = 7000
token = your_strong_token_here

[blog]
type = http
local_port = 3000
local_ip = 127.0.0.1
custom_domains = blog.example.com

[wiki]
type = https
local_port = 443
local_ip = 127.0.0.1
custom_domains = wiki.example.com

注意:域名解析到 frps 的公网 IP,frps 根据 custom_domains 路由到不同 frpc。


五、systemd 守护(推荐生产方式)

5.1 服务端 /etc/systemd/system/rps.service

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

[Service]
Type = simple
ExecStart = /usr/local/games/rp/frps -c /usr/local/games/rp/frps.ini
Restart = always
RestartSec = 5s

[Install]
WantedBy = multi-user.target

5.2 客户端 /etc/systemd/system/rpc.service

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

[Service]
Type = simple
ExecStart = /usr/local/games/rp/frpc -c /usr/local/games/rp/frpc.ini
Restart = always
RestartSec = 20s
User = nobody

[Install]
WantedBy = multi-user.target
1
2
3
4
systemctl daemon-reload
systemctl enable --now rps   # 服务端
systemctl enable --now rpc   # 客户端
systemctl status rpc

5.3 验证连接

1
2
3
# 从公网客户端访问
ssh -p 6000 root@<vps-public-ip>
# 实际上等同于 SSH 进内网机器的 22 端口

六、TOML 格式(frp 0.50+)

frp 0.50+ 推荐 TOML:

1
2
3
4
5
6
7
8
9
# frps.toml
bindAddr = "0.0.0.0"
bindPort = 7000
auth.method = "token"
auth.token = "your_strong_token_here"
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "your_dashboard_pwd"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
auth.method = "token"
auth.token = "your_strong_token_here"

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

[[proxies]]
name = "mysql"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3306
remotePort = 3307

七、批量部署多个内网机器

假设一台公网 VPS 暴露多个内网客户的 MySQL/SSH:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 客户端 A(客户 A)
[mysql]
type = tcp
local_ip = 127.0.0.1
local_port = 3306
remote_port = 6101

# 客户端 B(客户 B)
[mysql]
type = tcp
local_ip = 127.0.0.1
local_port = 3306
remote_port = 6102

配合 fail2ban:因为所有 frpc 看到的来源都是 127.0.0.1必须在 frps 端 配置 fail2ban,按 frps 日志里的真实 IP 拉黑。

1
2
3
4
# /etc/fail2ban/filter.d/frps.conf
[Definition]
failregex = ^.*get a user connection \[<HOST>:[0-9]*\]
ignoreregex = ^.*\[.*gateway.*

八、常见问题

8.1 连接后立即断开

  • 检查 VPS 的 7000remote_port 是否在安全组/防火墙开放
  • 客户端 server_addr 写错(写成了内网 IP)
  • token 不一致

8.2 速度慢

  • frp 走 TCP 中转,带宽 = min(VPS 上行, frpc 上行)
  • 加密模式 stcp/xtcp 略增加 CPU 消耗
  • 大文件传输考虑 rclone + 临时公网 OSS

8.3 0.50+ 升级后 INI 不识别

frp 0.50 删除了对 INI 的支持,统一 TOML。用 v0.43.0 仍是 INI,v0.52.3 之后基本 TOML 化。


九、卸载

1
2
3
4
5
6
systemctl stop rpc
systemctl disable rpc
rm -rf /etc/systemd/system/rpc.service
rm -rf /usr/local/games/rp
systemctl daemon-reload
systemctl reset-failed rpc

小结

frp 0.20~0.43 是经典 INI 时代,0.50+ 切到 TOML,核心架构没变:主动连接 + 长隧道 + 端口映射。生产部署三个要点:

  1. 必设 token,避免被白嫖
  2. 配合 fail2ban,按 frps 日志真实 IP 拉黑攻击者
  3. systemd 守护 + Restart=always,客户端断开自动重连

下一步

  • 把 frps 配合 nginxWebUI 做证书自动续期(HTTP 代理场景)
  • stcp/xtcp 加密模式暴露 SSH
  • 高敏感服务用 WireGuard 替代 frp(点对点,无中转)

2024 视角:frp 0.59+ 在云原生时代的"角色变化"

2017 那篇 frp 是"内网穿透神器"。2024 视角下,frp 仍是经典,但有 3 个新选择更激进

一、frp 版本进化(2024 主流)

  • frp 0.59+(2024-06 起持续更新):全面 TOML 化,INI 已被废弃
  • 新特性
    • WebSocket over TLS(2024):WSS 模式走 443 端口,能穿透企业防火墙
    • QUIC 协议(实验性):UDP 传输,比 TCP 模式延迟低 20%
    • 带宽限制 / 速率统计:精确控制客户端带宽
    • 多 frpc 共享 frps:跨 NAT 设备互联
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# frps.toml (0.59+)
bindAddr = "0.0.0.0"
bindPort = 7000
auth.method = "token"
auth.token = "your_strong_token"

# 启用 WSS(重要:能穿透企业防火墙)
transport.websocket.enable = true
transport.websocket.url = "/_frp_ws"

# 启用 QUIC(2024 新)
transport.quic.enable = true

二、Cloudflare Tunnel——2024 主流替代

  • Cloudflare Tunnelcloudflared):不需要公网 VPS——Cloudflare 边缘做"中转"。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 装
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared focal main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
apt update && apt install cloudflared

# 登录
cloudflared tunnel login
cloudflared tunnel create my-tunnel
cloudflared tunnel route dns my-tunnel myapp.example.com

# 启动(后台)
cloudflared tunnel --config /etc/cloudflared/config.yml run my-tunnel
1
2
3
4
5
6
7
8
# /etc/cloudflared/config.yml
tunnel: my-tunnel
credentials-file: /root/.cloudflared/xxxxxx.json

ingress:
  - hostname: myapp.example.com
    service: http://localhost:3000
  - service: http_status:404
  • 优势
    • 不需要公网 VPS(Cloudflare 边缘免费)
    • 零暴露端口(只用 HTTPS 443 出站)
    • Cloudflare 整套生态:CDN / WAF / DDoS 防护 / 零信任鉴权
    • 免费 50 个 tunnel / 1000 次请求/秒
  • 2024 大量新项目用 Cloudflare Tunnel 替代 frp

三、Tailscale —— “点对点 VPN” 替代内网穿透

2017 那篇 frp 是"反代中转"。2024 主流是 P2P VPN

1
2
3
4
# 装 Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up
# 自动获得 100.x.x.x 虚拟 IP
  • Tailscale SSH 替代 SSH 隧道
    • 不需要公网 IP
    • 不需要 frp 中转
    • 鉴权走 Tailscale ACL(不是 SSH 公私钥)
1
2
3
4
# 直接 SSH 任何 Tailscale 设备
ssh user@machine-name
# Tailscale 自动协商点对点连接(UDP 打洞)
# 如果 P2P 失败,自动 fallback 到 Tailscale DERP 中转(仍比 frp 简单)
  • Tailscale ACL(基于 WireGuard):
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// tailscale ACL
{
  "acls": [
    {
      "action": "accept",
      "src": ["group:dev"],
      "dst": ["tag:prod-server:22"]
    }
  ]
}

四、frp 在 K8s 时代的"角色"

  • 2024 趋势:K8s 项目用 Ingress + Cloudflare Tunnel 替代 frp。
  • frp 仍在用的场景:
    • 自建机房(无 Cloudflare)
    • 临时调试(1 小时建一个隧道)
    • 边缘设备(IoT / 工厂)
    • 企业内网(不能用 Cloudflare)

五、frp 安全加固的"现代"姿势

2017 那篇给 token 鉴权。2024 升级

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# frps.toml - 强认证
auth.method = "token"
auth.token = "<random-32-chars>"
auth.additionalScopes = ["Heartbeat"]

# TLS 加密(防中间人)
transport.tls.force = true

# 限速(防滥用)
transport.maxPoolCount = 5
1
2
3
4
5
6
7
# frpc.toml - 强认证
auth.method = "token"
auth.token = "<random-32-chars>"

# 多重 TLS
transport.tls.enable = true
transport.tls.disableCustomTLSFirstByte = false

六、frp 性能优化

  • 2024 实测:frp 0.59+ 在 1Gbps 内网下,单 tunnel 可达 800+ Mbps(TCP 直连)。
  • 多 tunnel 负载(frp 0.59+):
1
2
3
4
5
6
7
[[proxies]]
name = "web1"
type = "tcp"
localPort = 80
remotePort = 8080
# 启用多路复用
transport.bandwidthLimit = "100MB"
  • QUIC 协议(2024 实验):减少握手延迟(首次连接 0-RTT)。

七、frp 的"替代品"对比(2024)

工具架构适用
frp客户端-服务器自建 VPS、临时穿透
Cloudflare Tunnel客户端-Cloudflare 边缘不需要 VPS、零信任
TailscaleP2P(WireGuard)长期组网、家庭 / 远程办公
ZeroTierP2P + Controller多平台、大规模
nps(国产)客户端-服务器国内网络、简单场景
lanproxy(国产)Java 写简单 Java 项目集成
rathole(2022+)Rust 写性能敏感、嵌入式
bore(Rust)极简个人项目、临时调试

八、frp + Cloudflare Tunnel 的"混合"

  • 2024 一些项目同时用 frp + Cloudflare Tunnel:
    • frp 做"内网到 VPS"的隧道
    • Cloudflare Tunnel 做"VPS 到公网"的暴露
    • 效果:VPS 的 IP 永远不暴露(Cloudflare 边缘代为接受流量)

九、AI 时代的"运维代理"

  • 2024 LLM 时代:AI Agent(如 Claude Code / Devin)需要 SSH 访问内网服务器。
  • Tailscale / Cloudflare Tunnel 让 AI Agent 不需要公网 IP 就能访问内网。
  • 未来:frp 在 AI Agent 场景会"云化"——AI Agent 通过 Tunnel 远程执行命令。

源文档

  • os/linux/第三方tools/net/frp/内网穿透.md(内网穿透场景、systemd 模板、Docker 部署)
  • os/linux/第三方tools/net/frp/frp.md(多客户端批量配置、fail2ban 集成、TOML 新格式)
使用 Hugo 构建
主题 StackJimmy 设计