很多人把内网穿透做成了“能连上”,但没做成“能扛打”。
最常见的翻车姿势有三种:
• 直接把 WSL 里的服务暴露到公网
• 以为 FRP 自带安全能力,结果把它当成网关
• 能访问是能访问,但没有认证、没有限流、没有封禁机制
如果你的目标不是“临时打通一下”,而是想把一套跑在 WSL 里的服务,长期、稳定、相对安全地开放给公网访问,那么真正靠谱的做法,不是单点加固,而是把整条链路分层设计。
我这次要讲的,就是一套适合长期运行的组合:
WSL + FRP + Nginx Basic Auth + Fail2ban。
它的核心思想很简单:
• FRP 负责打洞
• Nginx 负责统一入口和鉴权
• Fail2ban 负责把可疑 IP 直接踢出去
• WSL 内服务只监听本地回环,不直接见公网
这不是最花哨的方案,但它足够稳、足够清楚,也足够适合真实生产环境的轻量暴露场景。
一、先说结论:安全不是靠某一个组件,而是靠分层
很多人第一次接触 FRP,会天然觉得:
“我都加了 token 了,应该已经挺安全了吧?”
答案是:不够。
FRP 的本职工作是“建立一条隧道”,不是“充当业务安全网关”。
也就是说,FRP 只能帮你把流量送进来,但不能替你判断:
• 这个访问者该不该进
• 这个人是不是在暴力猜密码
• 这个请求是不是异常行为
• 这个入口是不是应该被限速和封禁
所以,一套真正合理的公网暴露架构,应该是四层分工:
1. WSL 内服务层:只监听 127.0.0.1
2. FRP 隧道层:负责把公网请求转回本地
3. Nginx 入口层:负责 HTTPS、反代、Basic Auth、统一域名入口
4. Fail2ban 行为层:负责根据日志自动封禁恶意 IP
这四层叠在一起,才叫“能长期跑”的方案。
二、这套架构到底长什么样

先看最终链路:
Internet -> Nginx:443 -> FRPS映射端口 -> FRPC -> WSL:127.0.0.1:服务端口
如果你要暴露的是 OpenClaw 之类的本地服务,典型链路就是:
Internet -> Nginx:443 -> FRPS:61879 -> FRPC -> WSL:127.0.0.1:18789
如果你还想保留 SSH 运维通道,则是:
Internet -> FRPS:60022 -> FRPC -> WSL:127.0.0.1:22
这里最关键的设计点,不是端口号本身,而是这三个原则:
• 公网用户永远优先走 Nginx 域名入口,不直连裸端口
• WSL 内业务服务永远只监听 127.0.0.1
• FRP 只传输,不承担上层业务访问控制
换句话说,FRP 是运货的,Nginx 才是门卫,Fail2ban 是保安。
三、为什么 WSL 内服务一定要绑定 127.0.0.1

这是整套架构里最容易被忽略、但又最关键的一点。
很多人打通穿透之后,会忍不住把本地服务直接改成监听 0.0.0.0。这样做的短期效果是“方便”,但长期效果通常是“出事”。
因为一旦服务监听到所有网卡:
• 它可能被局域网内其他设备直接访问
• 它可能绕过你原本设计好的统一入口
• 它会让你搞不清楚到底是谁在访问它
• 你后续的认证、审计、限流都会变得混乱
更稳妥的方式,是让 WSL 里的 SSH 和业务服务都只监听本地回环:
• SSH:127.0.0.1:22
• OpenClaw:127.0.0.1:18789
然后由 frpc 负责把这些本地端口“转交”给公网服务器。
这样做的好处是:即使 FRP 某天停了、Nginx 某天改了,你本地服务本身也没有直接暴露在公网面前。
这就是所谓的:后端隐藏,入口统一。
四、FRP 正确的角色:只负责穿透,不负责安全决策

FRP 很强,但不要对它寄予错误的期待。
它该做的事情是:
• frps 在公网服务器上监听控制端口
• frpc 在 WSL 里主动连接公网服务器
• 建立稳定转发通道
• 把指定的 remotePort 映射到本地服务
它不该承担的职责是:
• 替代 HTTPS 证书和域名入口
• 替代登录认证
• 替代访问频率控制
• 替代恶意行为封禁
所以 FRP 的安全重点,应该放在“收紧自己”,而不是“幻想它保护一切”:
• 打开 auth.method = "token"
• 使用足够强的随机 token
• allowPorts 只放行确实需要映射的端口
• dashboard 只监听 127.0.0.1
• 定期轮换 token
一个很实用的 frps.toml 思路如下:
bindPort = 7000auth.method = "token"auth.token = "换成一串高强度随机值"allowPorts = [ { start = 60022, end = 60022 }, { start = 61879, end = 61879 }]webServer.addr = "127.0.0.1"webServer.port = 7500webServer.user = "admin"webServer.password = "换成强密码"log.to = "/var/log/frps.log"log.level = "info"
这套配置表达的意思非常明确:
• 我只允许两类映射端口存在
• 我不把 dashboard 暴露给公网
• 我默认一切最小化开放
这才是 FRP 在安全体系里的正确姿势。
五、FRPC 的关键不是“能连上”,而是“回源回得干净”
在 WSL 这一侧,frpc.toml 的核心原则只有一个:
所有 localIP 都尽量写成 127.0.0.1。
示意配置如下:
serverAddr = "你的公网IP或域名"serverPort = 7000auth.method = "token"auth.token = "与 frps 一致"[[proxies]]name = "wsl-ssh"type = "tcp"localIP = "127.0.0.1"localPort = 22remotePort = 60022[[proxies]]name = "openclaw-ui"type = "tcp"localIP = "127.0.0.1"localPort = 18789remotePort = 61879
这里的设计意图是:
• SSH 只给 frpc 读
• OpenClaw 只给 frpc 读
• WSL 自己不对公网直接开门
很多人出问题,往往不是 FRP 配不通,而是本地服务监听地址错了、或者误把 WSL 的服务开放成了对外可见。
一句话概括:
FRPC 的价值,不只是“连通”,更是帮你把本地服务关在内层。
六、真正的公网入口,应该交给 Nginx
如果你的服务需要长期提供给自己或少数可信用户访问,那么最理性的做法,是不要让别人去记 IP:端口,而是统一走一个 HTTPS 域名入口。
比如:
https://proxy.example.com
这样做有四个好处:
1. 统一入口:用户只需要记一个域名
2. HTTPS 加密:不让认证信息裸奔
3. 便于加认证:Basic Auth 很容易直接挂在入口层
4. 便于观察和封禁:日志集中在 Nginx,Fail2ban 更容易接管
Nginx 在这套架构里的角色,不是简单“转发一下”,而是“让所有公网访问先过我这一关”。
这就意味着,FRP 暴露出来的业务端口,最好只作为 Nginx 的上游,不要被用户直接拿去访问。
七、为什么 Basic Auth 虽然朴素,但依然非常实用

一提到认证,很多人会觉得 Basic Auth 太老了,不够高级。
但对“个人服务、轻量后台、受控访问入口”这种场景来说,Basic Auth 反而有三个很大的现实优势:
• 部署成本极低
• 兼容性极强
• 能立刻拦掉大多数无脑扫描
它当然不是万能的,也不是企业级零信任方案,但在“给自己的服务再加一道门”这个目标上,非常好用。
Nginx 里加 Basic Auth 的思路也很简单:
先生成密码文件:
sudo htpasswd -c /etc/nginx/.htpasswd clawadmin
然后在站点配置里加:
auth_basic "Restricted";auth_basic_user_file /etc/nginx/.htpasswd;
如果再配合 HTTPS,效果就很实际:
• 没密码的人,连页面都看不到
• 扫描器和机器人,会先撞在 Basic Auth 这堵墙上
• 错误尝试会进日志,方便 Fail2ban 后续接手
所以这里的关键不是“Basic Auth 高不高级”,而是:
它能不能帮你把最常见、最无脑、最烦人的访问挡在第一层。
答案是:能,而且很省事。
八、Nginx 在这套方案里的核心价值:统一入口、加密传输、顺手打日志

一个典型的 Nginx 反代站点,可以这样理解:
• 监听 80/443
• 80 自动跳转到 443
• 443 上挂 TLS 证书
• 对访问者先做 Basic Auth
• 认证通过后,再反代到 127.0.0.1:61879
示意配置大概如下:
这里面最重要的,不只是能反代成功,而是它天然给你带来了:
• HTTPS
• 认证入口
• 可审计日志
• 后续限速和封禁的落点
很多安全能力,其实都要靠 Nginx 这一层承接。
九、Fail2ban 才是让这套方案“能扛打”的关键拼图

如果说 Basic Auth 是门锁,那 Fail2ban 就是保安。
它的作用不是防第一次试探,而是防“持续撞门”。
比如:
• 某个 IP 连续猜错多次 Basic Auth 密码
• 某个来源不断暴力尝试 SSH 登录
• 某些扫描器反复探测你的入口
这时候,单靠 Nginx 记日志是不够的;你还需要有人看日志、看出异常、然后立刻封掉这个来源。
Fail2ban 做的正是这件事。
一套比较常见的思路,是至少开启两个 jail:
1. sshd
2. nginx-http-auth
例如:
[DEFAULT]bantime = 1hfindtime = 10mmaxretry = 5backend = systemdbanaction = firewallcmd-rich-rules[sshd]enabled = trueport = 22,60022logpath = %(sshd_log)smaxretry = 5[nginx-http-auth]enabled = trueport = http,httpslogpath = /var/log/nginx/*error*.logmaxretry = 5findtime = 10mbantime = 2h
这套逻辑的效果很直接:
• SSH 猜密码过多,封
• Basic Auth 猜密码过多,封
• 不需要你手工盯日志,系统自动处理
一旦你把 Fail2ban 接上去,这套入口的“韧性”会立刻上一个台阶。
十、这四层叠起来以后,安全效果到底体现在哪
我们来拆一下最常见的攻击路径,看看它会撞在哪一层。
场景 1:机器人扫你的域名
它先撞到的是 Nginx 的 HTTPS 入口。
场景 2:它想直接看后台页面
它先被 Basic Auth 挡住。
场景 3:它开始暴力试密码
错误日志被 Nginx 记下,Fail2ban 根据规则把它封掉。
场景 4:它不走 Web,去打 SSH
SSH 映射虽然还在,但 Fail2ban 同样盯着 sshd。
场景 5:它侥幸绕过前面两层,想直接摸后端
摸不到,因为 WSL 内服务只监听 127.0.0.1。
场景 6:FRP 自身被乱探测
frps 有 token,dashboard 没暴露公网,开放端口也被收敛过。
这时候你会发现,这套方案不是“靠某个点绝对安全”,而是:
每一层都让攻击者多撞一道墙。
这才是实际可用的安全设计。
十一、很多人会踩的几个坑,最好一开始就绕开

坑一:把 FRP 暴露端口直接当最终访问入口
这会导致:
• 没有统一认证
• 没有 HTTPS
• 没有好用的日志观测点
• 也不方便后续限速和封禁
更稳的做法,是让用户只记住你的域名入口,FRP 端口尽量躲在后面给 Nginx 用。
坑二:把 FRP 当成完整安全边界
FRP 不是网关安全系统,也不是 WAF。它只是隧道层。
坑三:WSL 服务监听 0.0.0.0
这会把你的后端直接暴露给更多不必要的网络面。
坑四:只加认证,不做行为封禁
有门锁,没有保安;锁会一直被试。
坑五:SSH 长期保留密码登录
这不是不能用,而是不适合长期暴露。稳定后最好切到密钥登录,再逐步关掉密码认证。
十二、如果你还保留 SSH 运维,建议顺手把它也收紧
很多人把业务入口做得很紧,结果 SSH 还在裸奔。
如果你确实需要通过 FRP 保留 SSH 运维,建议至少做到:
• 使用普通用户登录,不直接用 root
• 优先切到公钥认证
• 视情况关闭密码登录
• 配合 Fail2ban 持续观察失败尝试
也就是说:
• remotePort = 60022 可以保留
• 但真正的重点在于 SSH 策略,而不是 FRP 端口本身
FRP 只是把路打通,SSH 自己还是要守好门。
十三、为什么这套方案特别适合 WSL 场景
WSL 这种环境有个天然特点:
• 本地跑服务很方便
• 但公网直出不够优雅
• 内外网边界容易混
• 很多人为了省事,直接“能访问就行”
而这套方案刚好能把 WSL 的短板补上:
• FRP 解决“从公网进来”的问题
• Nginx 解决“统一入口、域名、TLS、认证”的问题
• Fail2ban 解决“长期暴露后会被试探”的问题
• 回环绑定 解决“后端不要乱露”的问题
它的优点不是某个组件多高级,而是:
每个组件都只做自己最擅长的那一部分。
所以整体才会稳。
十四、一套适合长期运行的最小暴露原则
如果让我把全文压缩成一句话,那就是:
入口统一,后端隐藏,鉴权前置,异常封禁。
再展开一点,就是:
• 公网入口尽量只留 80/443
• 业务服务不直接裸露
• FRP 只做打洞
• Nginx 负责鉴权和反代
• Fail2ban 负责处理异常行为
• SSH 作为运维通道单独收紧
很多所谓“终极安全方案”,其实写得很热闹,但最后落不到配置层。
而这套方案的好处是,它不是 PPT 安全,也不是概念安全,而是:
你真能一项一项落下去。
十五、最后的落地建议:先别追求炫技,先把四件事做扎实
如果你现在正准备把一套 WSL 服务稳定暴露到公网,我最建议你优先确认这四件事:
1. WSL 内业务是否只监听 127.0.0.1
这是内层边界。
2. FRP 是否只开放必要端口,并启用了 token
这是隧道层边界。
3. Nginx 是否已经启用 HTTPS + Basic Auth
这是公网入口边界。
4. Fail2ban 是否真的在盯 sshd 和 nginx-http-auth
这是行为层边界。
只要这四件事都做扎实,你这套架构就已经从“勉强可用”,进化到了“可以长期运行”。
结语
真正成熟的公网暴露方案,从来都不是“把服务放出来”这么简单。
它要解决的,从来不是连通性一个问题,而是四个问题:
• 怎么连进来
• 从哪里进来
• 进来前怎么验身份
• 乱试的人怎么踢出去
而 WSL + FRP + Nginx Basic Auth + Fail2ban,正是一套把这四件事讲清楚、做完整、还能持续跑下去的组合。
如果只用一句话总结这套思路,那就是:
FRP 负责连通,Nginx 负责守门,Fail2ban 负责出手,WSL 后端负责藏好。
这,才是一套真正适合长期运行的终极安全配置。
夜雨聆风