把站点挪到 8443 之后踩的几个坑
这台机器上 80 和 443 都被前置的东西占着,站点本身只好退到回环的
127.0.0.1:8443 上,对外由 443 转发过来。搬完之后页面能开,
但日志、缓存和协议版本全都不对,前后改了四轮才顺。
一、listen ... http2 的旧写法
nginx 1.25.1 起把 HTTP/2 从 listen 参数里拆了出来,改成独立的
http2 指令。原本的写法虽然还能跑,但启动时会扔一条
the "listen ... http2" directive is deprecated 的警告,
而且和新的 http2 on; 混用时行为不好猜。
server {
listen 127.0.0.1:8443 ssl;
http2 on; # 1.25.1+ 的正确写法
server_name example.com;
}
顺手把 nginx -t 的输出也看了一眼,警告一并消失。
二、ssl 参数不会自动继承
我以为在 http 块里写了 ssl_protocols,所有 server
就都跟着走。实际上 ssl_protocols 确实可以在 http 块里全局设置,
但一旦某个 server 块里又写了一遍,就只对那个 server 生效——而被其他配置
include 进来的模板经常各自带一份,最后哪个生效全看顺序。
排查办法是把合并后的配置打出来看:
sudo nginx -T | grep -nE "ssl_protocols|ssl_ciphers|listen "
-T 会输出所有 include 展开后的完整配置,比到处翻文件靠谱。
我这边就是发现某个 snippet 里还留着 TLSv1.1。
三、反向代理丢了 Host
前置转发到 8443 时,默认带过去的 Host 是上游的地址,站点拿到的
是 127.0.0.1:8443,于是 server_name 匹配不上,
落到了默认 server,页面内容对但所有绝对链接都错。
location / {
proxy_pass http://127.0.0.1:8443;
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;
}
$host 和 $http_host 的区别在于前者会去掉端口并按
server_name 归一化,静态站点用 $host 就够了。
四、日志里的 IP 全成了 127.0.0.1
这个不算 bug,是架构决定的:请求确实是回环来的。想拿到真实 IP 有两条路,
要么在链路上开 PROXY protocol,要么让前置把 X-Real-IP
传下来再配 real_ip_header:
set_real_ip_from 127.0.0.1;
real_ip_header X-Real-IP;
real_ip_recursive on;
开 PROXY protocol 要两边同时改,改错一边就是整站 502,我最后选了
X-Real-IP,够用。
验证
站点在回环上,浏览器没法直接测,用 --resolve 把域名硬指到
127.0.0.1,再配合 -k 忽略证书告警:
curl -sk --resolve example.com:8443:127.0.0.1 \
-o /dev/null -w "%{http_code} %{time_total}s\n" \
https://example.com:8443/
再补一条握手的检查,确认证书链完整、协议是 TLS 1.3:
openssl s_client -connect 127.0.0.1:8443 \
-servername example.com -brief </dev/null
四个坑里真正会让人误判的是第二个:配置看着都对,就是行为不对,
因为生效的是另一个文件里的那份。nginx -T 应该成为习惯。