一、背景与目标
在家庭网络环境中,已获得 公网 IPv4,并希望实现以下目标:
- 使用 域名 + 子域名 对外提供服务
- 仅暴露 80 / 443,不直接暴露任何内网服务端口
- OpenWrt 只负责转发(DNAT)
- 所有 HTTPS、证书、子域名分流 集中在一台局域网反代主机(Nginx)
- 不再使用 VPS / FRP 等中转方案
这是一个典型、标准、可长期维护的公网自建服务架构。
二、目标架构设计
最终期望的网络拓扑如下:
公网用户
↓ 80 / 443
公网 IP(OpenWrt)
↓ DNAT
局域网反代主机(Nginx :80 / :443)
↓
子域名 → 不同内网主机 / 不同端口
设计原则:
- OpenWrt:不提供 Web 服务
- Nginx:统一 HTTPS 入口 + 子域名分流
- 内网真实服务:不直接对公网监听
三、初始异常现象
在配置完成后,出现以下问题:
- 域名与子域名 DNS 解析正常
- 访问子域名时:
- 要么返回 OpenWrt 自签名证书
- 要么直接
Connection refused
- Nginx 配置本身看起来没有明显错误
四、问题一:OpenWrt 抢占 80 / 443
1. 关键证据
使用 curl -vk 访问子域名,发现:
- TLS 证书
CN=OpenWrt - 返回内容:
Rejected request from RFC1918 IP to public server address
这说明:
- 公网 443 实际终止在 OpenWrt
- 请求根本没有到达反代主机
2. 根因定位
检查 OpenWrt 的 uhttpd 配置:
list listen_http '0.0.0.0:80'
list listen_https '0.0.0.0:443'
option rfc1918_filter '1'
含义:
- uhttpd 监听 所有接口的 80 / 443(包括 WAN)
- DNAT 永远无法生效
- RFC1918 过滤直接拒绝“公网 → 私网”的访问路径
3. 修复方式(关键一步)
将 OpenWrt 的 Web 管理界面 限制为仅监听 LAN IP:
list listen_http '192.168.x.1:80'
list listen_https '192.168.x.1:443'
或直接将管理端口改为 8443。
重启服务:
/etc/init.d/uhttpd restart
验证监听状态:
ss -lntp | grep -E ':80|:443'
确认 不再存在 0.0.0.0:80/443。
五、问题二:DNAT 规则缺失
在释放 443 后,外部访问出现:
Connection refused
这意味着:
- OpenWrt 不再接管 443(正确)
- 但 也没有转发给任何内网主机
1. 关键证据
检查防火墙规则:
nft list ruleset | grep 443
无任何输出 → 说明 DNAT 根本不存在
2. 正确的 DNAT 规则
OpenWrt 上必须存在如下转发:
WAN TCP 443 → 反代主机 IP : 443
可通过 LuCI 添加:
网络 → 防火墙 → 端口转发
或命令行(示例):
nft add rule inet fw4 dstnat tcp dport 443 dnat to 192.168.x.y:443
注意:命令行方式需最终固化到防火墙配置中
六、最终验证
1. 反代主机监听确认
在反代主机上:
ss -lntp | grep :443
结果示例:
LISTEN 0 511 0.0.0.0:443 nginx
说明 Nginx 正常监听。
2. 外网验证
curl -vk https://subdomain.example.com/
正确表现:
- TLS 证书来自反代主机(非 OpenWrt)
- HTTP 返回
200 / 302 - 子域名正确分流到对应服务
七、最终可用架构总结
至此,完整架构闭环:
- DNS:子域名解析到公网 IP
- OpenWrt:
- 不监听公网 80 / 443
- 仅做 DNAT 转发
- 反代主机:
- 统一监听 80 / 443
- HTTPS 终止
- 子域名 → 内网服务映射
- 内网服务:
- 不直接暴露公网
- 只信任反代来源
这是一个:
- 最小攻击面
- 职责清晰
- 无需 VPS / 内网穿透
- 可长期维护的标准方案
八、经验总结
- DNAT 永远抢不过本机监听端口
- 公网端口转发前,必须确认路由器本身未监听该端口
Connection refused往往意味着:- DNAT 目标错误
- 或 DNAT 根本不存在
- 反向代理 + 子域名是最清晰、最稳定的公网服务组织方式