前阵子帮朋友折腾一台群晖NAS,他在外面老想访问家里NAS上的下载任务和照片库,但运营商不给公网IP,DDNS这条路直接断了。我第一反应是上frp,后来最终换成了nps体系下群晖用Docker部署npc客户端,原因是nps的服务端自带一个Web管理面板,能可视化管理所有隧道和客户端,对不熟悉命令行的朋友友好得多。这篇文章就把整个过程整理成一份可以直接照做的记录:从为什么选这套方案,到Docker里怎么配置npc,再到实际运行中会踩的坑,一次讲完。
如果你手上有群晖NAS,想在外面访问家里的服务,又不想折腾frp那一堆配置文件,这篇文章应该正适合你。不需要太深的基础,只要会打开群晖的Docker界面,跟着步骤走就能跑起来。
1. 先搞清楚:为什么是nps + npc + Docker + 群晖
1.1 没有公网IP时,内网穿透是怎么解决远程访问的
绝大多数家用宽带现在分不到真正的公网IP,运营商给的是一个内网地址,DDNS在这种环境下基本失效。你就算把域名解析做对了,流量也进不了家里的路由器。
内网穿透的基本思路,就是让内网的一台设备主动去连接一台有公网IP的服务器,建立一条长连接通道。外部用户访问公网服务器上的某个端口时,服务器把流量顺着这条通道转发到内网设备,内网设备再转发给NAS上的具体服务。这样,出方向的连接是由内网设备发起的,所以不需要公网IP,也不用在路由器上做端口映射。
nps和npc就是这套模型里很经典的开源实现。服务端部署在有公网IP的机器上,叫nps;客户端部署在需要被访问的内网设备上,也就是群晖NAS里,叫npc。npc启动后主动连上nps,之后你去访问nps服务器上的某个端口,流量就会被导到NAS对应端口上。
1.2 nps和frp怎么选
frp应该是目前社区里知名度最高的方案,配置灵活、文档也多。但frp的很多管理动作都要靠编辑配置文件来操作,服务端加一个隧道、改一个端口,要么改配置文件重载,要么用frps的Dashboard,但Dashboard只提供查看,很多操作还是得在命令行完成。
nps不同的地方是,它自带一个完整的Web管理后台。新建客户端、添加隧道、查看流量、控制启停,全部在浏览器里点就行。这个差别在日常使用中太重要了,尤其是给朋友的公司或者家里部署一次之后,以后维护基本不需要再登录到服务器上敲命令。
我自己的选择标准是:如果服务器上已经有完善的自动化管理工具,frp完全够用;但如果你希望有一个图形界面来管理所有穿透关系,nps会更顺手。群晖用户大多习惯图形化操作,所以用nps在体验上是更顺的。
1.3 为什么用Docker而不是套件或直接二进制
群晖上跑npc,常见有三种方式:在DSM里装第三方套件、手动执行二进制文件、用Docker容器运行。第三方套件的问题是更新不及时,而且来源良莠不齐,装之前要自己掂量安全性。直接执行二进制文件的问题是群晖系统升级后环境变化容易导致进程丢失,而且没有托管机制,崩溃了不会自动拉起来。
Docker就解决了很多麻烦:镜像里已经把运行环境打包好了,群晖的Container Manager(DSM 7.2以前叫Docker套件)会自动管理容器状态,还能设置开机自启。就算以后要换机器,只要导出配置再拉一次镜像,几分钟能恢复。所以我一直推荐群晖上能用Docker的都尽量用Docker,省心很多。
2. 部署前必须搞懂的3个概念
2.1 npc的工作模式:客户端主动连接,而不是服务端找上门
这一点是整个穿透能否跑通的核心,很多人配置了半天没成功,就是没理解npc的通信方向。npc启动后,是主动向nps的某个端口发起连接,连接建立后会保持这条长连接。后面外部用户访问nps服务器上的端口时,nps利用这条已经被建立的通道,把请求转发给处在内网的npc,npc再转发给内网里的服务。
这个模式的好处是:群晖这边不需要公网IP,不需要在路由器上做端口映射,也不需要去改运营商拿公网IP。npc就像是你派出去的一个信使,先跑到服务器那边等着,有请求来了信使再把话传回来。
理解了这一点,你就会明白为什么npc的配置里最重要的是服务器地址和vkey(连接密钥),因为npc启动时就要靠这两个信息找到nps并证明自己的身份。如果nps服务器地址填错、端口填错或者vkey不对,npc要么连不上,要么被服务端拒绝,整条链路建立不起来。
2.2 网络模式:host还是bridge
Docker容器跑起来之后,有几张可选的网络模式:桥接模式、host模式、macvlan等。群晖默认创建容器时通常选桥接模式,但npc这个场景下,我建议直接用host模式。
原因很简单。npc工作中需要监听一些本地端口,比如在群晖上开启某个穿透时,npc会在本机监听一个端口,然后把收到的流量转给另一个内网服务端口。如果用桥接模式,这些监听端口会落在容器内部,群晖宿主机要把流量转发进去就需要额外做端口映射。npc的端口是动态的,每建一个隧道就要映射一个端口,维护起来非常别扭。
host模式下,容器直接使用宿主机的网络栈,npc监听端口就等同于在群晖本机监听端口。配置更直观,也不容易出端口对应错乱的问题。代价是容器不具备网络隔离性,但对于群晖这样一个需要长期运行、本身就是单一主机的场景,这个代价可以接受。
2.3 几个绕不开的端口和参数
nps服务端默认有几个关键端口,理解它们的用途对排查问题很有帮助:
- 8080:nps的Web管理后台端口,你登录后台添加客户端、配置隧道都走这个端口。
- 8024:nps与npc之间的通信端口。npc启动时主动连接的就是这个端口,这是整个穿透链路的基础通道。
- 隧道业务端口:你在nps后台给某个客户端添加隧道时,指定的服务端监听端口,比如想通过服务器上的8000端口访问家里的NAS,这就是一个业务端口。
npc连接nps时用到的关键参数主要是三个:-server指定nps服务器的域名或IP加上通信端口、-vkey填写nps后台创建的客户端密钥、-type指定连接类型。有的场景下还会用到-tls_enable=true,当nps开启了TLS时才需要,一般内网穿透场景如果不特意配置,默认不用加。
在Docker里落地时,这些参数可以以命令行的形式传给容器,也可以通过配置文件挂载的方式传入。不同镜像支持的方式略有差异,但思路都是一样的:把nps服务端给你的连接信息交给npc。
3. 群晖上用Docker跑起npc的完整步骤
3.1 第一步:确认Docker环境
群晖从DSM 7.2开始在套件中心里叫Container Manager,老版本叫Docker。打开套件中心,搜索Container Manager或者Docker,如果没安装就先安装,这个操作很基础,几分钟就能完成。
装好之后,先检查一下硬件架构。群晖的主流机型分x86_64和ARM架构两种,家用比较常见的DS220+、DS920+都是x86_64,像DS420j这类低端家用机型很多是ARM。架构决定了你要拉哪个平台的镜像,这个信息可以在控制面板的「信息中心」里查到。拉错架构的镜像,容器可能启动报错或者根本无法运行。
另外建议把Container Manager升级到最新版,因为不同版本创建容器时界面有些差异,如果在网上查资料,别人用的界面和你不一样,很容易对不上。更新到最新版,至少能保证大部分找到的教程界面是匹配的。
3.2 第二步:获取npc连接凭证
npc不能自己凭空连接nps,必须在nps后台先创建一个客户端,拿到对应的vkey。这个操作在nps的Web管理后台里进行,打开8080端口的管理界面,登录后在「客户端」页面点击新增客户端。
新建客户端时,注意几个地方:基本验证里填一个备注,方便区分设备,比如家里NAS;压缩、加密这些选项按需开启,如果两台机器之间的流量要走公网,建议开启加密;最重要的字段是「唯一验证密钥」,也就是vkey,这个值可以手动指定一个复杂一点的字符串,也可以让系统自动生成。创建完成后,客户端列表里会显示这个vkey,复制保存,后面配置npc要用。
这里有一个很常见的认知误区,很多人以为npc是客户端,随便填个密码就能用。实际上nps后台不先创建客户端,npc拿着任何vkey去连都会失败。所以顺序上一定要先有nps,先有vkey,再配置npc。
3.3 第三步:拉镜像并创建容器
npc的Docker镜像,社区里比较常见的有yisier1/npc、edwynn/npc等,功能上没有本质区别,选一个star多的即可。这里以yisier1/npc为例,因为它的启动参数覆盖比较全,文档也比较清楚。
打开Container Manager,到「注册表」页面,搜索npc,找到你想用的镜像,双击下载。下载完成后,选中镜像,点击「启动」进入创建容器向导。
在「常规设置」里,容器名称随便填,比如npc。最关键的一步是「高级设置」里的网络,这里必须手动改成host模式。群晖的Container Manager界面里,点击「使用与宿主机相同的网络」选项,这对应Docker的host网络。如果不改,默认走bridge,后面端口管理会很麻烦。
接下来配置启动命令。不同镜像的处理方式略有不同,但普遍支持在「命令」一栏直接填写npc的启动参数。比较典型的写法是:
-server=your-nps-domain.com:8024 -vkey=your-vkey -type=tcp把your-nps-domain.com换成你nps服务器的地址,把your-vkey换成刚才在nps后台获取的vkey。如果nps开启了TLS,还需要在命令末尾加上-tls_enable=true。
然后在「存储空间」里,通常需要把npc的配置文件目录挂载出来,因为有的镜像会写入配置或日志。在群晖本地新建一个文件夹,比如/docker/npc/conf,在容器配置界面添加文件夹映射,挂载路径根据镜像文档决定。还有-log路径也可以挂载出来,方便查看运行日志。
最后确认无误后点击「应用」创建容器。如果创建成功,容器会自动启动。群晖的Container Manager会在容器状态里显示运行中,这个还不代表穿透已经通了,还需要看日志确认npc确实连上了nps。
3.4 第四步:验证穿透是否生效
容器创建完之后,先在Container Manager里双击这个容器,进入「日志」页面。能看到类似Successful connection或者connect to server success之类的日志,说明npc已经成功连上nps。如果反复报错,按后面常见问题的思路排查。
npc连上nps之后,还需要在nps后台添加隧道规则,穿透才算真正建立起来。比如你想通过服务器的8000端口访问群晖的Web界面(默认5000端口),就在nps后台找到对应的客户端,点击「添加隧道」,选择TCP隧道,服务端端口填8000,内网目标填127.0.0.1:5000,提交后隧道规则生效。
然后从外网访问http://你的服务器IP:8000,如果能打开群晖的登录界面,说明整条链路已经完全打通。如果打不开,大概率是服务器防火墙没有放行8000端口,或者nps服务的防火墙规则没更新。
这里提醒一下,隧道里的内网目标,在npc和nps在同一个容器网络下可能要用宿主机IP而不是127.0.0.1,但因为我们前面选了host网络,npc直接跑在群晖宿主机的网络栈里,127.0.0.1指的就是群晖本机,所以填127.0.0.1是没问题的。如果选了bridge模式,这个地址就要填群晖在Docker网桥里的IP,一般是172.17.0.1之类,很容易搞混,这也是我坚持用host模式的原因。
3.5 附:用docker-compose管理npc容器的一种方式
虽然群晖的Container Manager图形界面已经很好用了,但有些场景下用docker-compose会更方便,尤其是你还有Portainer这类工具,或者需要在多台设备上保持相同配置时。
假设你已经在群晖上开启了SSH,可以先创建一个docker-compose.yml文件,内容大概是这样:
version: '3' services: npc: image: yisier1/npc container_name: npc restart: unless-stopped network_mode: host command: - -server=your-nps-domain.com:8024 - -vkey=your-vkey - -type=tcp volumes: - /volume1/docker/npc/conf:/conf然后在docker-compose.yml所在目录执行docker compose up -d就能启动。restart: unless-stopped这个策略很关键,它保证群晖重启后容器会自动跟着启动,不用每次手动去点。
群晖的Container Manager现在也支持「项目」功能,可以在界面上传这个docker-compose.yml文件来创建容器,不一定非要开SSH操作。我个人习惯用SSH加compose文件来管理,因为后续改参数、看版本、备份都方便,而且一套配置可以在多台群晖之间复制。
4. 实际使用中的常见问题与排查实录
4.1 容器一直重启,日志里反复报错
这是npc部署后最常见的现象。容器创建完,状态一直在「退出」和「运行中」之间来回跳,点进去看日志,常见的有这几种:
第一种是connection refused,说明npc根本连不上nps服务器的8024端口。排查顺序是:先ping一下nginx服务器地址能不能通;再确认服务器防火墙是否放行了8024端口;最后确认nps服务端确实在运行、确实监听8024。如果用的是云服务器,还要检查安全组规则,这个经常被遗漏。
第二种是vkey incorrect之类的认证失败,说明vkey填错了,或者nps后台对应的客户端已经被删除。重新核对nps后台生成的vkey,注意复制的时候不要带多余空格。Docker容器的command参数里,如果值里有特殊字符,要注意转义。
第三种是容器启动后立刻退出,但日志里什么都没打印就结束了。这种情况大概率是启动命令格式有问题,比如-server=前有空格、参数之间用了中文逗号、或者镜像名不对导致拉到了别的程序。把command简化到最短,先只填-server和-vkey测试,确认能跑通后再添加其他参数。
4.2 隧道显示在线,但外网就是访问不了内网服务
这个问题的排查点往往不在npc,而在内网目标的地址和端口。nps后台添加隧道时,内网目标如果填错了,隧道状态再怎么正常也没用。
比如你想访问群晖的Web界面,内网目标填的是192.168.1.10:5000,但这个IP是群晖在路由器上拿到的地址,如果群晖的IP后来变了,这个目标地址就失效了。最稳妥的办法是把群晖在路由器或者DSM里绑定一个固定IP,或者直接在nps隧道里填127.0.0.1:5000。
另一种情况是服务本身监听的是内网地址而不是所有接口。比如群晖上某个服务只监听了127.0.0.1端口,那么npc转发过去时也要用127.0.0.1去连,不能填群晖的局域网IP。这个细节在访问Docker容器里跑的服务时尤其容易遇到,容器端口没有映射到宿主机上,npc自然连不上。
还有一点,隧道添加成功后要检查nps服务端防火墙和安全组,业务端口没有被放行的话,外部流量根本到不了nps。
4.3 端口冲突与防火墙
npc在host模式下运行时,监听端口和群晖上其他服务用的端口不能冲突。比如你想在nps后台添加一个TCP隧道,服务端端口填5000,从服务器访问时没问题,但如果npc在本地也需要监听某个端口,而那个端口已经被群晖的某个套件占用了,npc就启动不了,或者运行时报address already in use。
排查端口冲突,可以在群晖SSH里执行netstat -tlnp,看一下当前占用端口的情况。也可以在Container Manager日志里找bind相关的报错。解决方法是换一个端口,或者先停掉占用端口的那个套件。
群晖本身的防火墙也值得检查一下。如果DSM防火墙开启,它默认可能会拦截npc出方向的连接,虽然大多数情况下放行了内部网络,但为了保险,可以在防火墙规则里放行从群晖到nps服务器IP/端口的流量,白名单方式更精确。
4.4 关于DSM版本和Container Manager的注意事项
DSM 7.0之前,群晖的Docker套件是老版本,创建容器的流程和现在不太一样,很多老教程里写的界面和现在对不上。DSM 7.2之后全面改成了Container Manager,新增了「项目」功能,对docker-compose的支持也更好了。如果你用的是旧版DSM,建议先去套件中心更新到最新版。
另一个容易踩坑的是群晖系统升级后,部分老镜像可能因为内核版本变化无法正常启动。尤其是一些基于较老基础镜像构建的npc镜像,升级DSM后可能出现容器无法启动、报segmentation fault之类的问题。遇到这种情况,直接拉一个新的镜像版本重新创建容器,一般能解决。
还有一点,群晖的Docker镜像目录默认在系统分区,装太多镜像会占用系统存储。把镜像和容器配置放在存储空间大的硬盘上也值得注意,在Container Manager的设置里可以把Docker根目录改到大容量存储卷。
5. 部署完成后的进阶玩法与安全建议
5.1 不止是远程桌面:npc隧道在群晖上的几种实用场景
穿透跑通之后,能做的事情比想象中多很多。最基础的场景是远程访问群晖的Web界面,在外面用浏览器就能管理下载任务、看照片、上传文件。这个场景只要一条TCP隧道就能满足。
第二个常用场景是外部设备的远程桌面。比如你家里还有一台Windows电脑,想在办公室远程连过去处理一些事情,可以在群晖上通过隧道把Windows的3389端口映射出去。由于npc运行在群晖上,相当于群晖成为了内网所有服务的统一入口,你想要哪个服务被外面访问到,就往nps上添加一条指向对应内网IP和端口的隧道即可。群晖上跑着的其他服务,比如Git仓库、影音库、智能家居控制端,都可以用同样的方式暴露出去。
第三种是HTTP/HTTPS隧道。nps支持HTTP隧道,可以在nps后台绑定域名,让外部用户通过域名访问你家里的Web服务。这个场景适合那些不想记端口、想用域名区分服务的情况。配合nps的HTTP解析功能,一个服务端端口能对应多个域名,比直接用TCP隧道要清爽。
5.2 多客户端、多设备统一管理
nps的Web后台支持创建多个客户端,每个客户端可以属于一台设备。家里不仅有群晖,还有一台Linux服务器、一台树莓派,那就创建三个客户端,每个客户端有独立的vkey和隧道列表。
这个设计在管理上非常有用。你可以一眼看到所有设备的在线状态、流量消耗、隧道列表。某个设备掉线了,日志里能直接看到。不需要登录每台设备的命令行去查,这是比frp更直观的地方。
群晖这边跑的是npc,可以保持一个长期运行的状态。如果以后有多台群晖,每个群晖都创建一个独立客户端,vkey不同,隧道互不影响,管理界面里按备注区分,非常清晰。
5.3 安全加固:别让穿透变成了后门
内网穿透说到底就是把内网服务暴露到公网,安全上一定要处理好,否则等于给自己开了一个没上锁的大门。几个基础但不该省略的操作:
- vkey一定要用足够复杂的随机字符串,不要用默认密码、生日数字这类弱口令。vkey一旦泄露,等于别人可以随意在nps上挂一台客户端。
- nps后台的登录密码一定要改掉,不要用默认的admin/admin,改成强度够高的密码,最好再加个两步验证。
- 尽量给隧道开加密和压缩。nps创建客户端时勾选加密选项,能降低流量被中间人窃听的风险。
- 不要把不必要的服务暴露出去。只开你确实需要远程访问的端口,用完可以临时在nps后台停掉对应隧道。
- 如果nps服务器在云上,阿里云、腾讯云的防火墙安全组尽量只放行必要的端口,别图省事全部放行。
5.4 镜像更新与日常维护
镜像更新是Docker部署绕不开的话题。npc镜像出现新版本,通常意味着bug修复或新功能支持。更新流程不复杂:先在Container Manager里停掉当前npc容器,然后重新拉取最新镜像,再启动容器。注意观察启动命令和挂载配置有没有变化,如果有,需要一并调整。
日常维护不用太频繁,每周或者每月看一眼nps后台的客户端在线状态就够了。流量异常增长、隧道状态报警这些,都是排查安全问题的重要线索。
另外,如果群晖重启过,npc容器没有自动启动,优先检查容器的「重启策略」设置。Container Manager里创建容器时,高级设置里有重启策略选项,选除非停止后总是重启,就能保证群晖开机后npc自动恢复连接。
——
这套方案我已经在朋友家的群晖上稳定跑了大半年,npc容器基本没出过幺蛾子。要说最值得记住的经验,就两条:一是创建容器时一定记得切host网络,这是后期省心的关键;二是先把nps后台的客户端和证准备好再配置npc。只要这两点做对,剩下的就是按部就班填参数的事。群晖上用Docker跑npc,说到底就是把一个内网设备变成可远程管理的节点,真正用起来之后,你会发现它能解决的问题比想象中要多。