用 frp 实现家用 Windows 远程桌面内网穿透:从零到可用的完整实践

本文记录一次真实的内网穿透部署过程:用一台云服务器作为 frp 服务端,把家里 Windows 电脑的远程桌面(RDP)安全地暴露到公网。服务端与客户端均已实际部署、长期运行,文内所有踩坑均为实录。

一、为什么需要内网穿透?

家里电脑通常在路由器后面,只有运营商分配的内网 IP(如 192.168.x.x),公网无法直接访问。想在外部连回家里的电脑,常见方案有:

方案 优点 缺点
路由器端口映射 零成本 需要公网 IP,多数家宽没有;且运营商可能封 80/443
TeamViewer / 向日葵 零配置 免费版限速、限商业用途、需信任第三方
Tailscale / ZeroTier 组网优雅、P2P 直连 两端都要装客户端,手机端支持一般
frp 自建 完全可控、带宽自建、不限速 需要一台有公网 IP 的服务器

frp(Fast Reverse Proxy)是一个高性能的反向代理工具,采用 Go 编写,单一二进制文件,部署极其简单。本次选择它,理由是:已有云服务器、需要完全掌控数据、不想受第三方限速。

二、架构设计

frp 内网穿透架构图:外部设备经云服务器代理端口,通过 frp 隧道访问家里 Windows 的远程桌面
整体数据流:外部请求打到云服务器的代理端口,frps 通过 frpc 主动建立的控制隧道转发回家里电脑的本机端口

关键设计决策:

决策 选择 理由
服务端部署方式 宿主机 systemd(非 Docker) frps 仅 20MB 二进制,省一层网络转换,资源占用更低
RDP 对外端口 33390 避开默认 3389 的扫描;低于 49152(Windows 动态端口范围)不冲突
认证方式 token 简单可靠,够用
面板 仅监听 127.0.0.1 不占公网端口,通过 SSH 隧道访问,零暴露面
端口白名单 精确单端口 {33390} 纵深防御,token 泄露时限制破坏面

三、前置条件

服务端(云服务器):

  • 一台有公网 IP 的 Linux 服务器(本文以 Ubuntu 22.04 为例)
  • 建议配置:1 核 1GB 起够用,frps 本身极轻量
  • 能放行端口的防火墙(云厂商安全组 + 系统防火墙)

客户端(家里 Windows):

  • Windows 10/11 专业版(家庭版默认不支持 RDP 被控)
  • 远程桌面功能——别假设它是开着的,本文实机就是关的,见 5.2 节

四、服务端部署(frps)

4.1 放行防火墙端口

在云厂商控制台(安全组/防火墙)放行以下端口:

端口 用途 是否必须对公网
7000 frps 控制端口(frpc 连接用) ✅ 是
33390 RDP 对外代理端口 ✅ 是

💡 面板 7500 不需要放行,它只监听 127.0.0.1。

4.2 下载并安装 frp

# 下载最新版(本文使用 v0.61.2)
cd /tmp
wget https://github.com/fatedier/frp/releases/download/v0.61.2/frp_0.61.2_linux_amd64.tar.gz -O frp.tar.gz

# 解压
tar -xzf frp.tar.gz

# 安装到 /opt/frp
sudo mkdir -p /opt/frp /etc/frp
sudo cp frp_0.61.2_linux_amd64/frps /opt/frp/
sudo cp frp_0.61.2_linux_amd64/frpc /opt/frp/   # frpc 也留着,调试有用
sudo chmod +x /opt/frp/frps /opt/frp/frpc

# 验证
/opt/frp/frps --version
# 输出:0.61.2

4.3 生成安全凭证

# 生成 frp token(64 位十六进制)
openssl rand -hex 32

# 生成面板密码(32 位十六进制)
openssl rand -hex 16

把输出保存好,后面配置要用到。这两个值一旦泄露,等于把内网通道交给别人。

4.4 编写配置文件

创建 /etc/frp/frps.toml:

# ===== 基础绑定 =====
bindAddr = "0.0.0.0"
bindPort = 7000

# ===== 鉴权 =====
auth.method = "token"
auth.token = "在此填入你生成的64位token"

# ===== 传输优化(RDP 友好) =====
transport.tcpMux = true
transport.tcpMuxKeepaliveInterval = 30
transport.tcpKeepalive = 7200

# ===== 对外代理端口白名单(精确收紧,纵深防御) =====
allowPorts = [
  { single = 33390 }
]

# ===== Web 管理面板(仅本地监听,不暴露公网) =====
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "在此填入面板密码"

# ===== 日志 =====
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 14

# ===== 连接限制 =====
transport.maxPoolCount = 10

设置权限并验证语法:

sudo chmod 640 /etc/frp/frps.toml
sudo chown root:root /etc/frp/frps.toml

# 语法验证(很实用,能提前发现配置错误)
sudo /opt/frp/frps verify -c /etc/frp/frps.toml
# 输出:frps: the configuration file /etc/frp/frps.toml syntax is ok

关于 allowPorts:为什么不用端口范围?

很多人图省事写成 { start = 10000, end = 20000 },留一万多个端口备用。但这有安全隐患:

allowPorts 拦的是已经通过 token 认证的 frpc。正常情况下 frpc 只开配置里写的端口,白名单形同虚设;但一旦 token 泄露,攻击者就能连上来开任意端口做内网横向移动——一万端口等于送他一万个入口。

收紧成精确单端口后,即使 token 泄露,攻击者也只能开这一个端口。成本几乎为零(以后加代理改一次配置重启即可),收益明显。

4.5 创建 systemd 服务

创建 /etc/systemd/system/frps.service:

[Unit]
Description=frp server (frps)
After=network.target network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/frp/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576

# 安全加固
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log /etc/frp

[Install]
WantedBy=multi-user.target

启动并设置开机自启:

sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo systemctl status frps

看到 Active: active (running) 即成功。

4.6 验证服务端

# 检查端口监听
sudo ss -tlnp | grep -E "(7000|7500)"
# 期望:
# LISTEN  ... 127.0.0.1:7500 ...   (面板,仅本地)
# LISTEN  ... *:7000       ...     (控制端口,公网)

# 测试本地连通性
nc -zv 127.0.0.1 7000
nc -zv 127.0.0.1 7500

# 测试面板 API
curl -s -u admin:你的面板密码 http://127.0.0.1:7500/api/serverinfo

API 返回 JSON 且包含 "version":"0.61.2" 说明一切正常。

查看实际资源占用:

ps -o pid,rss,cmd -p $(pgrep frps)

实测:约 17~20 MB 内存,CPU 接近 0%。frps 极其轻量,1GB 内存的机器也毫无压力。

五、客户端部署(Windows 上的 frpc)

以下为在家用 Windows 电脑上实际执行过的完整流程,按顺序照做即可复现。全程使用「以管理员身份」打开的 PowerShell(Win → 输入 powershell → Ctrl+Shift+Enter)。

5.0 目录规划

C:\frp\
├── bin\frpc.exe      ← 客户端主程序
├── nssm.exe          ← 服务托管工具(后面用)
└── frpc.toml         ← 配置文件

5.1 下载 frpc

cd C:\
Invoke-WebRequest -Uri "https://github.com/fatedier/frp/releases/download/v0.61.2/frp_0.61.2_windows_amd64.zip" -OutFile frp.zip
Expand-Archive frp.zip -DestinationPath C:\frp
Rename-Item C:\frp\frp_0.61.2_windows_amd64 C:\frp\bin

国内网络直连 GitHub 大概率超时,先挂好代理再下载(或用镜像源)。下载完确认 C:\frp\bin\frpc.exe 存在;包里的 frps.exe 是服务端程序,Windows 上用不上,可删。

5.2 第一步:先确认远程桌面功能本身是开着的

实机(Windows 10 专业版)远程桌面默认是关闭的:注册表 fDenyTSConnections = 1,3389 无监听。如果跳过这步直接往下配,frpc 隧道打通了也连不上——这是最靠后才发现、排查最烦的一类问题,所以放在最前面。

# 图形界面方式:设置 → 系统 → 远程桌面 → 启用(专业版)

# 或注册表方式:
Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Terminal Server" -Name fDenyTSConnections -Value 0

# 同时开启 NLA(网络级别身份验证,强烈推荐)
Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" -Name UserAuthentication -Value 1

注意:用注册表方式开启后,GUI 里”远程桌面”开关同步生效,但防火墙规则要自己确认;GUI 开关则会自动创建。验证方式:Get-NetTCPConnection -LocalPort 3389 -State Listen 有输出即监听成功。建议先确认 3389 通了,再进入改端口的步骤——一次只改一个变量,排错面小。

5.3 修改 Windows RDP 监听端口(可选但推荐)

⚠️ 务必在电脑本机操作,不要用远程桌面连着改——改端口会重启远程桌面服务,远程连接会立刻断开。

# 1. 修改注册表(3389 → 33390)
reg add "HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 33390 /f

# 2. 验证
Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" -Name PortNumber
# 应输出:PortNumber : 33390

# 3. 防火墙放行新端口(见第七节:更推荐收成 LocalOnly 版本)
New-NetFirewallRule -DisplayName "RDP-33390" -Direction Inbound -Protocol TCP -LocalPort 33390 -Action Allow

# 4. 删除旧规则(按系统语言,规则名可能不同)
Remove-NetFirewallRule -DisplayName "远程桌面(TCP-In)" -ErrorAction SilentlyContinue
Remove-NetFirewallRule -DisplayName "Remote Desktop (TCP-In)" -ErrorAction SilentlyContinue

💥 实录大坑:改完端口执行 Restart-Service TermService -Force 后,服务状态显示 Running,但新端口不监听(3389 也没了)。改端口后的 RDP 监听器只有在服务真正冷启动时才会用新值重建,原地重启服务大概率不生效。实测结论:改端口这类操作,做完注册表直接重启电脑最稳。重启后再 netstat -ano | findstr 33390 确认监听,再继续后面的步骤。

端口选择避坑:

端口 是否可用 原因
3389 ❌ 默认端口,扫描器必扫
3390/33890/13389/23389 ⚠️ 热门”替代端口”,扫描器同样会试
49152–65535 ❌ Windows 动态端口范围,系统出站会占用,会随机冲突
20000–49151 内的随机值 ✅ 推荐

老实说:改端口只挡盲扫,挡不了定向扫描。真正的主力防线是后面的强密码 + NLA。别把安全权重放反了。

5.4 编写 frpc.toml

在 C:\frp\frpc.toml:

# ===== 服务器连接信息 =====
serverAddr = "你的服务器公网IP"
serverPort = 7000

# ===== 鉴权(必须与服务端一致) =====
auth.method = "token"
auth.token = "服务端生成的64位token"

# ===== 传输优化 =====
transport.tcpMux = true
transport.tcpMuxKeepaliveInterval = 30
transport.heartbeatInterval = 30
transport.heartbeatTimeout = 90

log.to = "C:\\frp\\frpc.log"
log.level = "info"
log.maxDays = 7

# ===== 本地面板(可选,查看代理状态) =====
webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "本地面板密码"

# ===== RDP 代理 =====
# localPort 必须与 Windows 注册表改的端口一致
[[proxies]]
name = "rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 33390
remotePort = 33390

5.5 首次手动测试

先别急着注册服务,手动跑一次确认能连上:

cd C:\frp
.\bin\frpc.exe -c frpc.toml

成功输出类似:

[I] [client/service.go:295] try to connect to server...
[I] [client/service.go:287] login to server success, get run id [xxxx]
[I] [proxy/proxy_manager.go:173] [xxxx] proxy added: [rdp]
[I] [client/control.go:170] [xxxx] [rdp] start proxy success

看到 start proxy success 就成功了,按 Ctrl+C 停止。

常见失败原因:

报错 原因 / 解决
connection refused 服务器防火墙没放行 7000;或本地网络屏蔽了非标准端口
auth failed token 不匹配,重新核对
port not allowed 服务端 allowPorts 没包含你的 remotePort
connect to local 127.0.0.1:33390 failed Windows RDP 端口还没改好(或没重启),检查 5.2 / 5.3 步

5.6 注册为 Windows 服务(开机自启)

用 NSSM(Non-Sucking Service Manager)把 frpc 注册为服务,比计划任务稳定得多。下载:https://nssm.cc/release/nssm-2.24.zip,取 win64\nssm.exe 放到 C:\frp\。

cd C:\frp

# 注册服务
.\nssm.exe install frpc "C:\frp\bin\frpc.exe" "-c C:\frp\frpc.toml"
.\nssm.exe set frpc DisplayName "frp Client (RDP Tunnel)"
.\nssm.exe set frpc Start SERVICE_AUTO_START

# 日志轮转(防止日志无限增长)
.\nssm.exe set frpc AppStdout "C:\frp\frpc_stdout.log"
.\nssm.exe set frpc AppStderr "C:\frp\frpc_stderr.log"
.\nssm.exe set frpc AppRotateFiles 1
.\nssm.exe set frpc AppRotateBytes 1048576

# 启动
.\nssm.exe start frpc
.\nssm.exe status frpc          # 应为 SERVICE_RUNNING

5.7 重启电脑 + 端到端验证(部署自检清单)

所有配置就绪后重启一次电脑(顺带解决 5.3 的端口重建问题),frpc 是自动启动,开机后无需任何操作。然后过一遍自检清单:

# ① 本机端口监听:RDP(33390) / frpc面板(7400)
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -in 33390,7400 }

# ② frpc 服务状态 + 日志
Get-Service frpc                                   # 应为 Running
Get-Content C:\frp\frpc.log -Tail 10
# 应看到:login to server success + [rdp] start proxy success

# ③ 端到端回环测试:在本机连"服务器的代理端口"
#    流量会走完整隧道(服务器 → frpc → 回到本机),能 TCP 握手成功即全链路通
Test-NetConnection 你的服务器公网IP -Port 33390

# ④ 浏览器打开本地面板看代理在线状态:http://127.0.0.1:7400

四关全过 = 链路就绪,接下来只剩安全加固(第七节)。

六、连接测试

在外部网络(手机热点、公司电脑)打开远程桌面连接:

电脑:    你的服务器公网IP:33390
用户名:  Windows 登录用户名
密码:    Windows 登录密码

提醒:RDP 走的也是 Windows 账户验证,同样受账户锁定策略约束(见第七节)——外部输错密码的次数和坐在电脑前输错是同一个计数器。

卡顿优化:在远程桌面客户端的”显示”设置里,把颜色深度降到 16 位、关闭桌面背景和字体平滑,能显著降低带宽占用。

七、安全加固(RDP 暴露公网必做)

按实际防护力排序(这点很重要,别把精力放错地方):

🥇 第一优先级:强密码 + NLA

# 开启 NLA(网络级别身份验证)
sysdm.cpl → 远程 → 勾选"仅允许运行使用网络级别身份验证的远程桌面的计算机连接(推荐)"

NLA 不会影响 frp 工作——frp 只转发 TCP 字节流,不解析 RDP 协议,NLA 握手是「客户端 ↔ Windows」端到端进行的。所有现代 RDP 客户端都支持 NLA。

密码要求:≥12 位,含大小写 + 数字 + 符号。

🥈 第二优先级:账户锁定策略(含两个实测坑)

路径:secpol.msc → 账户策略 → 账户锁定策略。三个参数的含义:锁定阈值(连续错几次锁)、锁定时间(锁多久)、锁定计数器重置(多久没输错就清零重算)。

坑一:两个工具显示的值可能对不上。全新工作站上 secpol.msc 显示阈值”0 次无效登录”(未配置),而 net accounts 显示阈值 10。以 net accounts 的输出为准判断当前生效值。

坑二(更重要):管理员账户默认豁免锁定!策略列表里有一项「允许管理员帐户锁定」,默认禁用——不启用它,你平时用来登录的管理员账户无论输错多少次都不会被锁,整套策略对最常见的账户形同虚设。必须手动改成「已启用」。

参数怎么选:网传”5 次锁 30 分钟”偏严——自己远程时输错几次就真被锁住干瞪眼;设 0(禁用)则等于给公网爆破开门。本文最终采用折中参数,把爆破限速到约 1.4 万次/天(无实用价值),而正常使用几乎无感:

# 管理员 PowerShell(secpol.msc 改也行)
net accounts /lockoutthreshold:50     # 50 次无效登录触发锁定
net accounts /lockoutduration:5       # 锁定 5 分钟自动解锁
net accounts /lockoutwindow:15        # 15 分钟无失败则计数清零
# "允许管理员帐户锁定" 在 secpol.msc 中改为已启用

🥈 补充:两条密码策略命令

# 1. 强制密码最小长度(防止以后改密码手滑设弱)
net accounts /minpwlen:12

# 2. 检查并修复账户的"需要密码"标志
#    用 net user 用户名 查看输出,若"需要密码"显示 No,
#    说明账户标志位允许空密码(隐患),执行:
net user 用户名 /passwordreq:yes

💡 想知道有没有人敲门:事件查看器 → Windows 日志 → 安全,筛选事件 ID 4625(登录失败),可看到每次失败的来源和账户名。

🥉 第三优先级:专用账户,禁用 Administrator 远程登录

# 新建专用远程账户
$pwd = ConvertTo-SecureString "你的强密码" -AsPlainText -Force
New-LocalUser -Name "remote" -Password $pwd
Add-LocalGroupMember -Group "Remote Desktop Users" -Member "remote"

补充:Windows 防火墙限制来源 IP

既然只有 frpc 需要连 RDP,可以限制为仅允许本机访问:

Remove-NetFirewallRule -DisplayName "RDP-33390"
New-NetFirewallRule -DisplayName "RDP-33390-LocalOnly" -Direction Inbound -Protocol TCP -LocalPort 33390 -RemoteAddress 127.0.0.1 -Action Allow

这样连同一 WiFi 下的其他设备都摸不到你的 RDP。

安全措施真实性价比参考

措施 防护力 说明
强密码 + NLA ★★★★★ 挡住 99% 爆破,主力防线
token 不泄露 ★★★★★ frp 根本,泄露即全线崩溃
云平台防火墙最小化 ★★★★☆ 第一道关口
防火墙限制来源 IP ★★★☆☆ 成本低收益高
账户锁定 + 管理员锁定启用 ★★★☆☆ 限速爆破;注意管理员默认豁免,必须手动启用
改非标端口 ★★☆☆☆ 防盲扫,防不了定向
allowPorts 收紧 ★★☆☆☆ 仅 token 泄露时才有意义

八、日常运维

服务端(Linux)

sudo systemctl status frps
sudo systemctl restart frps
sudo tail -f /var/log/frps.log

# 通过 SSH 隧道访问面板(在你自己的电脑上执行)
ssh -L 7500:127.0.0.1:7500 ubuntu@你的服务器IP
# 然后浏览器打开 http://127.0.0.1:7500

客户端(Windows)

Get-Service frpc                      # 查看状态
Restart-Service frpc                  # 重启
Get-Content C:\frp\frpc.log -Wait -Tail 30   # 实时日志

# 卸载服务(如需重装)
cd C:\frp
.\nssm.exe stop frpc
.\nssm.exe remove frpc confirm

九、带宽与性能实测

frps 资源占用(实测):内存 17~20 MB;CPU 接近 0%;磁盘 <50 MB。

真正的瓶颈是带宽:frp 的所有流量都要经过服务器的公网带宽弯一下。无论家里宽带上行多快,外部访问速度上限 ≈ 服务器带宽。

场景 体验
SSH / 命令行 ✅ 流畅
RDP 远程桌面(1080P) ✅ 可用,建议降画质到 720P/16位色
大文件传输 ⚠️ 受服务器带宽限制
视频串流 / 游戏 ❌ 不适合

结论:frp 适合远程桌面和命令行这类低带宽场景。NAS 大文件传输或视频串流需要更高带宽的服务器,或改用支持 P2P 打洞的方案(如 Tailscale)。

十、排错清单

现象 排查方向
frpc 连不上服务器 服务器防火墙 7000 没放行;本地网络屏蔽非标端口
auth failed token 前后不一致(注意别复制时带空格)
port not allowed 服务端 allowPorts 未包含该端口
frpc 连上了但 RDP 连不上 Windows RDP 功能没开(5.2);端口没改对;改端口后只 Restart-Service 没重启电脑(监听器不会用新端口重建)
RDP 能连但黑屏 Windows 锁屏;NVIDIA 独显可能需要虚拟显示器驱动
重启后没自动连上 Get-Service frpc 看状态;查 C:\frp\frpc_stdout.log
连接频繁断开 检查 heartbeatInterval/tcpKeepalive;家用 NAT 超时可能需调小
锁定策略改了不生效 ① 用 net accounts 看生效值(secpol 未配置时显示 0)② 管理员账户默认豁免锁定,需启用「允许管理员帐户锁定」

十一、总结

整个部署的核心步骤:

  1. 服务端:放行端口 → 装 frps → 写 frps.toml(token + 精确白名单 + 本地面板)→ systemd 托管
  2. 客户端:开 RDP + NLA → 改端口(改完重启电脑)→ 写 frpc.toml → NSSM 注册服务 → 端到端自检
  3. 安全:强密码 + NLA + 锁定策略(记得启用管理员锁定)+ minpwlen=12 + 专用账户——这几项比改端口重要得多
  4. 验证:本机端口监听(33390/7400)→ frpc 日志 [rdp] start proxy success → 回环测试 → 外部真连

资源开销几乎可以忽略(20MB 内存),真正的限制是服务器带宽。只要需求是远程桌面这类低带宽场景,这套方案稳定且完全自主可控。

本文基于 frp v0.61.2 实测部署整理,服务端与客户端流程均已实机全流程跑通。

顶部