ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

从零搭建frp内网穿透:SSH远程访问与安全加固实践

从零搭建frp内网穿透:SSH远程访问与安全加固实践 1. 为什么要搭内网穿透一次真实的远程访问困局1.1 从“人在外面要访问家里NAS”说起先讲一个我自己的场景。有段时间我在外面出差笔记本上有一份资料需要从家里NAS里调出来可家里那台NAS挂在路由器后面用的是192.168.x.x这样的内网地址。人在酒店里SSH连不上、Web管理界面也打不开差点让整个项目卡住。类似的需求其实非常普遍周末在咖啡馆想连回家里那台Linux服务器跑个训练脚本白天在公司想远程看家里电脑上的文件或者给客户演示一个本地开发中的Web系统但对方访问不到你电脑上的8080端口。这些问题落到技术上就叫内网穿透。frp就是目前开源社区里用得最多、资料最全的一套内网穿透方案。它的全称是Fast Reverse Proxy作者是fatedier项目托管在GitHub上Go语言编写天然支持跨平台从Windows、Linux到macOS、树莓派都能跑。frp的价值在于不需要跟运营商申请公网IP不用改路由器配置只要手里有一台带公网IP的服务器就能把内网里的任何一个TCP/UDP服务“送”到公网上让其他人随时访问。这篇文章我把自己从零搭建frp、配置SSH、Web服务、远程桌面的完整过程写下来包括踩过的坑和排查思路。如果你也遇到过“人在外面但访问不了家里设备”的窘境这篇应该能帮你少走不少弯路。1.2 公网IP、NAT与端口映射的天然限制要理解frp为什么要存在先搞清楚一个基础问题为什么默认情况下外网访问不了你家里的设备。家庭宽带接入运营商网络后运营商一般只分配一个动态的公网IP给光猫而光猫后面再接路由器路由器再给家里的手机、电脑、NAS分配192.168.x.x的内网IP。这个过程中所有内网设备对外通信都经过NATNetwork Address Translation转换路由器把内网IP和端口映射成公网IP和端口。但反过来当公网上的一个请求主动访问你家的某个端口时路由器并不知道这个请求应该转给内网的哪台设备默认直接丢弃。传统解决办法有两个。一是去运营商申请公网IP并且祈祷能拿到二是自己在路由器上做端口映射把路由器的某个公网端口指向内网某台设备的某个端口。前者受限于地区、套餐和运营商的策略后者受限于路由器的NAT类型如果是对称型NAT端口映射往往不稳定而且暴露了路由器本身的安全风险。frp的思路绕开了这些限制。它不再依赖“外网主动连进来”而是由内网设备主动向外网的frp服务器建立一条长连接然后所有公网用户的请求都走这条已经存在的反向通道。这样无论你家网络处于什么NAT类型只要有出网能力隧道就能建立。这也是frp这类反向代理工具和传统端口映射最本质的差别。1.3 为什么我最终选了frp而不是ngrok搜索引擎里搜“内网穿透”ngrok和frp永远是排在前面的两个名字。我也都试过简单说说取舍。ngrok官方提供SaaS服务下载客户端填一个authtoken就能用还会给你分配一个随机域名适合快速演示。但免费版限制很多域名每次重启都变、连接数受限、带宽被限速自定义域名要付费而且服务区在海外延迟不稳定。自己部署ngrok服务端也麻烦开源版的功能和文档成熟度不如frp。frp的优势在于完全自托管数据走自己的服务器隐私性和可控性更强支持TCP、UDP、HTTP、HTTPS多种协议可以映射任意端口而不是只能暴露80/443配置灵活一套服务端可以同时开SSH、Web、远程桌面、数据库等多个隧道文档和社区活跃度高遇到问题搜一搜基本都有解决方案。如果你是偶尔临时用一下或者只想给朋友展示一个页面ngrok的免部署优势确实香。但如果你像我一样需要长期、稳定、多场景地访问内网设备frp是更靠谱的选择。2. frp的工作原理一条由内网主动发起的反向隧道2.1 frps与frpc的职责划分frp整个体系分成两块frps和frpc。frps全称frp Server运行在带公网IP的服务器上。它的职责是监听一个固定端口接收frpc的连接同时接收公网用户的访问请求把两边衔接起来。frpc全称frp Client运行在内网设备上。它的职责是主动向frps发起连接维持隧道并把本地服务的流量封装后送出去。打个比方frps像是公司前台frpc像是你在家办公时专门负责跑腿的同事。这个同事主动跑到前台待命外面有访客来办事前台就通过这个“待命的同事”把需求传回你在家里的工位再把你的回复带出来。访客并不知道你人在哪里他只需要知道前台地址就行。这个“内网设备主动向外连”的设计是整个frp的基石。因为公网服务器IP固定可达内网设备只需要能访问互联网隧道就能建立不需要任何入站端口。2.2 一次SSH连接在隧道里是如何流转的看一个具体例子假设我在家里的Linux服务器上跑了sshd监听22端口。我用frpc在frps上注册了一个隧道公网侧端口为6000。当我在外地执行ssh -p 6000 userserver_ip时流量是这样走的客户端SSH请求先到达frps的公网IP的6000端口。frps查自己的代理表发现6000端口对应着一个名为“ssh-home”的隧道而这个隧道的实际目的地是frpc那边的127.0.0.1:22。frps于是把请求通过已建立的frp长连接转发给frpc。frpc收到后把数据拆包连接到本机或内网目标机器的22端口完成链路打通。这条链路建立后frps和frpc之间的长连接实际上成了一个双向管道公网SSH客户端的输入输出数据都被封装在这个管道里透明传输。整个过程对SSH客户端完全无感知它以为自己连接的就是服务器IP:6000实际上数据已经被frp“偷梁换柱”转进了内网。这个设计带来一个天然好处frps不需要存储任何业务数据它只做流量的转发所以即使frps服务器本身资源很小比如1核512M内存也能稳定扛住不少连接。2.3 TCP、UDP、HTTP各自的路由逻辑frp支持多种代理类型配置时要在type字段里标清楚tcp最通用的类型适合SSH、远程桌面、数据库等任意TCP服务。公网侧指定一个remotePort流量直接转发到内网localIP:localPort。udp适合DNS、游戏服务器等UDP协议服务原理和tcp类似。http和tcp的差异在于它不需要占用独立端口而是通过域名区分转发目标。frps配置一个vhostHTTPPort比如8080所有HTTP代理都共用这个端口根据请求的Host头判断该转发给哪个内网服务。https原理同http但还需要配置证书相关参数适合有域名且想走HTTPS加密的场景。stcp和xtcp这两类用得更深入。stcp是加密的点对点隧道访客端也需要装frpc才能访问适合不想暴露公网端口的场景xtcp走P2P打洞流量不经服务器中转延迟更低但受NAT类型限制明显成功率不稳定。我自己日常用得最多的就是tcp和http两种。tcp解决SSH和远程桌面http解决对外展示Web服务。把这两类搞清楚frp 80%的使用场景就覆盖了。3. 服务器端frps安装从下载到systemd自启3.1 服务器选型与网络环境检查搭建frp前你首先需要一台有公网IP的服务器。国内用户通常会选阿里云、腾讯云、华为云的轻量应用服务器海外的话Vultr、DigitalOcean、Linode都行。配置不用高1核1G内存、带宽按量付费或者5Mbps起步就够了frp本身不消耗太多资源主要瓶颈在带宽。挑服务器时我建议关注三件事带宽如果只用来SSH1Mbps都够如果要远程看视频、传文件带宽越高越好。frp转发流量是消耗服务器带宽的所以别在带宽上太省。地域离你常用网络环境近的机房延迟更低。如果主要访问者在国内选国内节点如果主要是海外访问选海外节点。系统镜像优先选Ubuntu 20.04 LTS或Debian 11/12资料多后续排查问题方便。拿到服务器后先做一次基础检查确认出网正常并更新系统ping -c 4 baidu.com apt update apt upgrade -y然后检查防火墙状态这一步很多人忽略后面连不上时才会意识到是防火墙的锅ufw status # 如果开启了ufw需要放行frps的端口具体端口根据你的配置决定3.2 下载、解压与版本信息确认frp的每个Release版本会打包好各平台的二进制文件命名类似frp_0.61.0_linux_amd64.tar.gz。arm架构的服务器比如某些轻量服务器、树莓派要选linux_arm64x86的选linux_amd64先通过uname -m确认架构再下载。cd /usr/local/src wget https://github.com/fatedier/frp/releases/download/v0.61.0/frp_0.61.0_linux_amd64.tar.gz tar -zxvf frp_0.61.0_linux_amd64.tar.gz mv frp_0.61.0_linux_amd64 /usr/local/frp cd /usr/local/frp ls -l解压后你会在目录里看到frps、frpc两个主程序以及对应的toml配置文件。服务端只需要frps和frps.toml客户端那组文件可以直接删掉保持目录干净。要特别提醒一下frp版本更新很快新版本对旧版配置格式并不完全兼容。早年frp用的是ini格式从v0.52.0开始配置文件逐步迁移到TOML格式函数名也从[common]段落变成根级字段。如果你是照着网上两三年前的教程操作配置格式很可能对不上建议以你下载版本的官方文档为准别盲抄老文章。3.3 frps.toml关键配置逐项说明打开frps.toml最小化配置看起来是这样bindPort 7000 auth.method token auth.token aB3dEf9gHiJkLmNopQrStUvWxYz123456 webServer.addr 0.0.0.0 webServer.port 7500 webServer.user admin webServer.password change_this_password逐项拆解一下bindPort 7000frps主监听端口frpc连接服务器时用的就是这个端口。建议改成不常见的端口比如17000、27000减少被扫描器盯上的概率。auth.method token鉴权方式token是最简单也最有效的办法。auth.token客户端连接服务端时的共享密钥。这个值一定要设置而且要设得足够随机。可以拿openssl rand -base64 32生成别用123456这种。webServerfrps自带的监控面板配置。开启后可以通过浏览器查看当前连接数、代理列表、流量统计。生产环境建议改为监听127.0.0.1只允许本机查看避免面板本身成为攻击入口。如果要支持HTTP/HTTPS类型的代理还需要加一行vhostHTTPPort 8080 vhostHTTPSPort 8443这两个端口用于HTTP代理的统一入口后面配置Web服务时会用到。3.4 用systemd把frps托管成常驻服务直接用./frps -c frps.toml可以前台运行但关闭终端进程就没了。正确做法是用systemd把它注册成系统服务开机自启、崩溃自动拉起省心得多。创建一个服务文件vim /etc/systemd/system/frps.service写入[Unit] DescriptionFRP Server Afternetwork.target [Service] Typesimple ExecStart/usr/local/frp/frps -c /usr/local/frp/frps.toml Restarton-failure RestartSec5 [Install] WantedBymulti-user.target然后依次执行systemctl daemon-reload systemctl enable frps systemctl start frps systemctl status frps看到Active: active (running)就说明服务已经起来了。后续如果改了配置只需要systemctl restart frps我遇到过一次改配置后忘记重启结果连接一直报旧的端口莫名其妙的bug。所以提醒自己养成习惯改完frps.toml或frpc.toml后第一时间重启对应服务再看日志确认。4. 客户端frpc配置三种高频场景一次讲清4.1 frpc.toml的骨架结构frpc的配置可以拆成两部分连接服务器的公共配置和定义隧道的[[proxies]]段。公共段告诉客户端如何找到服务器、用什么凭证登录proxy段则声明了“我要把内网的哪个服务映射到服务器的哪个位置”。基础骨架serverAddr your_server_public_ip serverPort 7000 auth.method token auth.token aB3dEf9gHiJkLmNopQrStUvWxYz123456serverAddr填frps所在服务器的公网IP或域名serverPort和auth.token必须和frps.toml里的配置一致否则客户端根本连不上服务端。下面每个[[proxies]]段就代表一条隧道。多个隧道可以共存比如同一台内网机器既开SSH又开Web服务就写两个[[proxies]]段注意name不能重复。4.2 场景一SSH远程登录内网Linux这个用途最刚需。比如我家里的服务器SSH端口是22我想在公网通过服务器的6000端口访问它[[proxies]] name ssh-home type tcp localIP 127.0.0.1 localPort 22 remotePort 6000各字段含义name隧道名称用于在frps面板和后端日志里标识这个隧道。type固定为tcp。localIP内网目标机器的IP。如果frpc和SSH服务在同一台机器上填127.0.0.1即可如果frpc跑在内网机器A但想转发到内网机器B就填B的内网IP。localPort内网服务的实际端口。remotePortfrps上对外开放的端口。外部用户通过服务器IP:remotePort访问frps会把流量转给frpc再转给localIP:localPort。配置完成后重启frpc在外网执行ssh -p 6000 useryour_server_public_ip如果一切正常你就能拿到内网机器的shell了。这里有个细节remotePort要避开frps自身占用的端口比如7000、7500、8080否则会冲突导致隧道启动失败。4.3 场景二HTTP域名访问内网Web服务假设你内网的树莓派上跑着一个博客系统监听8080端口。你想通过blog.example.com这个域名从公网访问。frp的巧妙之处在于所有HTTP代理共用vhostHTTPPort通过Host头区分具体目标所以不需要为每个Web服务单独开端口。frps.toml里确保已配置vhostHTTPPort 8080frpc.toml里添加[[proxies]] name blog-web type http localIP 127.0.0.1 localPort 8080 customDomains [blog.example.com]然后去DNS服务商把blog.example.com解析到你的服务器IP访问http://blog.example.com:8080就能看到内网博客了。如果你有自己的域名并配置了HTTPS证书可以用type https并添加certFile和keyFile参数[[proxies]] name blog-web-https type https localIP 127.0.0.1 localPort 8080 customDomains [blog.example.com] certFile /etc/letsencrypt/live/blog.example.com/fullchain.pem keyFile /etc/letsencrypt/live/blog.example.com/privkey.pem顺带提醒一句如果你的域名没有备案使用国内服务器做Web服务在80/443端口上会有合规限制HTTP代理用的8080端口通常不受影响但这个水很深建议根据你自己的实际情况评估或者干脆用海外节点跑Web展示类业务。4.4 场景三Windows远程桌面RDP远程桌面和SSH类似也是TCP隧道只是目标端口换成了3389。假设你家里有一台Windows电脑想在公司的Mac上远程连过去[[proxies]] name win-rdp type tcp localIP 192.168.1.100 localPort 3389 remotePort 63389这里有个细节值得说Windows RDP默认监听3389端口这个端口常年被扫描器爆破是重灾区。通过frp暴露时建议把remotePort设成一个高位的随机端口比如63389同时内网Windows侧可以做IP白名单限制只允许网关或frpc所在机器IP访问3389端口。外网连接时Windows自带的远程桌面客户端里填your_server_public_ip:63389Mac端可以用Microsoft Remote Desktop客户端连接方式一样。我实测下来只要服务器带宽够远程桌面的流畅度可以接受操作起来没有明显卡顿。4.5 客户端用screen还是systemdWindows端的自启问题Linux端的frpc和frps一样推荐用systemd托管配置文件逻辑完全一致。如果你不希望把frpc写成系统级的服务也可以用nohup或screen但systemd更稳妥一些。很多人的内网穿透是跑在Windows机器上的Windows上不需要systemd直接用“任务计划程序”或者把frpc.exe放进启动文件夹都能实现开机自启。更推荐的做法是写一个简单的bat脚本echo off cd C:\tools\frp frpc.exe -c frpc.toml然后通过“任务计划程序”设置开机启动并勾选“如果任务失败重新启动”保证进程意外退出后能自动拉起。5. 安全加固隧道开通后的第一件事5.1 认证、面板权限与最小化暴露隧道一开相当于把你内网的设备暴露到公网安全是绝对绕不开的话题。所有扫描器都在全天候扫端口一个没有认证的frp服务很快就会被陌生人利用轻则流量被盗刷重则内网被入侵。我的安全基线至少包含这几项token鉴权必开auth.method tokentoken用长随机串。面板不能裸奔webServer.addr不要设0.0.0.0改为127.0.0.1。如果确实需要远程看面板可以配合SSH隧道或防火墙白名单访问而不是直接暴露到公网。关闭不需要的代理只开通实际使用的那几条隧道用不到的服务别映射出去。5.2 端口收敛与防火墙白名单frps的端口号尽量挑高位端口比如主端口用17000而不是7000面板用17500而不是7500能少很多无差别扫描的麻烦。服务器上开启防火墙只放行必需端口。以Ubuntu的ufw为例ufw allow 17000/tcp ufw allow 17500/tcp ufw allow 8080/tcp ufw enable如果你需要限制SSH远程登录的来源IP可以在frps所在服务器的安全组或防火墙里做白名单只允许你公司的出口IP访问SSH端口。5.3 日志与异常连接的排查习惯frps会打印所有会话的连接日志包括来源IP、连接时间、隧道名称。养成定期看日志的习惯很有价值。几行快速查看命令journalctl -u frps -n 100 --no-pager journalctl -u frps --since 1 hour ago发现日志里面有大量来自陌生IP的SYN重试或连接失败记录就要警觉是不是被爆破或者扫描了。配合frps面板里的流量统计可以直观看到每个隧道的数据量如果某个隧道流量异常暴涨优先考虑是不是被人盯上了。另外frp本身只做转发不负责鉴权。暴露出去的内网服务比如SSH、RDP、数据库自身的密码强度、认证方式同样要过关。否则就算frp服务端配得再安全内网服务被攻破了一样白搭。正所谓“木桶效应”最薄弱的一环决定整个链路的实际安全性。6. 踩坑实录从“连不上”到“老掉线”的完整排查链路6.1 服务端连上了但隧道始终不生效这是我折腾frp时遇到最多的第一个问题。frpc日志显示login to server success看起来已经连上了但外网访问服务器IP:remotePort就是不通。排查链路大概是这样的先确认remotePort有没有和frps自身端口冲突。比如frps的bindPort是7000webServer.port是7500如果你的隧道remotePort也是7500frps就会启动失败或者隧道注册失败。接着查frps所在服务器的防火墙和安全组。云服务器有两层防火墙第一层是云厂商控制台里的安全组规则第二层才是系统内的ufw/iptables。大多数人在系统防火墙放行了端口却忘了在云控制台的安全组里也放行一次。这一步排查最快日志里往往什么都看不出来因为frps层面连接是正常的但网络层面流量根本没进来。最后是remotePort是否被本地运营商封锁。国内家宽用户在访问某些高位端口时会遇到运营商限制这种情况只能换端口试。我碰到过一次换了一个端口后立刻通了这种事虽然不常见但确实存在。6.2 隧道频繁中断问题出在keepalive和网络环境另一种常见问题是隧道不稳定SSH用着用着就断重连又能用几分钟。排查这类问题时我先看frpc的日志确认是“连接被断开”还是“心跳超时”。frp的默认心跳机制是frpc每30秒向frps发送一次keepalive包。但很多内网网络环境比如公司Wi-Fi、家庭路由器会在空闲一段时间后回收空闲连接导致隧道被断开后双方还没反应过来。解决方法是调整心跳和超时参数# frpc.toml 公共段 transport.heartbeatInterval 10 transport.heartbeatTimeout 30把心跳间隔从30秒缩短到10秒超时设为30秒这样连接空闲时也能保持活性不容易被中间设备回收。此外frpc所在机器的网络如果走的是代理或多层NAT比如公司内网再套一层Wi-Fi也可能导致隧道不稳定。这类环境建议尽量让frpc所在设备和目标服务处于同一局域网减少中间跳数。6.3 配置格式、版本与文档不对应的问题这是新一代用户最容易被坑的地方。网上大量教程还在用老的ini写法比如[common] server_addr x.x.x.x server_port 7000新版本直接不认这个格式会报错或者提示字段不存在。frp从v0.52.0开始配置文件改为TOML格式字段名也从server_addr变成了serverAddr。判断你的下载版本很简单/usr/local/frp/frps --version如果是v0.52.0之后的版本就按本文的TOML写法来如果是老版本再去找对应的老格式教程下载。另一个更稳妥的做法是每次升级frp后去官方GitHub Release页面对照frps.toml示例和frpc.toml示例把变更点过一遍别默认升级后配置还能直接用。6.4 mac m4系统安装frp架构坑与权限坑搜索热词里提到了“mac m4系统安装使用frp”这块我单独说点实操细节。M4芯片的Mac属于arm64架构下载压缩包时记得选darwin_arm64后缀别选成darwin_amd64。装完二进制文件后直接命令行运行会遇到“无法打开因为无法验证开发者”的拦截需要在“系统设置→隐私与安全性”里放行或者执行chmod x /usr/local/frp/frpc xattr -d com.apple.quarantine /usr/local/frp/frpc把com.apple.quarantine属性删掉Gatekeeper就不会再拦了。Mac上想开机自启frpc可以用launchd写一个plist文件或者用Homebrew的services机制brew services start frpc前提是你通过brew安装并配置好了frpc。我用下来感觉Mac版frpc的稳定性不错做客户端完全够用。7. 稳定性优化与进阶玩法7.1 带宽瓶颈如何破xtcp P2P路径frp默认模式是服务端中转所有流量都走frps服务器这就意味着带宽上限取决于你服务器的带宽。如果是服务器带宽只有5Mbps那远程看视频或者传大文件体验会很差。frp其实提供了xtcp类型的P2P打洞模式当两个frpc之间能成功打洞时流量直接在内网之间传输不再经过服务器。这样一来远程访问NAS传文件的速度可以接近家宽的上行带宽。xtcp配置大概长这样[[proxies]] name p2p-nas type xtcp localIP 127.0.0.1 localPort 5000 secretKey your_secret_key访问方也需要装frpc并且配置一个visitor段才能访问这个P2P隧道。但这个模式受限于双方的NAT类型如果有一方是对称型NAT打洞基本会失败。所以xtcp适合做优化手段不适合做保底方案我通常会在同一台机器上同时保留tcp中转和xtcp两个隧道打洞成功走P2P失败自动切回中转。7.2 多客户端、多隧道的组织和命名规范当内网设备多起来之后隧道数量会膨胀得很快。我有三台内网设备要暴露家里一台NAS、一台Linux服务器、一台Windows电脑加上各种Web服务frpc里写了十几个[[proxies]]段。这时候命名规范就很重要了。我的习惯是设备名-服务名-用途比如nas-ssh-managementnas-web-photowin-rdp-mainlinux-ssh-dev日志里查故障时一目了然面板上的连接列表也不会乱七八糟。如果你有多个内网设备分别跑frpc还可以在token之外设置user字段新版本里是user.name来区分不同客户端面板上会按user分组显示排查问题效率高很多。7.3 与DDNS搭配没有固定IP也能跑服务端frps需要一台有公网IP的服务器但如果你不想买服务器也可以用一台有公网IP的旧电脑或家用NAS自己跑frps——前提是你确实拿到了公网IP。这种情况下IP经常是动态变化的配合DDNS动态域名解析就能解决把serverAddr配成你的DDNS域名IP变了会自动重新解析。这类方案适合有一定网络基础、不想额外花钱买服务器的玩家。稳定性取决于你家的上行带宽和IP稳定性当成练手项目完全没问题。8. 写在最后关于frp这件事我的几点实际体会8.1 frp不是洪水猛兽但要有边界意识frp是一个非常中立的工具它的核心价值是让合法的内网服务被授权访问而不是破解任何限制。我在自己的设备之间搭建frp是为了远程办公、文件访问、服务调试这些用途都是为了提升日常工作效率。如果你也有类似需求顺着这篇文章把frps和frpc跑起来基本半天就能用上。但边界意识必须有内网穿透本质上是在你内网和公网之间开了一扇门门开多大、放谁进来、什么时候关这些问题要提前想清楚。frp的token认证、防火墙白名单、端口收敛这些安全配置不是可选项而是必选项。我见过太多人图方便frps裸奔跑在默认端口上token都不设结果服务器被扫描器塞满了奇怪进程。这不是frp的问题是使用方式的问题。8.2 建议的落地顺序如果你是第一次接触frp我建议按这个顺序动手先在服务器上部署frps用systemd跑起来面板打开确认进程活着。在一台内网Linux机器上配frpc先打通SSH验证最基本的tcp隧道。再加一条http代理把内网的一个Web服务通过域名暴露出去。确认稳定运行后再考虑远程桌面、UDP等更复杂的场景。最后做一次安全审计看token强度、关闭多余端口、限制面板访问、查看日志。每一步验证通过再继续下一步不要把十几个隧道一次性配完否则出了问题你会花更多时间定位。8.3 最后一句话frp这个工具我用了差不多五年从早期的ini配置到现在的TOML从单隧道到多设备多隧道它一直是我远程访问内网服务最顺手的一把“钥匙”。搭建过程不算复杂但里面涉及的网络原理、安全意识和排查思路才是真正有价值的东西。希望这篇长文能让你少踩几个坑一次把内网穿透跑通。
返回列表