
内网入口——代理搭建端口转发你有没有遇到过这种情况出差在外突然要连回公司或家里的内网机器处理一件事或者内网里跑了好几个服务每个都占一个端口想让外面的同事、客户只通过一个地址就能访问再或者路由器是动态IP、没有公网IP但你就是需要一条能随时进内网的通道。这就是“内网入口”要解决的问题。说白了就是把内网里那些默认只对局域网开放的服务通过代理或端口转发的方式安全地暴露到外网让授权的人能访问。这篇文章我会把代理搭建和端口转发这两个常用方案放在一起讲从选型、配置到排障把我实际操作中踩过的坑和验证过的做法都写出来。适合有基本网络概念、想自己动手打通内网入口的开发、运维或者技术爱好者参考。1. 为什么要给内网开一个“入口”1.1 没有公网IP不等于内网服务和外界绝缘大多数公司内网和家庭网络都跑在私有网段比如192.168.x.x这种地址在外面是没法直接访问的。没有公网IP、或者公网IP是动态变化的并不意味着内网机器必须与外界绝缘我们依然可以通过代理服务或者端口转发把内网的服务“托”到一台有公网IP的机器上由这台机器作为入口再把请求转给内网。这里的核心逻辑是外网请求先到入口机器入口机器再根据规则把流量转发到内网具体的主机和端口。整个过程对外表现是透明的用户只跟入口的地址和端口打交道内网的真实拓扑被藏在了后面。1.2 先分清三个概念代理、转发、映射很多人会把代理搭建、端口转发、端口映射混为一谈实际操作前最好分清楚端口映射发生在路由器或防火墙上把公网IP的某个端口映射到内网某台主机的某个端口比如把公网IP的8080端口映射到192.168.1.50的80端口。端口转发由一台具有多个网络接口的主机来操作把从一个网卡接口收到的数据根据端口规则转给另一个网卡接口或者别的IP。所以它是一个更泛化的概念端口映射只是端口转发的一种常见落地方式。代理通常指应用层或者传输层的转发服务客户端先把请求发给代理代理再替客户端去访问目标。反向代理尤其适合做“统一入口”把HTTP、TCP等不同协议的服务集中在同一个域名或端口后面。简单理解端口转发是“快递中转站”只管把包裹按地址运到下一个点代理则是“前台接待”它会根据来访者的需求把请求分配到后台不同的人手上。1.3 什么场景下需要这套方案我梳理下来最常见的三类需求远程管理内网机器人在外面要SSH到公司或家里的Linux服务器或者远程桌面到内网Windows电脑。多个内网服务对外发布内网跑了几个Web系统、数据库、API服务需要让外部协作方访问又不想给人家开一堆复杂网络准入。隐藏内网细节统一由入口分发通过代理把Nginx、Jenkins、GitLab、内部API等收口到一个域名或一个端口下外网用户不用关心内网到底有几台服务器、分别是什么IP。只要命中这几个场景就说明你需要一套可靠的内网入口方案。2. 方案选型什么时候用代理什么时候用端口转发2.1 按业务类型选HTTP入站、TCP入站、远程管理选型的第一原则是看你想要暴露什么类型的流量。如果是HTTP/HTTPS服务比如公司内网的OA系统、测试环境的前端页面、GitLab代码仓库首选反向代理。代理层面可以直接处理域名、证书、负载均衡还能在转发前加一层鉴权灵活性最高。如果是非HTTP的TCP服务比如SSH、MySQL、Redis、各类私有协议反向代理也能做四层转发但Nginx做四层转发时没法做应用层过滤功能会弱一些。这个时候我更倾向于直接用端口转发规则简单又直观。如果是临时需要访问内网的一台机器SSH隧道是最快的方式。它在本地和跳板机之间建立一条加密通道本地端口收到的流量会通过这条隧道转发到内网机器。这个手法可以作为临时应急入口但不适合作为长期对外服务的稳定方案。2.2 按安全等级选要不要暴露端口、要不要加认证另一个关键维度是安全容忍度。端口转发一旦把端口开放到公网就等于把内网服务直接推到门口如果服务本身没有认证或有漏洞风险很高。所以我会给不同场景定一个安全等级低风险临时远程管理用SSH隧道不对外开放长期端口。中风险需要长期对外访问的HTTP服务用反向代理加访问认证、加HTTPS。高风险数据库、消息队列这类基础设施不建议直接端口转发到公网必须通过跳板机加白名单IP访问。这么做的根本原因是哪怕你做了端口转发也不代表要做成“公网裸奔”。入口的统一、认证、IP白名单这些本该是配套动作。2.3 我最终选择的组合以我最近一次给一个小型团队搭内网入口的经历为例目标是把内网的三个Web应用统一暴露出去同时允许两个核心成员在外面SSH进内网开发机。我最终用的方案是“Nginx反向代理 路由器端口映射 SSH隧道”的组合Nginx部署在DMZ区的一台Linux机器上用域名区分三个Web应用启用HTTPS和Basic Auth。路由器上只映射两个端口443给Nginx8022给SSH跳板机。核心成员SSH到跳板机后再用跳板机连接内网其他机器。这个组合的好处是暴露面很小而且规则的边界很清晰到443的流量由Nginx负责到8022的流量专门用于远程管理互不干扰。3. 代理搭建实操用Nginx把内网服务统一收口3.1 安装与基础配置Nginx做反向代理是社区里最成熟的做法。我用的是官方源安装在Ubuntu系统上直接运行sudo apt update sudo apt install nginx -y装好之后先确认版本和默认配置目录避免后面改错文件nginx -v ls /etc/nginx/配置文件的组织方式很关键。默认的nginx.conf里有include /etc/nginx/conf.d/*.conf和include /etc/nginx/sites-enabled/*我习惯把所有反向代理配置写在/etc/nginx/conf.d/下一个域名一个文件命名清晰后期维护不头疼。3.2 HTTP反向代理的关键参数先给一个小型Web应用配置一个最简单的反向代理。假设内网有一台Web服务器跑在192.168.1.10:8080我希望外网用户访问https://app.example.com时请求自动转到这台内网服务器。server { listen 443 ssl; server_name app.example.com; ssl_certificate /etc/nginx/certs/app.example.com.pem; ssl_certificate_key /etc/nginx/certs/app.example.com.key; location / { proxy_pass http://192.168.1.10:8080; 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_pass指定了流量的最终去向Nginx收到请求后会把请求转发给内网服务器。proxy_set_header Host $host保证内网服务器拿到的是原始域名而不是Nginx的IP很多Web应用靠Host头做域名判断少了这行就会出现访问不了或者跳转不对的问题。X-Real-IP和X-Forwarded-For用于把客户端真实IP传递给后端否则后端日志里看到的所有请求IP都是Nginx的IP排查问题会非常痛苦。X-Forwarded-Proto告诉后端请求是HTTP还是HTTPS有些应用会基于这个头生成重定向地址缺了它可能出现明明访问的是HTTPS应用却把用户重定向到HTTP的情况。3.3 TCP/UDP四层转发配置如果只想把某个TCP端口原样透传到内网可以用Nginx的stream模块。比如把入口机器的3307端口转发到内网数据库服务器的3306端口stream { server { listen 3307; proxy_pass 192.168.1.20:3306; } }这个配置需要确保Nginx编译时带了stream模块可用nginx -V查看。四层转发比HTTP层简单得多不解析应用协议本质上就是在TCP层面把字节流从入口端口搬到目标主机端口。所以它也不具备HTTP层的那些高级能力比如根据域名分流、加认证这些只能在TCP层之外另想办法。3.4 给代理加上访问控制把内网服务暴露到公网之后访问控制必须跟着做。我最常用的是Basic Auth加IP白名单的组合。创建密码文件sudo apt install apache2-utils -y sudo htpasswd -c /etc/nginx/.htpasswd opsadmin在Nginx配置里加上location / { auth_basic Restricted Access; auth_basic_user_file /etc/nginx/.htpasswd; allow 203.0.113.10; # 只允许固定出口IP访问 deny all; proxy_pass http://192.168.1.10:8080; }这里要提醒一点Basic Auth的密码是Base64编码传输的不是加密所以必须配合HTTPS一起用否则密码等于明文在网络上传了一遍。IP白名单适合固定办公网络、固定出口IP的场景配合使用能把暴露面压缩得很小。我还建议在Nginx层加一个简单的限流防止入口被刷limit_req_zone $binary_remote_addr zoneapp_limit:10m rate5r/s; server { location / { limit_req zoneapp_limit burst10 nodelay; # 其余配置 } }限流参数这里简单说明一下rate5r/s表示每秒平均允许5个请求burst10表示瞬时最多能再排队处理10个突发请求nodelay表示排队时不额外等待。这个配置对内部系统完全够用能挡住大部分恶意扫描。4. 端口转发实操三种常用方式4.1 路由器端口映射最直接的方式如果你掌控了出口路由器端口映射是最简单直接的。我以常见的企业或家用路由器为例登录路由器管理后台找到“端口映射”或“虚拟服务器”功能添加一条规则外部端口8022内部IP192.168.1.30内部端口22协议TCP这样外网用户访问路由器公网IP的8022端口就等价于访问内网192.168.1.30的22端口。这里有几个容易踩的坑内网IP建议设置成静态地址或者给设备配置DHCP保留否则设备重启后IP变了转发规则就失效了。外部端口和内部端口不一定非要相同。比如外部用8022、内部用22这样可以避免直接暴露默认端口减小被扫描器命中的概率。很多路由器默认只允许配置有限条数的映射规则注意优先级关系避免规则冲突。4.2 Linux iptables端口转发在Linux服务器上做端口转发最常用的工具是iptables。它工作在内核层面性能好规则灵活。假设入口机器有两块网卡一块连外网、一块连内网现在要把外网网卡收到的8000端口流量转发到内网主机192.168.1.40的8000端口。首先开启内核IP转发sudo sysctl -w net.ipv4.ip_forward1要让这个设置在重启后依然生效需要编辑/etc/sysctl.conf确保里面有一行net.ipv4.ip_forward 1然后配置iptables规则核心是DNAT和SNAT# 将到达本机8000端口的TCP流量目标地址改为内网服务器 sudo iptables -t nat -A PREROUTING -p tcp --dport 8000 -j DNAT --to-destination 192.168.1.40:8000 # 将转发出去的流量源地址改为本机保证回程流量能正确返回 sudo iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.40 --dport 8000 -j SNAT --to-source 192.168.1.1第一行是“入口改写”告诉内核凡是到8000端口的包目的地改成内网主机第二行是“源地址改写”让内网主机收到包时看到的来源是入口机器而不是外网某个随机IP否则回包会直接发给外网客户端导致连接失败。保存规则时不同发行版命令不一样。Ubuntu可以装iptables-persistentsudo apt install iptables-persistent -y sudo netfilter-persistent saveCentOS/RHEL则用sudo service iptables saveiptables的坑主要在两个方面一是很多云服务器的安全组会在外部先拦一道光配iptables没用二是回程路由如果内网主机的默认网关不是这台入口机器SNAT规则必须保留否则响应流量走别的路径回来后连接状态会错乱表现就是“请求发出去了但一直卡住没有响应”。4.3 Windows netsh端口转发Windows服务器上做端口转发我用的是内置的netsh命令它比第三方工具更省心。它支持IPv4和IPv6配置语法很简洁。比如把Windows服务器的8080端口转发到内网的192.168.1.60:80netsh interface portproxy add v4tov4 listenport8080 listenaddress0.0.0.0 connectport80 connectaddress192.168.1.60参数含义listenport入口机器监听的端口listenaddress监听的地址0.0.0.0表示所有网卡都监听connectport内网目标端口connectaddress内网目标IP查看现有规则netsh interface portproxy show all删除某条规则netsh interface portproxy delete v4tov4 listenport8080 listenaddress0.0.0.0这套方式做起来很快但有一个前提Windows防火墙必须放行监听端口否则外部流量根本到不了portproxy服务。另外netsh portproxy不支持像iptables那样限制源地址需要借助防火墙规则来补充访问控制。4.4 用SSH隧道的场景补充如果只是想临时让某个人从外面访问内网机器但又不想在路由器上开新端口SSH隧道是很好的补充手段。它依赖一台能被外网访问的跳板机然后通过SSH建立加密通道把本地端口和内网目标端口连接起来。在本地机器执行ssh -L 9000:192.168.1.70:3306 userpublic-server这条命令的意思是本地的9000端口接收流量经过SSH隧道到达public-server后由public-server再转发到内网192.168.1.70的3306端口。之后在本地用mysql -h 127.0.0.1 -P 9000就能访问内网数据库了。如果要保持隧道长时间在线推荐加-N参数表示不执行远程命令只做端口转发同时用-f放到后台运行ssh -N -f -L 9000:192.168.1.70:3306 userpublic-server这种方式的优势是加密和复用对外的端口只有跳板机的22端口内网服务不直接暴露。劣势是流量要经过跳板机带宽瓶颈出现在跳板机的网络条件上不适合跑大流量业务。5. 常见问题与排查实录5.1 端口通了但页面一直转圈这是我遇到最多的问题。用telnet或nc测试入口端口是通的但浏览器打开页面就是一直加载。排查思路通常是这样的先确认Nginx日志里请求是否到达、转发目标是否可达、后端服务是否有响应。Nginx错误日志默认在/var/log/nginx/error.log访问日志在/var/log/nginx/access.log。我碰到过一次典型情况Nginx配置正确端口也是通的但页面一直没有响应。后来发现是Nginx解析不了内网服务器的域名因为后端地址我写的是机器名而Nginx运行环境的/etc/hosts里没有这个解析改成内网IP后问题立刻解决。还有一次是后端服务绑定的是127.0.0.1只监听本地地址内网其他机器访问不了所以Nginx转发过去直接被拒绝。这个需要检查后端服务的监听地址确保它监听在0.0.0.0或内网网卡地址上。5.2 从内网访问没问题外网就不行这个现象通常不是应用本身的问题而是网络链路的问题。我从底层往上排查按这个顺序来第一步入口机器的防火墙是否放行了对应端口。Linux用ufw status或iptables -L -nWindows用防火墙高级安全看入站规则。第二步云服务器的安全组是否放行。很多云平台有独立于系统防火墙的安全组策略漏配了就是不同。第三步路由器NAT规则是否正确。外部端口、内部IP、内部端口、协议类型必须一一对应。第四步内网主机的防火墙是否允许来自入口机器或外部IP的流量。这四步里最常见的是第二步和第一步因为很多人只配了iptables或者只配了安全组以为只做一件事就够了。5.3 安全问题端口暴露后如何保护端口转发把内网服务暴露到公网等于把门打开了一条缝。保护不到位这条缝就会被扫描器盯上。我能给到的最中肯的建议转发越少越好每多一个端口就多一份暴露面。所有能加认证的入口都要加认证HTTP服务优先上HTTPS基础认证这种方式虽然简单但配HTTPS后安全性完全可以接受。开启日志至少保留30天。Nginx的访问日志默认就有但要注意日志文件增长配一下logrotate。对数据库、Redis这类服务除非业务真的需要否则永远不要直接端口转发到公网。用SSH隧道代替。之前我们团队就吃过一次亏有同事图省事把内网Redis的6379端口直接映射到公网密码又设得太简单结果被扫描器命中数据被加密勒索。后来我们彻底整改把所有基础设施类服务全部收回到SSH隧道后面再也没有发生过类似事故。这不是危言耸听而是实实在在会发生的代价。写在最后端口转发和代理搭建这件事本质上是在给内网划一条边界再在这条边界上开几扇受控的门。代理是那扇带门禁的主门端口转发是几扇侧门SSH隧道则是只有你知道密道的暗门。门开多少、什么时候开、给谁开都取决于你对业务和安全边界的理解。我自己的习惯是能收敛到一个入口就绝不多开第二个能给入口加上认证的绝不做裸奔转发能用临时隧道解决的问题绝不长期占用端口。这套原则帮我避免了不少麻烦也希望对你有些参考价值。