2024年3月,我接手一个电商项目,开发服务器部署在公司内网(IP: 192.168.1.100),数据库MySQL 8.0.35跑在上面,Redis 7.2.4做缓存。白天在公司用VSCode Remote-SSH直连,延迟<1ms,爽得很。
但晚上回家或者周末加班,问题来了:公司没有公网IP,路由器是TP-Link家用级,不支持端口映射。我只能用TeamViewer远程桌面,卡成PPT,延迟200ms+,敲个代码等半秒才显示。更坑的是,数据库连不上,每次都要手动导出SQL再导入本地。
试过Ngrok免费版,速度慢到怀疑人生,带宽被限制在1Mbps。试过ZeroTier,公司网络策略禁止安装虚拟网卡驱动。最后选了frp 0.58.0,自己搭中转服务器,总算解决了。
我对比了市面上主流的三种方案,测试环境:公司内网服务器(Ubuntu 22.04,4核8G),公网中转服务器(阿里云轻量应用服务器,2核4G,5Mbps带宽),客户端(MacBook Pro M1,家里宽带100Mbps)。
| 方案 | 延迟(ms) | 带宽(Mbps) | 配置复杂度 | 稳定性 | 成本 |
|---|---|---|---|---|---|
| Ngrok免费版 | 180-250 | 1 | 低 | 差(经常断连) | 免费 |
| ZeroTier | 30-50 | 10-20 | 中 | 中(依赖网络策略) | 免费 |
| frp 0.58.0 | 8-15 | 4.5-5 | 中高 | 高(自建服务器) | 服务器月费30元 |
结论:如果你有公网服务器(哪怕最便宜的轻量云),frp是最优解。延迟低、带宽可控、完全自主。Ngrok免费版只适合临时测试,ZeroTier适合网络环境宽松的场景。
所有机器都下载同一个压缩包,里面包含frps(服务端)和frpc(客户端)。
# 公网服务器(服务端)
wget https://github.com/fatedier/frp/releases/download/v0.58.0/frp_0.58.0_linux_amd64.tar.gz
tar -zxvf frp_0.58.0_linux_amd64.tar.gz
cd frp_0.58.0_linux_amd64
# 内网服务器(客户端)
# 同样操作,或者用scp从公网服务器传过去
scp root@123.123.123.123:/root/frp_0.58.0_linux_amd64.tar.gz ./
tar -zxvf frp_0.58.0_linux_amd64.tar.gz
cd frp_0.58.0_linux_amd64
# Mac客户端(也是客户端,用于SSH连接)
# 下载macOS版本
wget https://github.com/fatedier/frp/releases/download/v0.58.0/frp_0.58.0_darwin_amd64.tar.gz
tar -zxvf frp_0.58.0_darwin_amd64.tar.gz
cd frp_0.58.0_darwin_amd64
frp从0.52版本开始改用TOML格式配置文件,不再支持ini。注意版本兼容性。
# frps.toml - 公网服务器配置
bindPort = 7000 # frp控制端口,客户端连接用
bindAddr = "0.0.0.0" # 监听所有网卡
# Web管理界面(可选,强烈建议开启)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "your_strong_password_here"
# 认证令牌,客户端必须匹配
auth.token = "your_secret_token_here"
# 日志配置
log.to = "./frps.log"
log.level = "info"
log.maxDays = 3
# 连接池配置
transport.poolCount = 10
内网服务器上配置,把SSH、MySQL、Redis都穿透出去。
# frpc.toml - 内网服务器配置
serverAddr = "123.123.123.123" # 公网服务器IP
serverPort = 7000
auth.token = "your_secret_token_here"
# SSH穿透 - 远程开发核心
[[proxies]]
name = "ssh-dev"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000 # 公网服务器上暴露的端口
# MySQL穿透
[[proxies]]
name = "mysql-dev"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3306
remotePort = 6001
# Redis穿透
[[proxies]]
name = "redis-dev"
type = "tcp"
localIP = "127.0.0.1"
localPort = 6379
remotePort = 6002
# HTTP服务穿透(比如你的开发环境有Web界面)
[[proxies]]
name = "web-dev"
type = "http"
localIP = "127.0.0.1"
localPort = 8080
customDomains = ["dev.yourdomain.com"] # 需要DNS解析到公网服务器
# 公网服务器启动frps
cd frp_0.58.0_linux_amd64
./frps -c frps.toml &
# 检查是否启动成功
netstat -tlnp | grep 7000 # 应该看到LISTEN
netstat -tlnp | grep 7500 # Web管理界面
# 内网服务器启动frpc
cd frp_0.58.0_linux_amd64
./frpc -c frpc.toml &
# 查看日志
tail -f frpc.log
在MacBook上测试SSH连接:
# 通过frp隧道连接内网服务器
ssh -p 6000 user@123.123.123.123
# 配置SSH config简化连接(~/.ssh/config)
Host dev-server
HostName 123.123.123.123
Port 6000
User your_username
IdentityFile ~/.ssh/id_rsa
ServerAliveInterval 60
ServerAliveCountMax 3
# 之后直接 ssh dev-server 即可
生产环境必须用systemd管理,否则进程挂了都不知道。
# 公网服务器 - 创建frps服务
sudo vim /etc/systemd/system/frps.service
[Unit]
Description=Frp Server Service
After=network.target
[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/root/frp_0.58.0_linux_amd64/frps -c /root/frp_0.58.0_linux_amd64/frps.toml
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
# 内网服务器 - 创建frpc服务(内容类似,路径改一下)
sudo vim /etc/systemd/system/frpc.service
[Unit]
Description=Frp Client Service
After=network.target
[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/home/user/frp_0.58.0_linux_amd64/frpc -c /home/user/frp_0.58.0_linux_amd64/frpc.toml
[Install]
WantedBy=multi-user.target
# 启用并启动
sudo systemctl enable frps
sudo systemctl start frps
sudo systemctl status frps
测试工具:iperf3(带宽测试)、ping(延迟测试)、MySQL Workbench(数据库查询测试)。
| 场景 | 平均延迟(ms) | 最大延迟(ms) | 丢包率 |
|---|---|---|---|
| 公司内网直连 | 0.5 | 1.2 | 0% |
| frp隧道(家里) | 8.3 | 15.6 | 0.1% |
| TeamViewer远程桌面 | 210 | 450 | 5% |
| Ngrok免费版 | 195 | 380 | 2% |
frp延迟8ms,完全满足SSH编辑代码的需求,VSCode Remote-SSH几乎感觉不到延迟。
# 内网服务器启动iperf3服务端
iperf3 -s -p 5201
# 家里客户端通过frp隧道测试(注意frp要配置iperf3端口穿透)
iperf3 -c 123.123.123.123 -p 6003 -t 30
# 结果:
[ ID] Interval Transfer Bitrate
[ 5] 0.00-30.00 sec 16.8 MBytes 4.70 Mbits/sec
[ 5] 0.00-30.00 sec 16.8 MBytes 4.70 Mbits/sec
# 对比:Ngrok免费版
iperf3 -c 2.tcp.ngrok.io -p 12345 -t 30
[ ID] Interval Transfer Bitrate
[ 5] 0.00-30.00 sec 3.75 MBytes 1.05 Mbits/sec
frp几乎跑满了5Mbps带宽(利用率94%),Ngrok只有1Mbps(被限速)。
测试查询:SELECT * FROM orders WHERE created_at > '2024-01-01' LIMIT 1000(orders表50万行数据)。
| 连接方式 | 查询耗时(ms) | 数据传输时间(ms) |
|---|---|---|
| 内网直连 | 45 | 12 |
| frp隧道 | 58 | 25 |
| Ngrok | 320 | 280 |
frp隧道额外增加约26ms开销,完全可以接受。Ngrok因为带宽限制,数据传输时间暴涨。
公网服务器配置好frps后,客户端一直连不上。排查了半小时,发现阿里云安全组没放行7000、6000-6002端口。还有系统防火墙(firewalld)默认是开启的。
# 阿里云控制台:安全组 → 入方向 → 添加规则
# 放行 TCP:7000,6000-6002,7500
# 系统防火墙
sudo firewall-cmd --zone=public --add-port=7000/tcp --permanent
sudo firewall-cmd --zone=public --add-port=6000-6002/tcp --permanent
sudo firewall-cmd --zone=public --add-port=7500/tcp --permanent
sudo firewall-cmd --reload
第一次配置用了弱密码"123456",结果第二天发现frp Web管理界面被登录,有人扫描端口。赶紧改了强密码,并限制Web管理界面只允许内网访问。
# frps.toml 安全加固
webServer.addr = "127.0.0.1" # 只监听本地,通过SSH隧道访问
# 或者用nginx反向代理加HTTPS
家里网络不稳定,SSH连接经常掉线。加了心跳配置后解决。
# 客户端SSH配置
Host dev-server
ServerAliveInterval 30 # 每30秒发一个心跳包
ServerAliveCountMax 3 # 连续3次无响应则断开
TCPKeepAlive yes
一开始下载了frp 0.51.0,配置文件是ini格式。后来升级到0.58.0,发现配置格式变了。注意:0.52版本开始改用TOML,0.50及之前用ini。升级时一定要看Release Notes。
# 查看当前版本
./frps --version
# frps version 0.58.0
# 旧版ini配置示例(0.50及之前)
[common]
bind_port = 7000
token = 123456
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
有一次同事用frp传输大文件(5GB数据库备份),把5Mbps带宽占满,导致我的SSH操作卡顿。解决方案:限速。
# frpc.toml 对特定代理限速
[[proxies]]
name = "file-transfer"
type = "tcp"
localIP = "127.0.0.1"
localPort = 9999
remotePort = 6005
transport.bandwidthLimit = "2MB" # 限制2MB/s
frp的Web管理界面默认监听0.0.0.0:7500,没有HTTPS,密码明文传输。建议用nginx反向代理加SSL,或者只监听127.0.0.1通过SSH隧道访问。
# 通过SSH隧道访问Web管理界面
ssh -L 7500:127.0.0.1:7500 root@123.123.123.123
# 然后浏览器打开 http://127.0.0.1:7500
团队多人需要连接不同的内网服务器,可以在frps上配置多个代理,每个客户端用不同的remotePort。
# frpc.toml - 同事A的配置
serverAddr = "123.123.123.123"
serverPort = 7000
auth.token = "team_token"
[[proxies]]
name = "ssh-dev-a"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6010 # 不同端口
# frpc.toml - 同事B的配置
[[proxies]]
name = "ssh-dev-b"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6011 # 不同端口
STCP模式只允许特定的客户端访问,需要双方都配置相同的secretKey。
# frpc.toml - 内网服务器
[[proxies]]
name = "ssh-stcp"
type = "stcp"
localIP = "127.0.0.1"
localPort = 22
secretKey = "your_secret_key"
# frpc.toml - 家里客户端(也需要运行frpc)
[[visitors]]
name = "ssh-stcp-visitor"
type = "stcp"
serverName = "ssh-stcp"
secretKey = "your_secret_key"
bindAddr = "127.0.0.1"
bindPort = 2222
用Prometheus + Grafana监控frp运行状态。frp从0.52版本开始支持Prometheus指标导出。
# frps.toml 开启监控
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.enablePrometheus = true # 开启Prometheus指标
# 访问 http://123.123.123.123:7500/metrics 查看指标
frp是目前搭建远程开发环境最靠谱的方案,没有之一。只要你有台公网服务器(最低配轻量云30元/月),就能获得接近内网直连的开发体验。延迟8ms、带宽利用率94%,比Ngrok、ZeroTier强太多。
关键点:版本选对(0.58.0)、防火墙放行、心跳保活、安全加固。照着本文一步步来,半小时内就能跑起来。
最后说一句:别在公网暴露22端口,用frp的隧道端口(如6000)更安全,因为攻击者扫描不到你的真实SSH端口。
专注技术分享与实战