远程办公、异地出差、回家后想连回公司电脑处理点急事,这类需求我每年都会碰到好几次。最省事的办法当然是让被控电脑直接暴露在公网,但大多数家庭宽带和企业内网都在 NAT 后面,没有独立公网 IP,直接连 3389 根本连不上。这时候就需要一套可靠的内网穿透方案:用 frp 在一台有公网 IP 的云主机上做转发入口,把内网 Windows 的远程桌面端口映射出去;如果追求更低的延迟和更少的公网流量,还可以利用 frp 的 xtcp 模式做 UDP 打洞,让访问端和被控端尝试点对点直连。这篇内容我就把这两条路线拆开,从原理、配置、实测到排错,完整走一遍。不管你用的是 Windows 10 还是 Windows 11,只要远程桌面能正常开启,跟着配下来基本都能用。
1. 整体方案设计与核心思路拆解
1.1 为什么选择 frp 加 UDP 打洞的组合
frp 是我用过的内网穿透工具里比较顺手的一个,它开源、配置文件简单,支持 TCP、UDP 转发,也支持 xtcp 这种点对点打洞模式。对于 Windows 远程桌面来说,默认走 TCP 3389,但 Windows 也会尝试 UDP 3389 来提升图形传输效率。如果只做 TCP 映射,所有流量都要经过公网服务器,延迟取决于服务器和你家宽带的距离,而且公网服务器的带宽会直接成为瓶颈。UDP 打洞的价值就在于,它让访问端和被控端在建立连接后尽可能直连,数据不再绕行公网服务器,延迟更低,服务器压力也更小。
当然,UDP 打洞不是万能的。它依赖双方 NAT 设备的类型,如果一方是 Symmetric NAT,打洞成功率会明显下降,这时候 frp 会自动回退到通过公网服务器转发,或者需要你改用 TCP 映射兜底。所以我的建议是:先配好 TCP 映射保证随时能连上,再叠加 xtcp 打洞作为优化项。这样即使打洞失败,远程桌面也不会断。
1.2 公网服务器、内网主机、访问端的角色分工
整个方案里有三个角色。第一个是公网服务器,它运行 frps,负责监听公网端口、验证客户端身份、在 TCP 映射模式下转发流量,在 UDP 打洞模式下充当信令交换点。第二个是被控的内网 Windows 主机,它运行 frpc,把本地的 3389 端口注册到 frps 上。第三个是访问端,可以是一台运行 frpc 的电脑,也可以直接通过远程桌面客户端连接公网服务器的映射端口。
如果你只用 TCP 映射,访问端不需要安装 frp,直接打开 Windows 自带的“远程桌面连接”,输入公网 IP 和映射端口就能连。如果你想用 xtcp 打洞,访问端也需要运行 frpc,并配置成 visitor 角色,它会在本地监听一个端口,然后你再用远程桌面连接这个本地端口。这样做的好处是访问端和被控端之间的数据可以走 P2P,公网服务器只负责牵线。
1.3 方案拓扑与数据流向
先看 TCP 映射模式的数据流向:访问端发起远程桌面连接,目标地址是公网服务器的 13389 端口;frps 收到连接后,根据端口找到对应的 frpc 会话,把流量转发给内网主机的 frpc;frpc 再把流量转给本地的 127.0.0.1:3389,也就是 Windows 的远程桌面服务。整个过程中,公网服务器扮演的是端口转发入口的角色,所有数据都经过它。
再看 UDP 打洞模式:被控端 frpc 先向 frps 注册一个 xtcp 类型的服务,访问端 frpc 也向 frps 注册一个 visitor 角色。frps 会把双方的公网地址和端口信息互相交换,然后访问端和被控端同时向对方发送 UDP 包,尝试在各自的 NAT 设备上建立映射。一旦打洞成功,双方就会建立一条直接的 UDP 通道,远程桌面的流量不再经过公网服务器。如果打洞失败,frp 会尝试通过 frps 中转,保证连接仍然可用。
这个过程中,NAT 类型是关键。Full Cone NAT 最容易打洞,Restricted Cone 和 Port Restricted Cone 也大概率能成功,Symmetric NAT 则很难。你可以用一些 STUN 检测工具查看自己的 NAT 类型,但不用太纠结,因为 frp 会自动回退。实测下来,国内大部分家庭宽带是 Port Restricted Cone 或 Symmetric NAT,打洞成功率大概一半一半,所以 TCP 映射兜底非常必要。
2. 公网服务端与内网客户端的准备与部署
2.1 公网服务器选型与系统初始化
公网服务器不需要太高配置,1 核 1G 的云主机就够用,系统用 Debian 12 或 Ubuntu 22.04 都行。关键是要有公网 IP,并且你能在安全组里开放需要的端口。我一般会开放这几个端口:7000/TCP 给 frps 的绑定端口,7001/UDP 给 xtcp 的信令和打洞辅助,13389/TCP 给远程桌面映射入口。如果你还想用 dashboard 看状态,可以再开 7500/TCP,但强烈建议只对特定 IP 开放,或者干脆不开。
系统初始化方面,先更新软件包,安装 curl、wget、vim 这些基础工具。然后创建一个专门的目录,比如/opt/frp,把 frp 的服务端和客户端解压进去。下载 frp 可以去它的 GitHub Releases 页面,选择对应架构的压缩包。国内服务器下载 GitHub 可能比较慢,可以先用本地电脑下载再上传,或者使用一些镜像加速,这里不展开。
安全组配置有一个常见坑:很多人只开了 TCP 7000,忘了开 UDP 7001,结果 xtcp 一直打洞失败。所以你在配置安全组时,最好把 TCP 和 UDP 都按需放行。另外,公网服务器的防火墙(比如 ufw 或 firewalld)也要同步放行,否则安全组开了也没用。
2.2 frps 服务端安装与配置详解
frps 的配置文件我习惯用 ini 格式,虽然新版本也支持 toml,但 ini 更直观。下面是一个基础配置:
[common] bind_port = 7000 bind_udp_port = 7001 token = 你的复杂令牌 dashboard_port = 7500 dashboard_user = admin dashboard_pwd = 你的强密码 log_file = /opt/frp/frps.log log_level = info log_max_days = 7bind_port是 frps 监听的 TCP 端口,客户端通过它注册。bind_udp_port是 UDP 端口,xtcp 打洞时用来交换信息。token是客户端和服务端的共享密钥,必须设置得复杂一些,否则任何人只要知道你的公网 IP 和端口,就能把内网服务暴露出去。dashboard是监控面板,能看到连接数、流量、客户端状态,方便排查问题。
配置好后,可以用./frps -c frps.ini前台启动测试。确认没问题后,建议配置 systemd 服务,让它开机自启和崩溃重启。创建一个/etc/systemd/system/frps.service文件,内容大概是这样:
[Unit] Description=frp server After=network.target [Service] Type=simple ExecStart=/opt/frp/frps -c /opt/frp/frps.ini Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target然后执行systemctl daemon-reload、systemctl enable frps、systemctl start frps。这样 frps 就会在后台运行,日志会写到你指定的文件里。注意不要把 dashboard 暴露在公网而不设密码,也不要使用默认的 admin/admin,这是非常低级的错误。
2.3 frpc 客户端安装与基础映射配置
在内网 Windows 主机上,下载 frp 的 Windows 版本,解压到比如C:\frp目录。然后创建frpc.ini:
[common] server_addr = 你的公网IP server_port = 7000 token = 你的复杂令牌 tls_enable = true [rdp_tcp] type = tcp local_ip = 127.0.0.1 local_port = 3389 remote_port = 13389 use_encryption = true use_compression = true [rdp_udp] type = udp local_ip = 127.0.0.1 local_port = 3389 remote_port = 13389 use_encryption = true use_compression = true这里定义了两个转发规则:一个 TCP,一个 UDP,都把本地 3389 映射到公网服务器的 13389 端口。因为 TCP 和 UDP 是不同协议,所以可以使用相同的 remote_port。tls_enable开启 TLS 加密,use_encryption和use_compression让流量加密并压缩,对远程桌面这种图形流量有一定帮助。
启动 frpc 可以用命令行:frpc.exe -c frpc.ini。如果要开机自启,可以用 Windows 任务计划程序,设置触发器为“计算机启动时”,操作指向frpc.exe,参数填-c C:\frp\frpc.ini。也可以用 nssm 把它注册成 Windows 服务。我个人更喜欢任务计划程序,因为配置简单,不容易出权限问题。
启动后,去 frps 的 dashboard 看看客户端是否在线,对应的转发规则是否显示为绿色。如果显示离线,先检查 token 是否一致,再检查公网服务器的防火墙和 frpc 的日志。
2.4 Windows 远程桌面开启与防火墙放行
被控 Windows 主机需要开启远程桌面。在 Windows 10/11 专业版上,进入“设置 -> 系统 -> 远程桌面”,把“启用远程桌面”打开。系统会提示你确认,并显示当前电脑的名称。注意,Windows 家庭版不支持作为远程桌面服务端,如果你用的是家庭版,需要先升级到专业版,或者改用其他远程控制方式。
开启后,确保你的账户有密码。远程桌面不允许空密码账户登录。然后检查防火墙:Windows 防火墙默认会放行远程桌面,但如果你装了第三方安全软件,可能会拦截 3389。可以在“高级安全 Windows Defender 防火墙”里查看入站规则,确保“远程桌面 - 用户模式 (TCP-In)”是启用的。如果你修改过远程桌面端口,记得在规则里同步修改。
还有一个细节:网络级别身份验证(NLA)。默认情况下,远程桌面会要求 NLA,这能提升安全性,但有些旧客户端可能连不上。如果你遇到连接问题,可以暂时在“系统属性 -> 远程”里取消勾选“仅允许运行使用网络级别身份验证的远程桌面的计算机连接”,但我不建议长期关闭,因为它能防止未授权连接消耗资源。
3. TCP 映射与 UDP 打洞的实操配置
3.1 先用 TCP 映射快速打通远程桌面(3389)
TCP 映射是最基础也最可靠的一步。配置好 frpc 后,在访问端的“远程桌面连接”里输入公网IP:13389,点击连接。如果一切正常,你会看到 Windows 的登录界面。第一次连接时,可能会提示证书不受信任,选择“是”继续即可。
如果连不上,按这个顺序排查:第一,在公网服务器上执行netstat -tlnp | grep 13389,看 frps 是否在监听这个端口。第二,检查云服务器安全组是否开放了 13389/TCP。第三,在访问端用telnet 公网IP 13389测试端口连通性,如果 telnet 不通,说明网络层有问题。第四,查看 frpc 日志,如果提示connect to server error,说明 frpc 没连上 frps;如果提示port already used,说明 remote_port 被占用了。
另外,远程桌面的连接速度取决于公网服务器的带宽和延迟。如果你用的是按流量计费的云主机,长时间挂远程桌面可能会消耗不少流量。这也是为什么我建议在 TCP 映射稳定后,再尝试 UDP 打洞,因为打洞成功后流量就不再走公网服务器了。
3.2 配置 frp xtcp 实现 UDP 打洞的点对点连接
xtcp 需要被控端和访问端都运行 frpc。先在被控端的frpc.ini里增加一个 xtcp 规则:
[rdp_xtcp] type = xtcp role = server sk = 你的打洞密钥 local_ip = 127.0.0.1 local_port = 3389然后在访问端的frpc.ini里增加 visitor 规则:
[rdp_xtcp_visitor] type = xtcp role = visitor server_name = rdp_xtcp sk = 你的打洞密钥 bind_addr = 127.0.0.1 bind_port = 13389注意server_name必须和被控端的段名一致,sk也必须一致。访问端启动 frpc 后,它会在本地监听 127.0.0.1:13389。你再用远程桌面连接127.0.0.1:13389,frpc 就会尝试通过 frps 交换地址,然后打洞直连被控端的 3389。
如果打洞成功,你在 frpc 日志里会看到类似nat hole punching success的提示。这时候远程桌面的延迟会明显降低,公网服务器的流量也会大幅减少。如果打洞失败,frpc 会回退到通过 frps 转发,你仍然能连上,只是延迟和流量会回到 TCP 映射的水平。
打洞成功率受 NAT 类型影响很大。你可以用一些 STUN 检测工具查看自己的 NAT 类型,但更简单的办法是直接试。如果一直失败,可以尝试更换网络环境,比如从公司网络换到家庭宽带,或者用手机热点测试。有些企业防火墙会直接阻断 UDP,这种情况就只能用 TCP 映射。
3.3 安全加固:加密、压缩、权限验证、访问控制
内网穿透把内网服务暴露到公网,安全是重中之重。首先,token 一定要复杂,最好包含大小写字母、数字和特殊符号,长度不少于 20 位。其次,开启 TLS,在 frpc 和 frps 的 common 段都加上tls_enable = true。这样客户端和服务端之间的通信会加密,防止被中间人窃听。
对于转发规则,可以加上use_encryption = true和use_compression = true。加密能保护远程桌面的登录凭证和画面数据,压缩能减少带宽占用。frps 还可以配置allow_ports限制客户端只能映射特定端口,比如allow_ports = 13389,防止别人用你的 frps 映射其他敏感服务。
公网服务器的防火墙也要做限制。如果你知道访问端的固定 IP,可以在安全组里只允许那个 IP 访问 13389。如果访问端 IP 不固定,至少要把 dashboard 端口关掉或加密码。远程桌面本身也要启用强密码和账户锁定策略,避免被暴力破解。我还会在 Windows 上启用“网络级别身份验证”,并在 frps 日志里定期检查异常连接。
3.4 实测效果与延迟对比
我在一台国内云主机、家庭 500M 宽带、公司 200M 宽带的组合下做过测试。TCP 映射模式下,远程桌面的平均延迟在 35ms 到 60ms 之间,具体取决于云主机的位置。UDP 打洞成功后,延迟降到 15ms 到 25ms,几乎和局域网远程桌面差不多。流量方面,TCP 映射时所有画面和操作都经过公网服务器,一小时大概消耗 300MB 到 800MB;打洞成功后,公网服务器只承担信令交换,流量几乎为零。
下面这个表格是我整理的关键对比:
| 对比项 | TCP 映射 | UDP 打洞(xtcp) |
|---|---|---|
| 访问端是否需要 frpc | 不需要 | 需要 |
| 延迟 | 较高,取决于服务器 | 较低,接近直连 |
| 公网服务器带宽消耗 | 高 | 低 |
| 打洞成功率 | 100% | 约 50% 到 80% |
| 配置复杂度 | 简单 | 中等 |
| 适用场景 | 兜底、应急 | 长期高频使用 |
从实测来看,如果你的主要需求是偶尔连一下,TCP 映射足够了。如果你每天都要远程办公几个小时,UDP 打洞带来的体验提升非常明显,值得花时间配置。
4. 常见问题与排查技巧实录
4.1 连接被拒绝或超时的排查路径
远程桌面连不上,最常见的原因是端口没通。先在访问端用telnet 公网IP 13389测试。如果 telnet 直接提示连接失败,说明公网服务器的安全组或防火墙没放行。如果 telnet 能通但远程桌面报错,说明 frps 到 frpc 的链路有问题。
进入公网服务器,执行ss -tlnp | grep 13389看 frps 是否监听。再看 frps 日志,如果提示login to server failed,说明 token 不对。如果提示client offline,说明内网主机的 frpc 没连上。在内网主机上检查 frpc 进程是否在运行,日志里有没有报错。常见错误包括connect to server error(网络不通或端口不对)、dial tcp 127.0.0.1:3389: connect: connection refused(Windows 远程桌面没开启或端口被改)。
还有一个容易被忽略的点:Windows 防火墙可能只允许本地子网连接。在“高级安全 Windows Defender 防火墙”里,检查“远程桌面 - 用户模式 (TCP-In)”规则的“远程 IP 地址”是否限制为本地子网。如果是,改成“任何 IP 地址”即可。
4.2 UDP 打洞失败的典型原因与解决
UDP 打洞失败时,先看 frpc 日志。如果提示nat hole punching failed,通常有这几个原因:第一,frps 没有开放bind_udp_port,或者安全组没放行 UDP 7001。第二,一方或双方是 Symmetric NAT,导致打洞无法建立。第三,sk或server_name不一致,导致信令交换失败。第四,企业防火墙阻断了 UDP 出站。
解决办法:确认 frps 配置了bind_udp_port = 7001,并且安全组开放了 7001/UDP。检查被控端和访问端的sk、server_name是否完全一致。如果 NAT 类型太严格,可以尝试用手机热点测试,或者改用 TCP 映射兜底。frp 还支持 stcp 类型,它通过 frps 转发,但需要访问端也运行 frpc,安全性比普通 TCP 映射更高,可以作为打洞失败时的备选方案。
另外,有些路由器会开启“SIP ALG”或“UDP 过滤”,这些功能会干扰打洞。可以登录路由器后台,暂时关闭这些选项再测试。如果打洞成功但远程桌面经常断开,可能是 UDP 超时时间太短,可以在 frpc 里调整udp_packet_size或heartbeat_interval,让连接保持活跃。
4.3 远程桌面常见错误代码与处理
0x204 是远程桌面比较常见的错误,通常和凭证或安全层有关。可以尝试在远程桌面连接里点击“显示选项 -> 高级 -> 服务器身份验证”,选择“连接且不警告我”。或者在“体验”里把连接速度设为“局域网”,让安全层协商更宽松。如果还是不行,检查被控端是否启用了 NLA,尝试暂时关闭 NLA 再连。
“某些设置由你的组织来管理”这个提示,通常是组策略或注册表残留导致的。可以在被控端运行gpedit.msc,进入“计算机配置 -> 管理模板 -> Windows 组件 -> 远程桌面服务 -> 远程桌面会话主机 -> 连接”,检查是否有策略限制。如果没有组策略编辑器,可以检查注册表HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services,把多余的键值删掉。
如果你用的是 Windows Server,可能会遇到“远程桌面授权模式尚未配置”的提示。这是正常的授权提醒,不是故障。普通 Windows 专业版不会有这个问题,也不需要额外配置授权服务器。只要在合法授权的范围内使用,按系统提示配置即可。
4.4 日常维护与监控建议
frp 运行久了,日志会越来越大。可以在 frps 和 frpc 的配置里设置log_max_days,让日志自动轮转。我一般设置 7 天,既能保留排错所需的信息,又不会占满磁盘。dashboard 是个好用的工具,可以定期看看在线客户端、流量曲线和连接数。如果发现陌生客户端,立即更换 token 并检查防火墙。
版本更新也很重要。frp 社区活跃,新版本会修复安全漏洞和打洞逻辑。每隔几个月可以去 GitHub 看看有没有新版本,升级前先备份配置文件。升级时注意查看 release notes,有些配置项可能改名或废弃。
最后,远程桌面的账户安全不能忽视。给远程登录的账户设置强密码,启用账户锁定策略,比如连续 5 次失败锁定 15 分钟。如果条件允许,可以给远程桌面配置双因素认证,或者通过公网服务器的安全组限制访问来源 IP。我自己还会在 frps 里设置allow_ports = 13389,防止有人拿我的服务器做其他转发。
我个人在实际操作中的体会是,内网穿透这件事,先把 TCP 映射跑通,再折腾 UDP 打洞,心里会踏实很多。打洞成功是惊喜,失败也不影响使用。另外,公网服务器的带宽不用买太大,1M 到 3M 就够应急,真正高频使用还是靠打洞直连。最后再分享一个小技巧:如果你有多台内网 Windows 主机,可以给每台设置不同的 remote_port,比如 13389、13390、13391,然后在 frps 的 dashboard 里起个备注名,管理起来会清晰很多。