做开发时经常会遇到这种情况:本地起了一个 Web 服务,需要让外部来访问——微信支付回调、小程序服务端联调、第三方平台的 webhook、同事的手机、客户的测试页面……对方需要一个「公网可达」的地址/域名,而你的代码还跑在本地、还在改。
最常见的两种做法都有问题:
这篇文章记录的是一套省心的超稳定方案:隧道出口永远只绑 127.0.0.1,公网侧只有一个 Nginx 入口,管理端口全部"隐身"。既满足远程联调,又把暴露面压到最小,安全又稳定。

01 整体思路:公网只留一个口
先记住三条原则:
任何远程发布服务都不要直接监听公网。本地服务监听 127.0.0.1,云主机上的隧道出口也只监听 127.0.0.1;
云主机唯一对外的 Web 入口是 Nginx(80/443),它把子域名转发到本机的 127.0.0.1:端口;
SSH / FRP 这类管理端口不靠"隐藏端口号"保护,而是靠"隐身"——外面扫描时它们看起来不存在,只有你的授权设备能连。
用暴露面对比一下:
02 选隧道:SSH 还是 FRP?
隧道的作用是在「你的电脑」和「云主机」之间建立一条加密通道,把本地端口"搬运"到云主机上。两个方案对比:
| | |
|---|
| | |
| | remotePort 默认绑 0.0.0.0,需配合防火墙 |
| | |
| | |
| | |
| | |
结论:临时开一个口子调试,用 SSH 反向隧道最快;打算长期维护、要同时映射多个服务,用 FRP。

03 方案 A:SSH 反向隧道(最快)
SSH 反向隧道的参数是 -R:远程(云主机)监听某个端口,把流量送回本地。
ssh -N -R 127.0.0.1:18080:127.0.0.1:8000 user@你的云主机IP
含义:登录云主机后,让云主机在 127.0.0.1:18080 上监听,所有连到这个端口的流量,都通过 SSH 加密隧道转回你本地的 127.0.0.1:8000。
关键点:-R 写的是 127.0.0.1:18080,不是 0.0.0.0:18080。只要云主机 sshd 没有开启 GatewayPorts(默认关闭),远程端就只会监听云主机的回环地址,公网扫不到这个端口——这正是我们要的效果。
验证一下(在云主机上执行):
ss -ltn | grep 18080
# 期望看到:127.0.0.1:18080,而不是 0.0.0.0:18080
断线自动重连:autossh
SSH 连接断了隧道就没了,调试到一半断线很恼火。用 autossh 保活:
autossh -M 0 -N -R 127.0.0.1:18080:127.0.0.1:8000 \
-o "ServerAliveInterval=30" -o "ServerAliveCountMax=3" \
user@你的云主机IP
配套安全设置(必做)
04 方案 B:FRP(长期稳定推荐)
FRP 分两端:云主机跑服务端 frps,本地跑客户端 frpc。
云主机 frps.toml(核心项):
bindPort = 7000 # frpc 连上来的控制端口
auth.method = "token"
auth.token = "换成一串足够长的随机字符串" # 两端必须一致
本地 frpc.toml:
serverAddr = "你的云主机公网IP或域名"
serverPort = 7000
auth.method = "token"
auth.token = "和 frps 一致"
[[proxies]]
name = "web-debug"
type = "tcp"
localIP = "127.0.0.1" # 本地服务
localPort = 8000
remotePort = 18080 # 映射到云主机上的端口
一个必须补的坑:remotePort 默认绑 0.0.0.0
FRP 和 SSH 不一样:frps 拿到 remotePort = 18080 后,会把它监听在云主机的所有网卡上(0.0.0.0),等于直接对公网开放。frp 配置本身没有"只绑 127.0.0.1"的开关,所以这一步必须用防火墙补上——只允许本机访问这个数据端口:
# 在云主机上执行:外部访问 18080 一律丢弃,只放行本机(Nginx 要转发给它)
iptables -I INPUT -p tcp --dport 18080 ! -i lo -j DROP
加完再验证:
ss -ltn | grep 18080
从公网 telnet 云主机 IP 的 18080 应该超时;只有云主机本机能访问。这一步别省,很多 FRP 教程默认绑公网,等于把服务直接送出去了,这种组网长久不了,可能用不了几天服务器就卡的不行了。
FRP 的其他加固项
frps 上限制客户端可用端口范围(allowPorts),防滥用;
控制端口 7000 不要靠"换个高位端口"来保护,配合第 06 节的隐身方案;
新版 FRP 支持传输层 TLS 加密,生产化之前记得开。
05 Nginx:子域名统一映射到 127.0.0.1
隧道出口已经落在云主机的 127.0.0.1:18080,接下来让 Nginx 把子域名转发过去,对外只暴露 80/443。
先解析域名:给云主机配一个 A 记录,例如 dev.example.com → 云主机IP。
Nginx 站点配置示例(/etc/nginx/conf.d/dev.conf):
server {
listen 80;
server_name dev.example.com;
location / {
proxy_pass http://127.0.0.1:18080;
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;
# 本地服务用到 WebSocket 时放开下面两行
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
}
}
检查语法并重载:
nginx -t && systemctl reload nginx
然后 https://dev.example.com 就能访问到你本地的调试服务了。强烈建议直接上 HTTPS:构建一个免费证书,几分钟的事——浏览器不再报不安全,微信/小程序环境也不会有混合内容问题。
多个调试服务怎么办
隧道出口端口错开,Nginx 里一个子域名对应一个 127.0.0.1 端口,想开就开、想关就关:
06 保护 SSH / FRP 端口:让它"隐身"
到这里,对外只剩两个口子:Nginx 的 80/443,以及云主机的 SSH(22)和 FRP 控制口(7000)。前者是给所有人访问 Web 的,必须开;后者是给你自己人用的,最招攻击——全球扫描器 24 小时在扫 22 端口做口令爆破。22和FRP的控制端口被攻破,等于这个云主机就废了,系统里面就不知道被塞了什么东西。
传统做法是"换高位端口 + 改白名单 IP",但端口号隐藏不了扫描、固定 IP 白名单又怕动态 IP。我这边选择的是 隐身卫士产品,属于零信任访问控制类产品,思路和上面整篇文章一致:默认拒绝,授权才放行。这个产品最大的优势是不需要白名单IP即可完成客户端授权,非常适合保护22/3389/7000等这种只能自己人登录的端口。
它的工作方式:
云主机上部署隐身卫士服务端,守护 22、7000、3389 等核心端口;
你发布服务的设备上装认证客户端,设备身份用"设备特征 + 证书"绑定;
对未授权设备,这些端口表现为不存在——扫描器扫不到、爆破器没机会、就算账号密码泄露,非授权设备也连握手都完成不了;
策略自适应 IP 变动,不用每次换网络都去改白名单。
一句话总结它的价值:端口不是"藏起来",而是"对未授权者不存在"。
其他防御清单
07 验收:怎么证明暴露面真的小了
搭完别急着收工,做三个验证:
外部访问:换一台不在本地的设备(或用手机流量),访问 https://dev.example.com,能打开说明链路通;
关掉隧道:本地停掉 frpc/ssh 隧道,再访问域名——应该立刻 502 或超时。这证明外部只能通过隧道到达你的服务,没有第二个入口;
看监听:云主机上 ss -ltn,隧道数据端口应该只出现在 127.0.0.1 上;有条件的可以扫一下公网 IP,看不到 22/7000 的真实状态。
这套方案的底层逻辑很简单:把"需要远程访问"和"暴露在公网"这两件事彻底分开。远程访问走隧道 + 反向代理,暴露面只留给 Nginx 一个口;管理端口则让它们"隐身"。本地代码不用部署、联调随时开关、安全边界始终清晰。
这套方案能撑起多大规模?十几台设备 + 一台轻量云主机就够了
如果你要维护的是 10 台左右的开发/测试设备,这套方案加设备的边际成本几乎为零:
设备侧零开销:每台设备只是多跑一条 frpc / autossh 隧道,映射一个 127.0.0.1 端口即可,不需要各自的公网 IP,也不用额外买商业穿透服务;
云主机不用好:隧道只搬运流量、不跑业务,入门档轻量云撑起十几条隧道轻轻松松,一年成本通常只要几百块;
一台 frps 管所有:10 台设备 = 10 个数据端口 + 10 个子域名,Nginx 一张表列清楚,新增设备只是加一行 proxy_pass,想开就开、想关就关;
长期挂着不用管:frp 自带心跳重连、autossh 自动保活,配合 systemd 开机自启,断线自己恢复,不需要人工干预;
规模变大,暴露面不变:不管挂几台设备,公网始终只有 Nginx 一个入口、管理端口始终隐身——10 台设备和 1 台设备的边界成本是一样的。
域名是自己的:通过这套方案映射出去的域名是自己的,即使转到云主机上实际部署,其实也是可以用同样的方式部署,尤其是对带宽要求不是非常大的起步站点。
一句话总结:10 台设备、一台轻量云主机、一个 Nginx 入口——稳定、成本低、暴露面小的远程调试环境,这套配置就够了,不但用于调试,用闲置主机直接上线真实业务也是杠杠滴。
工具清单:
阅读原文:点击这里
该文章在 2026/9/3 17:17:13 编辑过