基于 FRP 实现内网穿透的跨网络 HTTP 服务转发方案

摘要

本文档详细记录了使用 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 生产环境建议

  1. 使用域名 + HTTPS:避免直接暴露 IP
  2. 配置 Nginx 反向代理:添加访问控制和日志
  3. 限流保护:防止 DDoS 攻击
  4. 日志监控:定期审计访问记录
  5. 定期更换令牌:降低泄露风险

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. 参考资料


附录:完整配置文件模板

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
验证状态 :✅ 已在生产环境验证
安全等级:🔒 已脱敏处理

相关推荐
代码不停28 分钟前
网络编程 UDP 和 TCP
网络·tcp/ip·udp
重启的码农30 分钟前
enet源码解析(5)事件驱动服务 (Event Service)
c++·网络协议
重启的码农32 分钟前
enet源码解析(6)协议处理逻辑 (Protocol Processing)
c++·网络协议
凯子坚持 c1 小时前
Doubao-Seed-Code模型深度剖析:Agentic Coding在Obsidian插件开发中的应用实践
网络·人工智能
小尧嵌入式1 小时前
基于HAL库实现ETH以太网
网络·arm开发·stm32·单片机·嵌入式硬件
元气满满-樱1 小时前
思科:路由条目优化实验
网络·智能路由器
tan180°1 小时前
Linux网络IP(下)(16)
linux·网络·后端·tcp/ip
视觉震撼2 小时前
本地机器远程连接配置与文件传输可行性检测工具
运维·服务器·网络·windows·php·apache
韩师学子--小倪2 小时前
http status 400 bad request
http