nps 内网穿透实战:npc 配置、隧道类型与排障指南
办公室角落那台旧笔记本上跑着一个库存查询页面仓库的同事在外地出差打开链接就是一片空白——这是我被问得最多的一类问题。内网穿透这套东西听起来像是网络工程师的活实际上只要你手上有台能被公网访问的服务器再加上 nps 这个工具半小时就能把内网里的服务安全地引出去。nps 的做法和路由器上的端口映射完全不同它不需要你有公网 IP也不用去动路由器而是让内网机器主动向公网服务器拨出一条长连接外部请求顺着这条连接回到内网再由内网机器交给本地服务。这篇文章我按自己的实际操作顺序来写从选服务器、改 nps.conf、拉起 npc到隧道类型的取舍和几个我踩过的坑配置都给到可以直接抄的程度。适合手上有 NAS、开发机、树莓派或者办公内网服务需要临时或长期对外开一个入口的人看也适合想搞清楚这类工具底层到底在干什么的读者。1. nps 到底替你做了哪件事把内网地址翻译成公网入口1.1 从一个仓库同事打不开的页面说起内网服务不外乎长这样某台机器上跑着192.168.1.20:8000同一个路由器下的电脑都能打开出了这个网段就彻底失联。想让外面的人访问通常只有三条路可走。第一条是把服务搬到公有云上改造成本高数据还得跟着迁第二条是在路由器上做端口映射前提是运营商给了你公网 IP很多家庭宽带和办公宽带早就换成大内网了而且多个服务抢一个 80 端口也难协调第三条就是本文要讲的内网穿透——内网机器主动向公网服务器拨号维持一条常驻连接公网服务器收到外部请求后把字节流顺着这条已经建好的连接塞回内网。nps 属于第三条路里比较完整的一套实现。它由两部分组成跑在公网服务器上的服务端叫nps跑在内网机器上的客户端叫npc。整个链路的走向是外部用户访问公网IP:9001→ nps 发现 9001 这个端口绑定在某条隧道上 → 把请求写进对应 npc 的长连接 → npc 收到后转发给隧道里配置的local_ip:local_port→ 内网服务返回响应 → 原路回到外部用户。整个过程里路由器、光猫、运营商那边一个字都不用改。1.2 nps 和 frp、ngrok 这类方案的差别在哪同一个需求工具选型其实取决于你要解决的是一次性把服务露出去还是长期管理一批内网节点。我把自己用过的几类放一起对比一下方便你对号入座。方案类型典型代表配置方式适合的场景需要留意的点面板驱动型nps服务端 Web 面板 客户端一个 vkey多台内网机器、需要统一查看在线状态面板本身要加固别裸奔在公网配置驱动型frp服务端与客户端都写配置文件配置纳入版本管理、批量下发改一条隧道要动配置并重启客户端托管服务型ngrok 类注册账号、一条命令拉起临时演示、给别人看几分钟免费额度有限域名通常是随机分配的我自己的习惯是给客户做临时演示用托管类省事公司内部要长期挂着几台机器用 nps 的面板管着如果整个流程要写进部署脚本、跟着代码仓库走那配置驱动的方案更顺手。nps 最舒服的地方是客户端侧几乎零配置——内网机器只要一个vkey就能上线隧道怎么开、开在哪个端口全在服务端面板上点几下就完事不用登录到内网机器上改文件。1.3 两个角色、一个 vkey先把概念对齐开始动手前有几个名词先说明白不然后面看配置文件会晕。bridge_port默认 8024npc 拨号连接 nps 用的端口也叫桥接端口。它只负责把管道建起来不承载业务流量。服务端口隧道对外暴露的端口比如你在面板上建了 9001那外部访问的就是公网IP:9001。local_ip / local_port内网服务实际监听的地址和端口注意这两个值的参照物是npc 所在的那台机器不是 nps 服务器。vkey客户端身份凭据。nps 的配置文件里有个public_vkey等于允许哪些客户端免账号接入的默认口令。提示vkey泄露的后果和把隧道入口的钥匙交出去是一样的。默认的123一定要换掉而且安装完第一件事就是改它。有一条经验值得提前说很多新手会把服务端口和bridge_port混在一起觉得既然客户端连的是 8024那 8024 就该是业务入口。实际上这两条路是分开的8024 只需要对客户端所在网络开放业务端口才对最终用户开放。搞清楚这一点后面排查问题时会少走很多弯路。2. 公网那台机器从开放端口到面板能登进去2.1 端口规划先做别等报错再回头改服务端最容易翻车的地方不是软件本身而是端口。我的做法是装之前先在纸上或者备忘录里列一张清单照着这张表去开安全组和系统防火墙一次到位。用途默认端口需要放行给谁说明桥接端口8024/tcp所有 npc 客户端可改成别的端口改完两端都要同步Web 管理面板8080/tcp只放行你自己的办公 IP强烈建议不要对全网开放HTTP 转发80/tcp所有访问者做域名转发时才需要HTTPS 转发443/tcp所有访问者需要证书文件业务隧道9000-9100/tcp所有访问者按需规划成一个区间别用到哪开到哪P2P 牵线6000/tcpudp客户端与访问者只有用点对点模式时才需要这里有个反复出现的坑云服务器的安全组和系统自带防火墙是两个独立层面安全组放行了系统里firewalld或ufw拦着照样不通。我一般会把三个命令连着执行一遍确认先看本机有没有监听ss -tlnp | grep 8024再从本机curl一下面板端口最后换个网络环境用telnet 公网IP 8024验证外部可达性。三段都通才说明这条链路是干净的。2.2 安装与用 systemd 托管起来我习惯把 nps 装在/opt/nps目录结构里会有nps二进制、conf/、web/三部分。官方提供了一键安装服务的命令装完可以直接用systemctl管mkdir -p /opt/nps cd /opt/nps # 解压发行包后目录里应包含 nps、conf、web ./nps install systemctl daemon-reload systemctl enable --now nps systemctl status nps --no-pager如果你不太喜欢install帮你写的东西或者需要自定义运行参数自己写一个 unit 文件更可控[Unit] Descriptionnps server Afternetwork.target [Service] Typesimple WorkingDirectory/opt/nps ExecStart/opt/nps/nps Restartalways RestartSec5 LimitNOFILE65535 [Install] WantedBymulti-user.target为什么坚持用 systemd 而不是nohup ./nps 三个非常实在的理由开机自启服务器重启后不用你再登录一次进程崩了自动拉起来Restartalways那行就是干这个的日志统一进journalctl排查问题时journalctl -u nps -f就能盯着看。最后那个LimitNOFILE也别省隧道一多文件描述符很容易撞到默认的 1024 上限撞上之后的症状是突然所有隧道都不通了重启就好非常难查。2.3 conf/nps.conf 里真正需要动的那几行配置文件字段不少但绝大多数保持默认就行。下面是我每次都会过一遍的部分appname nps runmode prod # Web 管理面板 web_ip 0.0.0.0 web_port 8080 web_open_ssl false # 桥接参数 bridge_type tcp bridge_port 8024 bridge_ip 0.0.0.0 public_vkey 换成你自己的随机串 # HTTP/HTTPS 转发端口 http_proxy_port 80 https_proxy_port 443 https_just_proxy true # 日志 log_level info log_path /var/log/nps.log # 用户权限 allow_user_login false allow_user_register false逐条说下为什么这么改。runmode从dev改成prod是为了关掉一些调试行为、让日志更干净。public_vkey必须是随机长串我一般用openssl rand -hex 16生成一个图省事用密码管理器里的随机串也行。log_level保持info就好调到debug会在流量大的时候把磁盘写满这个坑我踩过一次服务器磁盘告警才发现是日志惹的祸。allow_user_register关掉是防止有人在面板上自助注册账号——面板对公网开着的时候这个默认值是挺危险的。改完配置记得systemctl restart nps然后journalctl -u nps -n 50看一眼有没有报错。配置文件里任何一处语法写错进程会直接起不来日志里会告诉你哪一行有问题。2.4 登进面板之后要做的前三件事浏览器打开http://公网IP:8080默认账号密码在发行包的说明里能找到老版本是admin/123新版首次启动会随机生成并打印在日志里具体以你的版本为准。登进去之后别急着建隧道先把这三件事办了改掉面板密码、确认public_vkey已经换掉、把面板端口从 8080 改成不常见的高位端口。这三步加起来不超过两分钟但能挡掉绝大多数扫描。面板里有个客户端列表npc 上线后会出现在这里能看到它的唯一标识和在线状态。这个页面是后面排查问题的第一个抓手——如果客户端不在这里说明桥接都没建起来问题出在网络层如果客户端在线但业务不通问题就在隧道配置或内网服务本身。把这两种情况分开排查效率会高很多。3. 内网这台机器npc 接进来的两种姿势3.1 命令行一把梭临时验证用这个只是想确认能不能通一条命令就够了./npc -server公网IP:8024 -vkey你的vkey -typetcp几个参数的含义分别是-server是服务端的桥接地址-vkey是身份凭据-type指定桥接使用的传输方式可选tcp、kcp、tls具体支持情况看你的版本。跑起来之后服务端面板的客户端列表里应该立刻出现一条新记录。这时候去面板上建一条 TCP 隧道把服务端口指到 9001、目标地址填127.0.0.1:8000再从外网访问公网IP:9001页面能出来就说明整条链路通了。命令行的方式适合快速验证缺点也很明显关掉终端进程就没了而且参数散在命令里不好维护。验证通过之后还是要落到配置文件上。3.2 配置文件方式长期驻留应该这么写npc 的配置文件叫npc.conf写法大致是[common] server_addr公网IP:8024 conn_typetcp vkey你的vkey auto_reconnectiontrue max_conn1000 flow_limit1000 rate_limit1000 # 本地状态查看界面可选 # web_usernameadmin # web_password自定义口令 # web_port8081 # 日志 log_levelinfo log_path/var/log/npc.log重点解释几个字段。auto_reconnectiontrue一定要打开它负责在网络抖动、运营商回收连接之后自动重连没有它就得手工重启客户端长期挂着的服务基本没法用。max_conn是连接数上限flow_limit和rate_limit分别是流量和速率的限制单位是 KB不填或设得过大等于不限制具体取值建议按内网服务的实际压力来比如只给同事看个管理后台rate_limit1024就够。conn_type这个字段值得单独说说。默认的tcp在多数网络环境下表现最好兼容性也最广。如果客户端所在网络对长连接不太友好频繁出现断流可以换成kcp基于 UDP抗丢包能力强代价是流量开销略高或者换成tls让桥接流量带上加密。这个切换需要服务端bridge_type和客户端conn_type两边保持一致只改一边会连不上这是我见过最多的改了配置就起不来的原因。3.3 一台服务端挂多个客户端命名规范能省很多事真实的运维场景里通常不是一台内网机器而是好几台办公区一台跑管理后台机房一台跑数据库家里一台 NAS。它们可以共用同一个vkey取决于你的版本是否允许多客户端同凭据但我更建议给每台机器单独生成一个 vkey理由是万一某台机器要下线或者凭据泄露只需要在面板上删掉对应的那条其他机器完全不受影响。客户端的备注名建议写成位置-用途-序号的格式比如office-admin-01、idc-db-02。听起来是小事但等到面板上挂了三十条客户端记录你面对一堆npc-1、npc-2的时候就知道当初多打几个字有多值。隧道命名也一样我一般直接写成用途-端口比如admin-9001、ssh-9002一眼就能对上是哪个服务。3.4 把 npc 做成开机自启内网机器多半也是 Linux同样用 systemd 托管最省心[Unit] Descriptionnpc client Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple WorkingDirectory/opt/npc ExecStart/opt/npc/npc -config/opt/npc/npc.conf Restartalways RestartSec10 [Install] WantedBymulti-user.target注意After那里写的是network-online.target而不是network.target。这两者的区别在于后者只表示网卡驱动加载完了前者才表示网络真的可用。如果写成前者机器重启后 npc 可能比网络先起来连一次失败虽然Restartalways最终也会把它拉起来但日志里会多出几行让人误判的报错。这种细节不写进文档下次换个人维护又要重新踩一遍。4. 隧道类型怎么选TCP、UDP、HTTP 与点对点的适用边界4.1 TCP 隧道九成场景的默认答案TCP 隧道是 nps 里最通用的一类。SSH、远程桌面、自建 Web 服务、数据库连接全都走它。典型配置是服务端口填9001目标地址填192.168.1.20:22外部用户执行ssh -p 9001 用户名公网IP就能登进内网那台机器。有个细节值得提醒服务端口不要选 1024 以下的。Linux 上绑定特权端口需要 root 权限nps 以普通用户身份跑的时候会直接绑定失败日志里提示权限不足很多人看到这个报错会以为是防火墙问题绕一大圈。另外如果内网服务的local_ip就是 npc 所在机器本身填127.0.0.1是最省事的如果服务在同一个内网的另一台机器上务必填那台机器的内网地址比如192.168.1.20而不是127.0.0.1——这个错误我见过太多次症状是客户端在线、隧道也在、访问就是超时。4.2 UDP 隧道视频流、自建服务这类需要单独对待UDP 隧道的配置方式和 TCP 差不多但底层行为完全不同。UDP 无连接nps 需要按来源地址维护会话映射所以更适合那些自己会做重传和容错的场景比如自建的流媒体服务、某些游戏服务端、内网 DNS。用 UDP 隧道的时候要留意两件事一是超时时间空闲一段时间后会话可能被回收表现为过一会儿就连不上重新发起又好了二是不要指望它像 TCP 那样保证顺序如果你的应用本身依赖可靠传输还是老老实实用 TCP 隧道。我的经验是能用 TCP 解决的就别用 UDP除非应用协议本身强制要求。4.3 HTTP 域名转发一个 80 端口挂多个站点这是 nps 比较讨喜的一个功能。做法是把你的域名 A 记录解析到服务端公网 IP然后在面板上新建 HTTP 类型隧道填上域名服务端会按请求里的 Host 头把流量分发给对应的客户端。这样一来80 端口只需要开一次后面挂多少个站点都行——admin.你的域名指到办公区那台机器nas.你的域名指到家里那台 NAS互不干扰。上 HTTPS 的话把证书文件放到服务端的证书目录配置里打开web_open_ssl或者在隧道上单独指定证书https_just_proxy这个开关决定了 HTTPS 流量是直接透传还是由 nps 终止 TLS两种模式各有取舍透传省事、证书在内网侧管理终止 TLS 则由服务端统一处理证书更新证书只改一处我通常选后者因为证书到期的那一刻你会庆幸不用挨个登内网机器。4.4 私密隧道与点对点两种省心的玩法私密隧道适合那种服务只想给特定几个人看的场景。建隧道时设一个访问口令外部用户访问时会先要求输入口令通过了才转发到内网服务。它的好处是不用在业务应用里额外加一层登录临时给同事看个后台特别方便。缺点是口令是共享的谁给了谁你追踪不到所以只适合短周期使用。点对点模式解决的是流量成本问题。前面说的所有隧道数据都要经过公网服务器中转服务器带宽就是瓶颈。点对点模式的做法是服务端只负责牵线让客户端和访问者尝试直接建立连接握手成功后数据不再经过服务器。适合大文件传输、视频流这类吃带宽的场景。代价是它依赖双方网络的可达性如果客户端所在网络做了严格限制打洞可能失败这时候会回退到中转模式。配置上需要服务端开放牵线端口客户端和访问侧也要允许相应流量通过具体端口和开关按你的版本来不同版本字段名略有差异改之前建议先看一眼自带的示例配置。5. 面板一切正常但就是连不上几条真实的排查链路5.1 第一道坎安全组放行了系统防火墙还在拦这是我遇到的最高频问题没有之一。排查顺序我固定这么走从内到外一层层剥# 1. 本机有没有在监听 ss -tlnp | grep -E 8024|8080|9001 # 2. 本机自己能不能访问 curl -I http://127.0.0.1:8080 # 3. 防火墙规则 firewall-cmd --list-ports # CentOS 系 ufw status verbose # Ubuntu 系 # 4. 从外部网络验证 telnet 公网IP 9001第一步没输出说明服务根本没起来或者端口写错了去看journalctl -u nps -n 100。第二步不通说明被本机防火墙拦了firewall-cmd --add-port9001/tcp --permanent firewall-cmd --reload或者ufw allow 9001/tcp。第三步规则都在、第四步还是不通那就去云控制台看安全组很多时候问题就出在这里——尤其新建实例的时候安全组模板只放行了 22 和 80。5.2 第二道坎客户端在线访问就是超时面板上客户端显示绿色在线隧道也建好了外部访问公网IP:9001转圈然后超时这种时候基本可以断定问题出在npc 到内网服务这一段。可能的原因按概率排序local_ip填错了填成了127.0.0.1但服务在别的机器上、local_port写错了比如服务监听 8000 你填了 8080、内网服务所在机器自己的防火墙没放行这个端口、服务只监听了127.0.0.1而没有监听0.0.0.0。最后这条特别隐蔽。有些应用默认只绑定回环地址这种情况下即使防火墙全开、地址全对从 npc 所在机器访问192.168.1.20:8000依然不通。验证方法很简单登到 npc 那台机器上curl 127.0.0.1:8000通、curl 192.168.1.20:8000不通就说明服务只监听了回环地址需要改应用的监听配置。5.3 第三道坎连一阵子就断断了要等或者要重启间断性掉线是最折磨人的一类问题因为刚连上的时候一切正常。我的排查思路是先把谁断的分清楚npc 日志里如果有重连记录说明是桥接连接断了如果 npc 日志干干净净那问题在业务侧。桥接断的原因通常有三类。一是客户端所在网络对长连接不友好运营商的 NAT 会话表有老化时间空闲久了映射就被回收了二是链路质量差导致丢包累积三是服务端或客户端其中一端的资源到了上限。对应处理方式开auto_reconnection、把conn_type从tcp换成kcp、检查LimitNOFILE和max_conn的取值。我有一台放在办公室的机器就是因为办公网络每隔一段时间做一次会话清理换成kcp之后情况明显好转。还有一种情况是 TCP 隧道传大文件的时候卡死小请求都正常一传几十兆就停住。这类现象往往和链路 MTU 有关中间某跳对分片包做了处理导致大包被丢弃。我没有遇到过需要直接调 MTU 的极端情况一般换成kcp或者改用点对点模式就能绕过如果你确实遇到了可以在系统层面调小网卡 MTU 试试但要记得这是权宜之计链路一变可能又要重调。5.4 第四道坎HTTPS 页面能打开但资源全丢域名转发上线之后经常遇到这种画面首页 HTML 出来了样式表、脚本、图片全是 404或者点任何一个链接都跳回了 IP 地址。这几乎百分百是应用生成了绝对地址导致的。后端框架里的站点地址配置、反向代理传来的协议头任何一个环节没对齐应用就不知道自己其实是在 HTTPS 下被访问的。处理办法有两步。第一步去应用配置里把站点地址显式写成你的域名别让它自己猜。第二步在 nps 的配置里打开http_add_origin_header让转发时带上原始请求的信息这样后端就能判断出真实的访问协议和域名。如果是自己写的服务记得读X-Forwarded-Proto和X-Forwarded-Host这两个头。还有个小坑是 DNS 缓存。域名解析改完之后本地和中间解析节点可能还缓存着旧记录表现出来就是我这边能开别人打不开。验证的时候用dig 域名 short直接看解析结果别依赖浏览器浏览器缓存加上 DNS 缓存能让你怀疑人生。6. 从能跑通到敢交付面板、日志与备份的收尾工作6.1 面板安全三件套两分钟能做完面板这东西本身就是个对外服务而且它掌握着所有隧道的开关安全性优先级应该在所有事之前。我固定做三件事把web_port从 8080 换成一个不常见的高位端口比如 4 万以上的随机值把web_ip从0.0.0.0改成只监听内网地址再通过其他方式访问或者至少用云安全组把来源限制在你的固定 IP 上开启web_open_ssl并配上证书避免面板口令明文过网。再补一条容易被忽略的allow_user_login和allow_user_register都关掉。前者关掉之后即使有人猜到了账号密码也没有自助入口后者关掉是防止有人在你的面板上注册账号然后合法地创建隧道。这两项在面板对公网开放的环境里是必须关的默认值不能当安全配置用。6.2 用日志和流量数据回答谁在用服务上线之后一定会有人问你这个月跑了多少流量、哪台机器占用最多。nps 面板上有流量统计log_levelinfo的日志里也会记录连接情况。我一般会做两件事一是给每条隧道设上flow_limit和rate_limit防止某条隧道跑出意外流量二是给日志配一份轮转规则避免日志文件失控。# /etc/logrotate.d/nps /var/log/nps.log { daily rotate 14 compress missingok notifempty copytruncate }最后那行copytruncate是关键。如果日志文件被进程长期持有直接重命名会导致进程继续往旧文件写轮转就白做了。copytruncate是先复制再清空对这类常驻进程最友好。这个细节不写下来下次谁改了轮转配置磁盘告警又会回来。6.3 备份与迁移一个 conf 目录加一份隧道清单nps 需要备份的东西其实很少conf/目录配置加证书、nps二进制、以及一份从面板上导出来或者手动记录的隧道清单。面板上的隧道配置存在数据库里不同版本存储方式不同有的在conf/下的数据文件里所以迁移的时候稳妥做法是把整个 conf 目录打包带走然后在新机器上还原再确认一下bridge_port和各类端口在新环境里是否可用。升级的做法也简单停服务、备份 conf、替换二进制、启动、看日志。不要只替换二进制不备份——我有一次升级完发现新版本改了配置字段名老配置直接起不来靠着备份五分钟回滚要是没备份就得重头配一遍。升级前先在测试机上跑一遍这个习惯值得养成。6.4 资源占用和并发能力的实际感受最后聊聊容量。nps 本身很轻空跑的时候 CPU 几乎为零内存通常几十兆量级主要开销在连接数和转发带宽上。真正决定一台服务器能挂多少隧道的不是 nps 本身而是服务器的带宽和文件描述符上限。我给自己的参考线是中小规模场景几十条隧道、每条约几十个并发连接一台 1 核 2G 的入门机型足够如果主要是文件传输类流量瓶颈永远是带宽而不是 CPU。LimitNOFILE一定要往大了设我一般写 65535。判断上限是否够用可以在面板上看实时连接数或者用ss -s看当前 socket 总量。有个经验性的判断如果出现服务跑几小时之后新连接全部失败重启就好的现象八成就是描述符耗尽这时候先调上限再回头看是不是有连接泄漏。需要提醒的是以上这些数字都来自我自己的使用场景你的业务类型、内网服务特性、访问者分布都会影响结果动手之前建议先小规模跑一周看一段真实的流量曲线再决定扩容策略比任何估算都靠谱。从最早只会用命令行npc -server...硬连到现在把服务端配置、客户端托管、日志轮转、备份流程整套跑顺中间踩的坑基本都写在上面了。如果只能记住一句话那就是先把端口这张表列清楚再去改配置。我前后遇到的连接问题里至少有七成最后都能归结到某个端口没通上剩下的三成里一半是local_ip填错。把这两个地方盯住内网穿透这件事就没什么玄学可言了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →