W weiserv
← 返回博客

nginx www 跳转非www 301:canonical 冲突与验证文件 301 失败的两个坑

运维实践

背景

站点此前让 www.weiserv.comweiserv.com 同时服务同一内容,存在 SEO 重复内容风险,且与页面 canonical 标签(指向非 www)不一致。需要在 nginx 层做 www 跳转非www 的 301 归一

一、现象:两个域名服务同一内容

  • 浏览器访问 www.weiserv.comweiserv.com 都返回同样的页面;
  • 百度站长平台的规范 URL(canonical)指向非 www,但 www 仍可访问,两者不一致;
  • 若直接改,已通过的百度站点验证可能复检失败。

二、根因:跳转目标用了 $host、验证通道被 301 误伤

改前的两个失误:

# 改前::80 跳转保留 www($host 会保留用户输入的 www)
server { listen 80; server_name weiserv.com www.weiserv.com;
  return 301 https://$host$request_uri; }   # $host 含 www → 永远跳回 www

# 改前::443 单块同时服务两个域名
server { listen 443 ssl; server_name weiserv.com www.weiserv.com;
  location /baidu_verify_ { root /path/to/staticfiles; } ... }
  1. :80https://$host 会原样保留 www,www 跳转非www 根本没生效
  2. 把重定向铺到 server 级后,location /baidu_verify_ 也会被 301 覆盖——百度验证器拒收 301,已通过的验证会在复检时突然失败。

三、解决:目标写死 + nginx 双 443 重定向块都保留验证通道

# /etc/nginx/sites-enabled/weiserv
# 1) :80 —— 目标写死非 www,HTTP→HTTPS 一步到位
server {
    listen 80;
    server_name weiserv.com www.weiserv.com;
    location /baidu_verify_ { root /path/to/staticfiles; }
    location / { return 301 https://weiserv.com$request_uri; }
}
# 2) 新增 :443 www 重定向块
server {
    listen 443 ssl;
    server_name www.weiserv.com;
    include /etc/nginx/ssl_options.conf;
    return 301 https://weiserv.com$request_uri;
}
# 3) 原 :443 块 server_name 收窄为仅 weiserv.com(保留 baidu_verify 与 bdunion.txt 200)
server {
    listen 443 ssl default_server;
    server_name weiserv.com;
    location /baidu_verify_ { root /path/to/staticfiles; }
    # bdunion.txt 等价简化:真实为 alias 直出文件(http 下随全站 301→https),此处 return 200 语义等价
    location = /bdunion.txt { return 200; }
    # ... 原有站点配置
}

改前务必备份,再校验重载:

sudo cp /etc/nginx/sites-enabled/weiserv /var/backups/weiserv.vhost.bak.$(date +%Y%m%d%H%M)
sudo nginx -t && sudo nginx -s reload

四、验证:curl 实测 301 与 200

# www 全部 301 到非 www(nginx www 301 归一生效)
$ curl -sI https://www.weiserv.com/ | grep -iE '^HTTP|^location'
HTTP/1.1 301 Moved Permanently
Location: https://weiserv.com/

# 规范域名仍 200,canonical 一致
$ curl -s -o /dev/null -w '%{http_code}' https://weiserv.com/
200

# baidu_verify_ 文件在 http/https × www/非www 四组合仍 200(真实文件名带 codeva- 前缀,
# 如 baidu_verify_codeva-XXXX.html;未被 301 误伤)
# 注:bdunion.txt 在 https 下 200,http 下随全站 301→https(设计使然),勿与 baidu_verify_ 的四组合 200 混淆
$ curl -s -o /dev/null -w '%{http_code}' https://www.weiserv.com/baidu_verify_codeva-XXXX.html
200

五、避坑清单

  1. :80 的跳转目标必须写死域名,别用 $host——$host 会原样保留用户输入的 www,归一形同虚设。
  2. 百度验证器拒收 301:任何重定向改动都要保留 location /baidu_verify_(以及 bdunion.txt)直出 200,否则已通过验证会复检失败。
  3. :443 块都要保留验证通道:nginx 双 443 重定向(www 块 + 非 www 块),只要服务了含验证文件的域名,就得放行。
  4. 改前先备份 + nginx -t 校验:配置错了会全站 502,备份能秒回滚。
广告位占位 · post-inline