Ubuntu Server+NGINX+No-IP静态IP环境下,公网IP可ping通但HTTP请求超时(疑似Hairpinning问题)
嘿兄弟,我看你这情况太典型了,先帮你理清楚问题细节,再给你实打实的支招!
环境概况
- 服务器系统:Ubuntu Server v23
- 核心服务:NGINX
- 公网访问方案:通过No-IP绑定动态公网IP(域名
TheSite.com映射到50.47.211.xxx) - 服务器局域网IP:
192.168.1.43
问题现象整理
我把你遇到的情况拆解得更清楚:
- Ping测试完全正常:
- 服务器自身ping公网域名/IP:
root@websrv:/etc/nginx/conf.d# ping TheSite.com PING TheSite.com (50.47.211.xxx) 56(84) bytes of data. 64 bytes from 50-47-211-xxx.evrt.wa.ptr.ziplyfiber.com (50.47.211.xxx): icmp_seq=1 ttl=64 time=0.077 ms - 局域网Windows机器ping公网IP:
C:\Users\shawn>ping 50.47.211.xxx Pinging 50.47.211.xxx with 32 bytes of data: Reply from 50.47.211.xxx: bytes=32 time<1ms TTL=63
- 服务器自身ping公网域名/IP:
- HTTP请求彻底超时:
- Windows机器curl公网域名/IP:
C:\Users\shawn>curl TheSite.com --verbose * Trying 50.47.211.xxx:80... * connect to 50.47.211.xxx port 80 failed: Timed out * Failed to connect to TheSite.com port 80 after 21052 ms: Couldn't connect to server - 服务器自身curl公网IP也会超时(根据局域网机器的表现可推测)
- Windows机器curl公网域名/IP:
- 局域网IP访问毫无问题:
不管是服务器本地还是局域网Windows机器,直接访问192.168.1.43都能正常返回NGINX默认页面,比如服务器本地的测试结果:root@websrv:/home/shawn# curl 192.168.1.43 --verbose * Trying 192.168.1.43:80... * Connected to 192.168.1.43 (192.168.1.43) port 80 (#0) > GET / HTTP/1.1 > Host: 192.168.1.43 > User-Agent: curl/7.88.1 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Mon, 09 Oct 2023 07:09:01 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 615 < Last-Modified: Mon, 23 May 2022 23:59:19 GMT < Connection: keep-alive < ETag: "628c1fd7-267" < Accept-Ranges: bytes < <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...(省略后续HTML内容)
已尝试的排查操作
你已经做了不少基础排查:
- 关闭了Ubuntu服务器的ufw防火墙(
ufw disable) - 路由器(Orbi Pro)配置:
- 设置DMZ指向服务器LAN IP
192.168.1.43 - 端口转发80端口到服务器LAN IP
- 关闭了端口扫描和DoS保护
- 设置DMZ指向服务器LAN IP
问题核心分析:大概率是Hairpinning(发夹路由)问题
这种情况90%都是路由器的发夹路由不支持导致的:
当你在局域网内访问自己的公网IP/域名时,请求数据包从局域网设备发出,到路由器后被转发到公网IP,但路由器没处理好回程流量——本该把数据包直接发回局域网,结果可能直接丢包或者绕去公网兜圈子,最终超时。
Ping能通是因为ICMP协议的处理逻辑和TCP(HTTP用的是TCP)不一样,路由器对ICMP的发夹路由支持可能没问题,但TCP就卡壳了。
解决方案(按优先级排序)
1. 局域网内用本地DNS映射(最推荐)
在局域网的DNS服务器(或者路由器的本地DNS设置)里,把TheSite.com直接映射到服务器的局域网IP 192.168.1.43。这样局域网内的设备访问域名时,直接走局域网IP,绕开发夹路由问题。
- 如果是Orbi Pro路由器,一般有本地DNS记录或者主机名映射的功能,去管理后台找找添加即可。
- 如果没有路由器级别的设置,也可以在每台局域网设备的hosts文件里加一条:
- Windows:打开
C:\Windows\System32\drivers\etc\hosts,添加192.168.1.43 TheSite.com - Ubuntu:打开
/etc/hosts,添加同样的内容
- Windows:打开
2. 开启路由器的发夹路由功能
有些路由器(尤其是高端型号)有专门的发夹路由、NAT回环或者Hairpin NAT的开关,你可以去Orbi Pro的管理界面找找看,开启这个功能就能直接解决问题。
3. 确认NGINX监听配置(兜底排查)
看你的NGINX配置,server块里listen 80没有指定IP,理论上是监听所有网卡的80端口,但保险起见可以改成明确监听所有接口:
你的原配置片段:
server { server_name TheSite.com; listen 80; ... }
修改为:
server { server_name TheSite.com; listen 0.0.0.0:80; listen [::]:80; ... }
确保NGINX确实在所有网络接口上监听80端口,避免只绑定了局域网IP的情况(不过你局域网IP能访问,这个可能性不大,但可以排查下)。
4. 测试公网真实访问情况
如果上面的办法都不行,可以用手机开热点,用手机流量访问你的公网域名/IP:
- 如果手机能正常打开页面:那肯定是路由器的发夹路由问题,回到前两个方案继续折腾。
- 如果手机也不能访问:那可能是ISP的端口限制(极少数情况),或者你的端口转发/DMZ配置没生效(虽然你开了,但可以再核对一遍)。
总结
先试试本地DNS映射或者开启路由器的发夹路由功能,这两个办法解决90%以上的这类问题。你第一次搭服务器遇到这个很正常,别灰心,一步步来!
备注:内容来源于stack exchange,提问作者NOCARRIER

