摘要
本文档详细记录了使用 FRP(Fast Reverse Proxy)v0.64.0 实现三机网络架构下的内网穿透方案。通过在公网云服务器部署 FRP 服务端,成功将内网 Windows 机器上运行的 HTTP 服务暴露至公网,实现跨网络访问。本方案采用 TCP 代理模式,无需域名配置,适用于快速部署和测试环境。
关键词:内网穿透、反向代理、FRP、TCP 转发、跨网络通信
1. 背景与需求
1.1 网络拓扑
本方案涉及三台机器的协同工作:
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ 请求机 │ │ 云端服务器 │ │ Windows │
│ (Client) │────────>│ (frps) │<────────│ 响应机 │
│ │ 公网访问 │ <公网IP> │ 内网连接 │ (frpc) │
└─────────────┘ └──────────────────┘ └─────────────┘
① ② ③
发起请求 转发中继 提供服务
1.2 技术挑战
- Windows 响应机位于内网环境,无公网 IP
- 请求机需要通过公网访问响应机的服务
- 无可用域名,需直接通过 IP 访问
- 服务端点为
http://127.0.0.1:PORT/api_endpoint
2. 解决方案设计
2.1 技术选型
FRP (Fast Reverse Proxy) v0.64.0
- 开源高性能反向代理工具
- 支持 TCP、UDP、HTTP、HTTPS 多种协议
- 配置简单,跨平台支持
2.2 代理模式选择
| 模式 | 适用场景 | 是否需要域名 | 配置复杂度 |
|---|---|---|---|
| HTTP | 多服务虚拟主机 | ✅ 必需 | 中 |
| TCP | 单服务直连 | ❌ 不需要 | 低 |
| HTTPS | 加密传输 | ✅ 必需 + SSL证书 | 高 |
最终选择:TCP 模式(无域名需求,配置简洁)
3. 实施方案
3.1 架构设计
数据流向:
请求机 → http://<云端IP>:<暴露端口>/api_endpoint
↓ (公网)
云端服务器 frps (TCP 端口监听)
↓ (加密隧道)
Windows 响应机 frpc (连接云端控制端口)
↓ (本地转发)
本地服务 http://127.0.0.1:<本地端口>/api_endpoint
3.2 端口规划
| 端口 | 用途 | 绑定位置 | 协议 |
|---|---|---|---|
| 7000 | FRP 控制通道 | 云端服务器 | TCP |
| 8080 | HTTP 服务暴露端口 | 云端服务器(动态监听) | TCP |
| 8080 | 本地 HTTP 服务 | Windows 响应机 | HTTP |
4. 配置详解
4.1 云端服务器配置(frps)
4.1.1 配置文件 frps.toml
# FRP 服务端配置
bindPort = 7000 # 控制通道端口
auth.token = "your_secure_token" # 认证令牌(需与客户端一致)
配置说明:
bindPort:客户端连接的控制端口,用于维持长连接auth.token:身份验证令牌,防止未授权访问- 无需配置业务端口 :TCP 模式下由客户端
remotePort动态指定
4.1.2 启动命令
# Linux 环境
cd /path/to/frp
./frps -c frps.toml
# 预期输出
[I] [server/service.go:237] frps tcp listen on 0.0.0.0:7000
[I] [frps/root.go:117] frps started successfully
4.1.3 防火墙配置
# CentOS/RHEL
firewall-cmd --permanent --add-port=7000/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload
# Ubuntu/Debian
ufw allow 7000/tcp
ufw allow 8080/tcp
4.2 Windows 响应机配置(frpc)
4.2.1 配置文件 frpc.toml
# FRP 客户端配置
serverAddr = "<云端服务器IP>" # 云端服务器公网 IP
serverPort = 7000 # 连接云端的控制端口
auth.token = "your_secure_token" # 认证令牌(与服务端一致)
# 代理规则
[[proxies]]
name = "web_service" # 代理名称(唯一标识)
type = "tcp" # 代理类型:TCP 模式
localIP = "127.0.0.1" # 本地服务地址
localPort = 8080 # 本地服务端口
remotePort = 8080 # 云端监听端口(对外暴露)
配置说明:
serverAddr:云端服务器的公网 IP 地址remotePort:告诉服务端在哪个端口监听外部请求localIP+localPort:指向本地实际运行的服务auth.token:必须与服务端完全一致(包括大小写)
4.2.2 启动命令
# Windows PowerShell
cd C:\frp\frp_0.64.0_windows_amd64
.\frpc.exe -c frpc.toml
# 预期输出
[I] [service.go:xxx] login to server success
[I] [proxy/proxy.go:xxx] [web_service] start proxy success
4.3 请求机访问方式
# 方式1:命令行测试
curl http://<云端IP>:8080/api_endpoint
# 方式2:浏览器访问
http://<云端IP>:8080/api_endpoint
# 方式3:带参数请求
curl -X POST http://<云端IP>:8080/api_endpoint \
-H "Content-Type: application/json" \
-d '{"data": "test"}'
5. 关键技术点
5.1 TCP 模式与 HTTP 模式对比
# ❌ HTTP 模式(需要域名)
[[proxies]]
type = "http"
customDomains = ["api.example.com"] # 必需
# 服务端需配置: vhostHTTPPort = 8080
# ✅ TCP 模式(无需域名)
[[proxies]]
type = "tcp"
remotePort = 8080 # 直接指定端口
# 服务端自动监听此端口
5.2 路径透传机制
FRP 作为透明代理,完整保留 HTTP 请求的所有信息:
请求:http://<云端IP>:8080/api_endpoint?id=123
↓ (FRP 透传)
到达:http://127.0.0.1:8080/api_endpoint?id=123
保留内容:
✅ 请求路径 (/api_endpoint)
✅ Query 参数 (?id=123)
✅ HTTP 方法 (GET/POST)
✅ Request Headers
✅ Request Body
无需在配置中指定路径,所有 HTTP 细节自动转发。
5.3 动态端口监听
客户端启动 → 连接服务端7000端口 → 发送代理配置 (remotePort=8080)
↓
服务端动态监听8080端口
↓
外部请求 → 8080 → 转发到客户端
服务端日志验证:
[I] [proxy/tcp.go:xxx] [web_service] tcp proxy listen port [8080]
6. 故障排查
6.1 常见问题
问题1:客户端连接失败
[E] [client/control.go:xxx] connect to server error
排查步骤:
# 1. 测试网络连通性
ping <云端服务器IP>
# 2. 测试端口可达性
telnet <云端服务器IP> 7000
# 或
nc -zv <云端服务器IP> 7000
# 3. 检查服务端防火墙
firewall-cmd --list-ports
问题2:认证失败
[E] [client/control.go:xxx] authorization failed
解决方案:
- 确保客户端和服务端
auth.token完全一致 - 检查是否有多余空格或隐藏字符
- 区分大小写
问题3:端口被占用
[E] [server/service.go:xxx] listen tcp :8080: bind: address already in use
检查方法:
# Linux
netstat -tlnp | grep 8080
lsof -i :8080
# Windows
netstat -ano | findstr 8080
6.2 验证清单
- 云端服务器防火墙已开放 7000 和 8080 端口
- Windows 本地服务
http://127.0.0.1:8080/api_endpoint正常访问 - frps 日志显示
frps started successfully - frpc 日志显示
start proxy success - 服务端出现
tcp proxy listen port [8080] - 外部可访问
http://<云端IP>:8080/api_endpoint
7. 安全加固建议
7.1 基础安全
# 使用强密码(推荐32位随机字符串)
auth.token = "ABCdef123456!@#$%^&*()_+Random"
# 限制允许的端口范围(可选)
allowPorts = [8080, 8081, 8082]
7.2 进阶防护
# 使用 iptables 限制来源IP
iptables -A INPUT -p tcp --dport 8080 -s <允许的IP段> -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP
# 配置 TLS 加密(推荐生产环境)
# frps.toml
transport.tls.enable = true
transport.tls.certFile = "/path/to/cert.pem"
transport.tls.keyFile = "/path/to/key.pem"
7.3 生产环境建议
- 使用域名 + HTTPS:避免直接暴露 IP
- 配置 Nginx 反向代理:添加访问控制和日志
- 限流保护:防止 DDoS 攻击
- 日志监控:定期审计访问记录
- 定期更换令牌:降低泄露风险
8. 性能优化
8.1 连接池配置
# frpc.toml
transport.poolCount = 5 # 连接池大小
transport.tcpMux = true # 启用多路复用
transport.heartbeatInterval = 30 # 心跳间隔(秒)
transport.heartbeatTimeout = 90 # 心跳超时(秒)
8.2 压缩传输
# 适用于文本传输
[[proxies]]
name = "web_service"
type = "tcp"
useCompression = true # 启用压缩(适合JSON/HTML)
8.3 带宽限制
# 限制单个代理的带宽
[[proxies]]
name = "web_service"
type = "tcp"
bandwidthLimit = "1MB" # 限制带宽为1MB/s
9. 服务管理
9.1 系统服务配置(Linux)
# 创建 systemd 服务
cat > /etc/systemd/system/frps.service << 'EOF'
[Unit]
Description=FRP Server Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=frp
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
EOF
# 创建专用用户
useradd -r -s /sbin/nologin frp
# 启用服务
systemctl daemon-reload
systemctl enable frps
systemctl start frps
systemctl status frps
9.2 Windows 后台运行
方法1:使用 NSSM
# 下载 NSSM: https://nssm.cc/download
nssm install frpc "C:\frp\frpc.exe" "-c" "C:\frp\frpc.toml"
nssm set frpc AppDirectory "C:\frp"
nssm set frpc DisplayName "FRP Client Service"
nssm start frpc
方法2:使用任务计划程序
# 创建启动时运行的任务
$action = New-ScheduledTaskAction -Execute "C:\frp\frpc.exe" -Argument "-c C:\frp\frpc.toml"
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName "FRP Client" -Action $action -Trigger $trigger -Principal $principal
10. 日志管理
10.1 日志配置
# frps.toml - 服务端日志
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 7
# frpc.toml - 客户端日志
log.to = "C:\\frp\\logs\\frpc.log"
log.level = "info"
log.maxDays = 3
10.2 日志轮转(Linux)
# /etc/logrotate.d/frps
/var/log/frps.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
postrotate
systemctl reload frps > /dev/null 2>&1 || true
endscript
}
11. 监控与告警
11.1 健康检查配置
# frpc.toml
[[proxies]]
name = "web_service"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8080
# 健康检查
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 3
healthCheck.intervalSeconds = 10
healthCheck.maxFailed = 3
11.2 监控脚本示例
#!/bin/bash
# frps_monitor.sh - 监控 FRP 服务状态
SERVICE="frps"
EMAIL="admin@example.com"
if ! systemctl is-active --quiet $SERVICE; then
echo "FRP服务已停止,尝试重启..." | mail -s "FRP告警" $EMAIL
systemctl restart $SERVICE
sleep 5
if systemctl is-active --quiet $SERVICE; then
echo "FRP服务重启成功" | mail -s "FRP恢复" $EMAIL
else
echo "FRP服务重启失败,需要人工介入" | mail -s "FRP严重告警" $EMAIL
fi
fi
添加到 crontab:
# 每5分钟检查一次
*/5 * * * * /usr/local/bin/frps_monitor.sh
12. 实施总结
12.1 成功要素
✅ 配置简洁 :TCP 模式无需域名,降低部署难度
✅ 透明转发 :完整保留 HTTP 请求细节(路径、参数、Headers)
✅ 动态监听 :服务端根据客户端配置自动创建监听端口
✅ 跨平台支持 :Linux 服务端 + Windows 客户端无缝协作
✅ 断线重连:内置心跳机制,网络波动自动恢复
12.2 最终效果
外部访问:http://<云端IP>:8080/api_endpoint
内部实际:http://127.0.0.1:8080/api_endpoint (Windows 内网)
延迟增加:约 10-50ms(取决于网络质量)
稳定性:长连接保持,断线自动重连
吞吐量:取决于云服务器带宽和本地上行速度
12.3 适用场景
- ✅ 开发测试环境快速暴露内网服务
- ✅ 家庭服务器对外提供服务
- ✅ 临时演示项目给客户端访问
- ✅ IoT 设备数据回传
- ✅ 远程办公访问公司内网资源
- ⚠️ 不适合高并发生产环境(建议使用专业 CDN)
13. 进阶配置示例
13.1 多服务代理
# frpc.toml - 同时代理多个服务
serverAddr = "<云端IP>"
serverPort = 7000
auth.token = "your_secure_token"
# 服务1:Web API
[[proxies]]
name = "web_api"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8080
# 服务2:数据库
[[proxies]]
name = "database"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3306
remotePort = 13306
# 服务3:SSH
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 2222
13.2 带域名的 HTTP 代理
# frps.toml
bindPort = 7000
vhostHTTPPort = 80
auth.token = "your_secure_token"
# frpc.toml
[[proxies]]
name = "web_http"
type = "http"
localIP = "127.0.0.1"
localPort = 8080
customDomains = ["api.yourdomain.com"]
访问方式:http://api.yourdomain.com/api_endpoint
14. 参考资料
- FRP 官方文档 :https://github.com/fatedier/frp
- TOML 配置格式 :https://toml.io/
- 网络调试工具 :
curl、telnet、tcpdump、wireshark - 防火墙管理 :
firewalld、iptables、ufw
附录:完整配置文件模板
A.1 服务端配置(最简版)
# frps.toml
bindPort = 7000
auth.token = "your_secure_token_here"
A.2 服务端配置(完整版)
# frps.toml
bindPort = 7000
auth.token = "your_secure_token_here"
# 日志配置
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 7
# 性能优化
transport.maxPoolCount = 10
transport.tcpMux = true
# Dashboard(可选)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin_password"
A.3 客户端配置(最简版)
# frpc.toml
serverAddr = "<云端服务器IP>"
serverPort = 7000
auth.token = "your_secure_token_here"
[[proxies]]
name = "web_service"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8080
A.4 客户端配置(生产版)
# frpc.toml
serverAddr = "<云端服务器IP>"
serverPort = 7000
auth.token = "your_secure_token_here"
# 日志配置
log.to = "./logs/frpc.log"
log.level = "info"
log.maxDays = 3
# 连接优化
transport.poolCount = 5
transport.tcpMux = true
transport.heartbeatInterval = 30
transport.heartbeatTimeout = 90
# 代理配置
[[proxies]]
name = "web_service"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8080
# 健康检查
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 3
healthCheck.intervalSeconds = 10
healthCheck.maxFailed = 3
# 压缩和带宽限制
useCompression = true
bandwidthLimit = "5MB"
附录:快速故障诊断表
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 客户端无法连接服务端 | 防火墙阻止 | 检查防火墙规则和云安全组 |
| 认证失败 | Token 不匹配 | 确保 auth.token 完全一致 |
| 外部无法访问服务 | 端口未开放 | 检查服务端防火墙和云安全组 |
| 连接频繁断开 | 心跳超时 | 调整 heartbeatInterval 参数 |
| 服务端端口被占用 | 其他程序占用 | 使用 netstat 查找并关闭占用进程 |
| 本地服务无响应 | 服务未启动 | 检查本地服务状态 |
| 数据传输缓慢 | 带宽限制 | 检查网络带宽和 bandwidthLimit 配置 |
文档版本 :v2.0
最后更新 :2025-11-21
验证状态 :✅ 已在生产环境验证
安全等级:🔒 已脱敏处理