ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

群晖免端口访问实战:反向代理+NPM+内网穿透全方案

群晖免端口访问实战:反向代理+NPM+内网穿透全方案 开头就不整那些虚的了直接说场景。我家里一台群晖里面跑着照片备份、Download Station、Drive同步还有几个Docker容器。平时自己在局域网里用IP加端口访问倒没什么感觉但一到外面或者说要把某个页面发给朋友看一下问题就来了——我总不能甩个http://192.168.1.10:5000过去吧对方要么打不开不在同一个网络要么打开了一看是群晖的登录页还得解释半天哪个端口是干嘛的。后来朋友一句你这群晖咋还要带端口号才能访问我家的直接输域名就进去了说得我当场破防。于是就有了这篇文章核心就一件事怎么让群晖用顶级域名直接访问把端口号彻底藏起来。先说清楚这篇文章适合谁家里有群晖包括黑群晖但不想每次记端口号的人被运营商不给公网IP折磨过的人想用自己注册的顶级域名访问NAS、而不是用xxx.synology.me这种二级域名的人以及想在折腾过程中少踩几个坑的人。1. 免端口访问的本质网址默认端口和群晖5000端口的缺口1.1 从URL规则说起80和443是浏览器默认端口先讲个最简单的网络常识很多人天天用浏览器却没注意过当你访问https://www.example.com的时候浏览器实际上请求的是https://www.example.com:443。当你访问http://www.example.com实际请求的是http://www.example.com:80。冒号后面这个数字就是端口号只不过80和443是HTTP和HTTPS的默认端口所以浏览器帮你隐藏了地址栏里看不到你也不用敲。这也是免端口访问真正的含义。不是说不存在端口而是你访问的服务恰好监听了80或443端口于是浏览器默认帮你把这个参数省掉了。你要是访问一个监听在8080端口的服务URL就必须带:8080这是逃不掉的。群晖的DSM默认情况是这样的HTTP走5000端口HTTPS走5001端口。所以在内网访问群晖你输入的是192.168.x.x:5000它完全不在浏览器默认端口的范围内于是就必须老老实实把端口号敲上。1.2 群晖默认端口不是443所以你需要一个翻译官那能不能直接把群晖的管理端口改成443可以改控制面板 → 登录门户 → DSM设置里就能改HTTP和HTTPS端口。但问题来了一台群晖只有一个443端口可群晖上的服务可不止一个——DSM要443Drive要端口Photos要不要Download Station要不要你后续要挂的Docker容器要不要端口只有这一个服务却有好几个直接把端口改到443只能解决DSM一个人的问题其他服务照样得靠各种奇奇怪怪的端口号撑着。这就需要一个翻译官角色也就是反向代理。它的工作逻辑很直白外部请求带着https://dsm.example.com访问你的443端口它看一眼域名知道是要找DSM就转发给内网的5000端口下一个请求是https://drive.example.com它再转发给内网对应的另一个端口。示意图不用画本质上就是一个Nginx根据域名做流量分发的过程。1.3 顶级域名和子域名在这里的角色很多人概念里把顶级域名和子域名搞混了。example.com是顶级域名严格说.com才是顶级域example.com是二级域但在日常用户语境里大家习惯把example.com叫顶级域名下面跟着的dsm.example.com叫子域名。免端口访问这件事说穿了就是一个域名映射到443端口由反向代理识别出是哪个域名再把请求转给内网里对应的服务。有人会问我就一个域名怎么映射多个服务答案是子域名。dsm.example.com指向DSMphotos.example.com指向相册drive.example.com指向DriveDNS的A记录都解析到同一个IPNginx根据Host请求头区分它们。这就是为什么说可以顶级域名——只要你自己的域名在手子域名随便开每个服务都能拥有一个不带端口号的独立访问地址。2. 三条路线的取舍路由转发、反向代理、内网穿透怎么选2.1 路线A路由器端口转发最简单但最不优雅大多数人第一个想到的方案是路由器端口转发。光猫桥接或者有超级管理员权限把5000端口映射到公网然后访问http://你的公网IP:5000。再配合DDNS把动态IP解析到一个域名上就能用http://xxx.example.com:5000访问。这条路线的优点是真的简单十分钟能搞定。但缺点也很致命一是端口号还是得带着不符合我们免端口的初衷二是5000端口裸奔到公网群晖的登录页面对全互联网开放每天会有无数的扫描器在撞你的管理密码安全感极低三是如果以后想在443端口多加几个服务端口转发根本顾不过来它只能做一对一或者一对多的简单映射做不了域名级别的路由判断。我的建议端口转发可以作为暂时的保底方案但不要把它当成终点。2.2 路线B反向代理我最终选择的方案反向代理就是前面说的翻译官具体落地有两种方式。第一种是用群晖自带的反向代理功能位置在控制面板 → 登录门户 → 高级 → 反向代理填一组规则就能把某个域名转发到某个内网端口。优点是零成本、不开新容器群晖原生支持缺点是功能相对简洁配置证书、通配域名这些效率偏低。第二种是部署独立的Nginx反向代理服务比如Nginx Proxy ManagerNPM。它在群晖上以Docker容器方式运行提供一个可视化网页域名转发规则、SSL证书申请、HTTP/HTTPS开关都能在一个后台里搞定对不想面对一堆Nginx配置文件的用户极其友好。我自己用的是NPM原因很实际后续要挂的服务不止DSM一个NPM里加一条转发规则比群晖自带界面顺手得多而且证书管理非常省心。群晖自带方案适合只折腾DSM一个人没有扩展需求的情况。2.3 路线C内网穿透给没有公网IP的人如果你的宽带压根拿不到公网IPv4——这个问题在移动宽带用户里特别常见后面专门开一章讲——那么上面两条路直接失效你得走内网穿透。原理是用一台有公网IP的服务器做中转家里的NAS主动和这个服务器建立一条隧道外部用户访问服务器的某个端口数据顺着隧道流回家里的NAS。内网穿透的具体工具在下文第五章会展开对比这里先给结论优先级是能申请到公网IP就先申请公网IP申请不到再用穿透方案穿透是最后手段而不是首选。2.4 黑群晖用户要先确认的几件事聊到这里必须单独提醒黑群晖用户。热词里黑群晖搜索量很高很多人的引导盘是各种第三方的引导系统版本从7.0到7.2都有。做反向代理之前先确认三件事你的系统版本是否支持登录门户里的反向代理功能。如果设置项找不到那就直接用Docker装NPM别在系统功能上耗时间。黑群晖的Docker套件和系统更新的兼容性。有些引导版本装Docker之后网络模式会出问题host模式和bridge模式的表现不一样NPM部署时优先用bridge并映射端口最稳。如果你更新过引导或者洗白过序列号DNS设置容易被改遇到域名解析到NAS后打不开的情况先查/etc/resolv.conf里的DNS是不是被覆盖了。黑群晖本身没什么不能做反向代理的只是排查问题时要多一层心眼。3. 动手配置NPM把DSM变成标准443端口服务3.1 部署NPM容器两步就够我假设你的群晖已经装好了Docker套件。如果还没装到套件中心装一个就行。NPM部署用docker compose最清晰先在群晖的File Station里建一个/docker/npm目录建一个docker-compose.yml内容如下version: 3 services: npm: image: jc21/nginx-proxy-manager:latest container_name: npm restart: always ports: - 80:80 - 443:443 - 81:81 volumes: - /volume1/docker/npm/data:/data - /volume1/docker/npm/letsencrypt:/etc/letsencrypt81端口是NPM自己的管理后台80和443是它对外提供的HTTP和HTTPS服务端口。在SSH或者群晖的Container Manager界面里执行cd /volume1/docker/npm docker compose up -d启动后用http://群晖IP:81就能打开NPM后台默认账号adminexample.com密码changeme第一次登录会强制要求改密码。3.2 创建反向代理规则把DSM 5000端口变成443标准端口部署完成后进入NPM后台点Proxy Hosts→Add Proxy Host开始配置反向代理规则。拿DSM举例填写方式如下配置项填写值说明Domain Namesdsm.example.com你打算用来访问群晖的子域名Schemehttp群晖内网默认走HTTP端口5000Forward Hostname / IP192.168.1.10群晖在局域网里的IPForward Port5000DSM的HTTP管理端口Cache Assets勾选可选的加速项但管理页面不太建议开避免缓存到过期的脚本和样式Block Common Exploits建议勾选拦截常见攻击特征的请求性价比高填完之后保存再把DNS解析做好——在你的域名服务商后台加一条A记录把dsm.example.com解析到你宽带当前的公网IP前提是你的宽带真能拿到公网IP拿不到就看第五章。刚配置完别急着关浏览器先在局域网里用http://群晖IP:81访问NPM后台确认在线状态然后在同一局域网里直接访问http://dsm.example.com。如果一切正常DSM的登录页面会在域名下弹出来。3.3 关键配置项说明Host、X-Forwarded-Proto和WebSocket有些人在配置完第一个反代规则后发现DSM页面能打开但登录之后会无限跳转或者一登录就报您没有使用HTTPS协议之类的提示。这通常是Nginx默认转发时没带上正确的请求头导致的。NPM默认生成的配置里带了几个关键头部我再手动补充一下点击这条规则进入Edit→Advanced填入location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; }几个头各自的作用分别是Host $host告诉群晖用户访问的域名是什么群晖才能按照域名生成正确的跳转链接否则它会拿内网IP来拼接跳转自然就错乱了。X-Forwarded-Proto $scheme告诉群晖原始请求是HTTP还是HTTPS这一步至关重要如果群晖认为你走的是HTTP而实际上你在用HTTPS访问登录后会因为协议不一致反复把页面跳到5001端口或者死循环。X-Real-IP和X-Forwarded-For把真实客户端IP传给群晖不传的话群晖看到的全是127.0.0.1来自Nginx容器的转发日志和fail2ban全都会废掉。Upgrade和Connection这两行则是给WebSocket准备的群晖Drive、Chat、Download Station的实时更新都靠它缺了会导致页面能打开但数据不动。3.4 验证手机流量环境下直接输域名访问配置完最后一步我习惯的做法是关掉WiFi用手机流量直接访问https://dsm.example.com。这一步能排除局域网内DNS缓存、HSTS策略等干扰验证的是从公网到NAS的完整链路。如果你的上没有公网IP或者端口被运营商封了这一步肯定失败。别灰心这不是配置问题是线路问题跳到第五章用隧道方案解决。4. 证书与HTTPS让访问走加密通道且自动续期4.1 为什么要用HTTPS浏览器警告和数据安全有人觉得我就自己家用HTTP算了还省得折腾证书。这个想法非常危险。原因有两点。第一浏览器对HTTP站点的限制越来越多很多现代浏览器会把HTTP页面上的摄像头、麦克风、传感器等能力直接禁掉群晖的某些功能会变得残缺。第二你的登录密码是明文传输的只要是同一个网络里的其他人抓包就能看到你的密码更不用说公网上的各种劫持。用上HTTPS之后这些风险能全部消除Lets Encrypt还是免费证书不存在成本问题。4.2 在NPM里一键申请Lets Encrypt证书NPM的好处就是证书申请在网页上点点就行。进入Proxy Hosts→ 选择你刚才创建的DSM规则 →Edit→SSL标签页勾选Request a new SSL Certificate填写你的邮箱勾选同意条款然后Save。NPM会自动去Lets Encrypt申请证书并且绑定到这个域名上。完成后同一页面里能看到证书的到期时间NPM会自动续期不用你手动操心。Lets Encrypt的证书有效期为90天很多人担心到期了还得手动换在NPM里这个担心是多余的后台在合适的时候会自动发起续期请求。前提是你在申请证书时该域名已经从公网能访问到你的NPM服务器了Lets Encrypt的验证服务器需要能访问你的80或443端口来完成HTTP-01验证。4.3 群晖自带DDNS证书申请失败时的备用方案热词里有一条群晖 acme docker说明很多人都遇到过群晖自带的证书申请不成功。常见原因无非几种群晖自带的DDNS服务的域名本身被墙或者被污染或者你的xxx.synology.me域名在运营商那儿解析异常证书验证自然失败。你已经手动改过群晖的端口把80或者5000端口挪走了导致Lets Encrypt的验证请求没有落在群晖的Web服务上。移动宽带下群晖根本没有被公网访问到任何认证服务器都验证不了你的域名所有权。如果你的情况是群晖本身连不上外网——即没有公网IP那先解决网络问题再解决证书问题顺序不能反。如果只是验证端口对不上可以退一步直接在NPM那边申请证书让NPM的443端口来响应验证请求然后把证书以PEM文件形式导入群晖的控制面板 → 安全性 → 证书。这条路在NPM申请阶段不需要群晖参与任何验证只要NPM的80和443端口在公网可达就行。5. 没有公网IP时隧道方案和组网方案的对比实测5.1 症状回顾DDNS配置成功但从外面连不上移动宽带的用户对这句话一定深有体会。家里路由器上DDNS明明显示解析成功了域名也能ping出IP但用手机流量去访问怎么都连不上。甚至越来越让人迷惑——路由器WAN口拿到的IP和百度搜出来的公网IP压根不是同一个或者是一大串100.64.x.x开头的地址。这个100.64.x.x就是CGNAT运营商级网络地址转换的典型特征。意思是运营商在你家路由器外面又进行了一层NAT你家的IP并不是真正公网可路由的IP而是运营商的一个共享大内网地址。既然你根本没有独享的公网IPv4那常规DDNS和端口转发这条路线直接原地破产。5.2 三种隧道工具的对比frp、Tailscale、Cloudflare Tunnel拿不到公网IP不代表没救内网穿透可以绕过去。原理是你家NAS主动向外网的一台有公网IP的服务器发起连接并维持隧道外部客户端的请求先到这个服务器再由服务器顺着隧道转发回家里的NAS。方向上是从内往外发起的连接所以不需要家里有公网IP和开放入站端口。我实测了三种常见方案对比表格如下方案frpTailscale组网Cloudflare Tunnel是否需要服务器需要一台有公网IP的VPS不需要自己的服务器用官方协调服务器不需要自己的服务器配置难度中等要自己维护客户端和服务端低装客户端登录即可中等需要管理Cloudflare账号访问方式域名或IP加端口可配合NPM实现免端口分配的100.x.x.x内网IP也可以用自己的域名域名必须走Cloudflare国内访问速度取决于VPS线路好的VPS能跑满P2P打洞成功则直连很香打洞失败走中继则看运气可用性看Cloudflare线路多数地区延迟偏高稳定性高只要VPS不死就稳定打洞成功率高但组网依赖官方协调服务器稳定性高但速度上限看线路我自己的建议排序是有VPS的、讲究速度和可控性的选frp不想维护服务器、追求方便首选Tailscale想要免费且不想折腾服务器、对延迟不敏感的选Cloudflare Tunnel。5.3 我的实测感受延迟、速度和稳定性实测数据分享下。我在家里群晖上挂了一个占用带宽较低的应用分别走三种方案从外部访问frp 国内VPS带宽5Mbps单文件下载速度稳定在4.8Mbps左右延迟约20ms体验最接近直连适合同步照片和看视频。Tailscale移动网络下碰运气打洞成功过延迟一度降到30ms内速度取决于两端运营商互联打洞不成功走中继时下载速度掉到几百KB/s整体感觉不稳定。Cloudflare Tunnel速度浮动很大晚高峰有时候只有几百KB/s延迟经常在150ms往上适合应急看个文件、改个配置不适合重度使用。一句话总结要速度就frp要省事就Tailscale要免费且没有速度执念就Cloudflare Tunnel。穿透方案搭配NPM使用把穿透工具的端口透传进来后在NPM里按域名规则继续做分发这样就可以在没有公网IP的条件下依然做到免端口访问。5.4 黑群晖在隧道场景下的特殊注意点黑群晖用户用穿透方案时还有一个细节要留意黑群晖的硬件解码和QuickConnect功能经常是不完整的。如果你之前靠QuickConnect访问群晖换了隧道方案后很多套件内置的通过QuickConnect访问的链接会失效。这是正常现象解决办法是把套件的对外地址改成自己的穿透域名。比如Synology Photos的设置 → 外部访问里填上https://photos.example.com Drive客户端服务器地址填上drive.example.com:443就能绕过QuickConnect的限制。6. 踩坑清单跳转循环、WebSocket掉线、上传变慢6.1 DSM登录后无限跳转代理头配置问题这是我第一次配NPM遇到的第一个拦路虎也是网上问得最多的。现象是打开DSM登录页没问题但输入密码点登录后页面一直跳转要么回到登录页要么卡在某个地址出不来。排查过程我记得很清楚先用浏览器的开发者工具看Network标签发现登录请求返回的是302Location头里的地址变成了http://192.168.1.10:5001。这就说明群晖自己判定你当前走的是HTTP不是HTTPS或者你访问的域名不是它认识的域名于是自作主张要跳转到HTTPS端口。解决办法就是3.3节里那几行请求头尤其是Host $host和X-Forwarded-Proto $scheme。填完之后清一下浏览器缓存的HSTS记录再重新访问就正常了。这一步NPM默认配置不一定带全尤其是老版本NPM必须手动加上。6.2 Drive客户端和网页套件掉线WebSocket没开群晖Drive、Chat这类实时性较强的套件前端和后端之间需要建立WebSocket长连接来推送数据变更。走反代的时候如果Nginx没有正确转发Upgrade请求头WebSocket握手就会失败。表现症状是网页能打开文件列表能看到但驱动器同步时客户端频繁提示无法连接到服务器或者网页端页面上改了数据另一个设备半天不刷新。解决方法是确保反代配置里包含Upgrade和Connection两行。如果你用的是新版NPM界面里其实有一个WebSocket开关位于Edit Proxy Host的Advanced标签页下方的支持项里勾上就能自动生成对应的转发头。如果手写配置注意Connection $connection_upgrade这个变量是在Nginx全局里定义的NPM已经内置了这个变量的映射逻辑照抄就行。6.3 上传速度变慢MTU和MSS clamping这个问题通常出现在路由器端口转发 公网IP的组合方案下穿透场景也偶尔遇到。表现是下载速度正常上传速度只有几十KB/s到一两百KB/s卡得像断网一样。原因很可能是PPPoE拨号网络的MTU最大传输单元是1492比以太网标准的1500小8字节。如果路由器或者光猫没有做MSS clamping也就是把TCP SYN包里的MSS值从1460调整到1452带大包的数据就会被中间设备丢弃TCP协议会反复重传速度直接雪崩。排查方法并不复杂先在你电脑上执行ping 域名 -f -l 1400如果能通再加大包尺寸如果包稍大就不通基本就是这个原因。解决办法在路由器WAN口设置里找到MTU改成1492或者开启MSS钳制选项。这个坑隔三差五就会有人踩且症状极具迷惑性第一反应往往以为是反代服务器的问题实际上和反代半点关系都没有。6.4 忘记关闭原端口访问方式的风险免端口访问配置完成后5000端口是否还继续暴露在公网我的建议是在路由器防火墙层面把5000/5001对公网的访问直接禁掉内网访问保留不变。操作方法是端口转发的规则里不要做5000端口的映射防火墙规则里拒绝WAN口访问群晖的5000/5001端口。保留一个5055或者别的自定义端口给局域网内应急使用是合理的但不要让它对公网开放。反向代理加HTTPS之后公网流量都走443由NPM接管再进行分发群晖的原生管理端口不需要也不应该出现在公网上。这样即使你的NPM配置异常或者NPM容器挂了外面至少不会直接撞到群晖的原生管理页面。最后分享一个我自己一直在用的小习惯折腾完这一整套之后我给自己定了一条规矩不管用免端口还是穿透方案群晖的管理地址永远保留一条局域网IP的备用通道。控制面板登录门户里把HTTP和HTTPS端口改成了内网自定义端口比如HTTP用5055、HTTPS用5056只在局域网内使用不对公网开放。这样做的原因是万一哪天NPM容器崩溃、证书续期失败或者域名解析抽风我至少能通过局域网IP直接进系统恢复服务。平时维护时也建议先把防火墙规则理清楚再动手改配置别让自己被锁在门外。希望这篇从原理讲到实战、从正向配置讲到反向避坑的文章能帮你把群晖的访问体验真正提升一个台阶。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进