跳到主内容
芝麻园地
EN
← 返回博客
#domain-migration#nginx#seo#301#astro

网站换域名,不只是配一条 301:Nginx、SEO 与统计迁移完整实战

从 zhimayuandi-old.com 迁移到 zhimayuandi.com 的真实复盘:如何设计单跳 301、保留路径与查询参数,处理 Astro sitemap、canonical、百度统计、搜索引擎改版申报,并用一套验证矩阵确认迁移真的完成。

编程快车 22 分钟

最近,我把网站从 zhimayuandi-old.com 整体迁到了 zhimayuandi.com。

一开始以为这件事很简单:旧服务器写一条 301,新服务器把网站跑起来,结束。

真正做完才发现,301 只是迁移链路里最显眼的一环。一个看似正常的新站,可能同时存在这些问题:

  • 首页能跳转,深层文章却丢了路径;
  • HTTP 跳 HTTPS,再跳 www,最后才到主域,形成多级跳转;
  • 页面已经换域,canonical 和 sitemap 仍指向旧站;
  • 新站页面正常,API、反馈和后台路由却被新 Nginx 模板覆盖;
  • 百度统计里还能看到流量,但数据一直记在“旧站”名下;
  • 自定义 404 页面看起来没问题,HTTP 状态码却是 200。

这篇不是一份“复制一段配置就结束”的教程,而是一次完整迁移后的复盘:怎样把域名、服务器、SEO、统计和验证连成一个闭环。

先定义成功:迁移不是“新域能打开”

我给这次迁移定了六个验收条件:

  1. 旧域的 HTTP、HTTPS、www、非 www 都能到达新域;
  2. 每个旧 URL 都跳到内容对应的新 URL,路径和查询参数不丢;
  3. 整条链只有一次永久重定向;
  4. 新站的 canonical、hreflang、内链、Feed 和 sitemap 全部指向新域;
  5. 静态站、API、反馈后台、证书和压缩都正常;
  6. 搜索引擎和统计平台知道网站已经换了地址。

如果只满足“首页能打开”,最多只能叫“新域上线”,还不能叫“迁移完成”。

第一步:不要先写正则,先做 URL 清单

域名迁移最重要的资产不是 Nginx 文件,而是新旧 URL 的对应关系。

路径完全不变时,事情最简单:

https://old.example.com/blog/article/
→ https://new.example.com/blog/article/

如果路径变了,就必须明确映射:

https://old.example.com/post/123
→ https://new.example.com/blog/article-name/

我会从旧 sitemap、访问日志、搜索平台、外链和站内链接中收集 URL,再整理成表格:

旧 URL 新 URL 处理方式 最终状态
/blog/example/ /blog/example/ 域名级 301 200
/post/123 /blog/example/ 单独映射 200
/deleted-page/ 无替代内容 404/410 404/410

没有对应内容的页面,不要为了“看起来没有死链”而全部跳首页。搜索引擎可能把这种不相关跳转当成 soft 404,用户点进来同样会困惑。

第二步:旧站只做一件事——单跳到最终地址

同路径换域名时,Nginx 的 return 301 足够清晰:

server {
    listen 80;
    server_name old.example.com www.old.example.com;
    return 301 https://new.example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name old.example.com www.old.example.com;

    ssl_certificate     /etc/letsencrypt/live/old.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/old.example.com/privkey.pem;

    return 301 https://new.example.com$request_uri;
}

这里有三个细节:

第一,HTTP 直接到新站 HTTPS。 不要先跳旧站 HTTPS,再跳新域。

第二,必须保留 $request_uri。 它会带上路径和查询参数:

/tools/example/?from=old
→ https://new.example.com/tools/example/?from=old

第三,旧域证书不能停。 用户和爬虫访问 https://old.example.com 时,必须先完成 TLS 握手,浏览器才看得到后面的 301。证书过期,跳转写得再漂亮也没用。

如果只有部分路径变化,再为那些路径添加精确规则。简单同路径迁移优先 return,需要捕获和改写路径时再使用 rewrite 或 map,不要反过来。

第三步:新站配置必须从“真实服务拓扑”出发

我差点踩的最大坑,是把一个通用 PHP 示例当成新站模板。

实际项目是 Astro 静态站,部署目录是 /var/www/site,同时还有 API 和反馈服务。如果误用了 index.php、PHP-FPM 或 /index.php?$args,首页也许还能被某些默认配置兜住,但静态路由和接口会直接出问题。

简化后的主站结构应该像这样:

server {
    listen 443 ssl;
    server_name new.example.com;

    root /var/www/site;
    index index.html;

    location /api/ {
        proxy_pass http://127.0.0.1:8602;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        try_files $uri $uri/ =404;
    }

    error_page 404 /404.html;
}

但这仍然只是骨架。真实站点可能还有:

  • 更具体的 /api/feedback、/api/bugs 路由;
  • 上游服务返回跳转时所需的 proxy_redirect;
  • 修复上游 HTML 根相对链接的 sub_filter;
  • gzip/Brotli 预压缩;
  • 静态资源缓存、安全响应头和附件目录。

所以我的原则是:

迁移时以服务器当前生效配置为事实源,而不是以网上模板为事实源。

先用 nginx -T 看清完整配置,再整理;不要凭记忆重新生成一个“差不多”的版本。

第四步:SEO 信号必须一起换域

canonical

新站每个可索引页面都应该自指向新域:

<link rel="canonical" href="https://new.example.com/current-page/" />

如果页面已经在新域,canonical 仍指向旧域,相当于主动告诉搜索引擎:“旧页面才是正版。”

hreflang

多语言站还要同步修改语言版本关系:

<link rel="alternate" hreflang="zh-CN" href="https://new.example.com/page/" />
<link rel="alternate" hreflang="en" href="https://new.example.com/en/page/" />
<link rel="alternate" hreflang="x-default" href="https://new.example.com/page/" />

每个语言页面都应返回指向其他语言版本的链接,不能只做单向声明。

robots.txt

新站 robots 中的 sitemap 地址也要换:

User-agent: *
Allow: /

Sitemap: https://new.example.com/sitemap-index.xml

robots 规则按协议、主机和端口生效。旧域的 /robots.txt 可以和其他旧 URL 一样 301,但不能理解成“新站 robots 自动接管所有旧域规则”。

sitemap

Astro 的 @astrojs/sitemap 默认生成的是:

sitemap-index.xml
sitemap-0.xml

不是想当然的 /sitemap.xml。这类错误非常隐蔽:文档、robots 和站长平台都填了 /sitemap.xml,实际线上却一直 404。

sitemap 中只放:返回 200、允许索引、canonical 一致的新域 HTTPS URL。Google 会忽略 priority 和 changefreq;lastmod 只有真实准确时才有价值。

第五步:告诉搜索引擎“这是搬家,不是复制站”

Google Search Console

我的处理顺序是:

  1. 验证新旧域所有权,优先用 Domain property/DNS;
  2. 确认旧 URL 已经 301、新 URL 可抓取;
  3. 在旧属性中提交“更改地址”;
  4. 对实际使用或被收录的 www、非 www 和其他子域变体分别检查;
  5. 在新属性提交新 sitemap;
  6. 观察网页索引、抓取统计、HTTPS 和搜索效果。

Google 的地址变更通知持续 180 天,但官方迁站指南建议重定向通常至少保留一年。从用户和外链角度看,只要成本可控,长期保留更稳妥。

百度搜索资源平台

百度侧同样要先做好一一对应的 301,再通过“网站改版”提交域名或 URL 关系,并提交新站 sitemap。平台入口和工具名称可能调整,执行时以当期控制台为准。

Bing 与 IndexNow

Bing Webmaster Tools 中应验证新站并提交 sitemap。IndexNow 可以帮助推送新增和更新 URL,但它不能替代旧域到新域的整站 301。

第六步:百度统计“还有数据”,不等于迁移完成

这次还有一个很有迷惑性的现象:域名已经换了,百度统计的旧站报表仍不断出现新访问。

原因不是 301 在统计流量。服务器返回 301 时不会执行页面里的统计 JavaScript。真正原因是:新站继续加载了旧站的同一个百度统计 Site ID。

于是有两种选择。

新域新建统计站点

这是我更推荐的做法:

  1. 保留旧站统计项目,不删除历史数据;
  2. 为新域新增统计站点,获取新的 Site ID;
  3. 替换网站中的 Site ID,重新构建部署;
  4. 运行代码安装检查,确认新域开始入数;
  5. 用迁移日期作为新旧报表的分界线。

优点是归属清楚,代价是趋势图分成两段。

继续沿用旧 Site ID

如果更重视一张报表里的连续趋势,可以保留原 ID,同时更新站点资料、检查域名过滤并记录迁移日期。这样不用改代码,但站点身份可能长期带着旧域痕迹。

不要长期同时安装两个 Site ID,除非明确需要短期并行校验,也清楚两套报表都会记录同一次访问。

第七步:用“验证矩阵”代替“我点开看了”

迁移完成后,我不再只测首页,而是至少覆盖这些类型:

# 旧域四种入口
curl -sSI http://old.example.com/
curl -sSI https://old.example.com/
curl -sSI http://www.old.example.com/
curl -sSI https://www.old.example.com/

# 真实深层页面和查询参数
curl -sSIL 'https://old.example.com/blog/real-article/?from=test'

# 新站基础设施
curl -sSI https://new.example.com/
curl -sSI https://www.new.example.com/
curl -sSI https://new.example.com/robots.txt
curl -sSI https://new.example.com/sitemap-index.xml
curl -sS  https://new.example.com/api/health

# 不存在的页面必须返回 404
curl -sSI https://new.example.com/this-page-does-not-exist

验收标准:

  • 旧域真实页面一次 301 后最终 200;
  • 路径和查询参数不变;
  • 新域 HTTP/www 一次跳到 HTTPS 非 www;
  • robots、sitemap、API 正常;
  • 不存在的页面最终为 404;
  • 没有 302、循环、证书错误或额外中转。

还要补一句:不要拿不存在的示例 URL 验证“最终必须 200”。 我最初用 /post/123 测试,最终当然是 404,因为新站根本没有这个页面。验证 URL 本身也必须真实。

对于写接口和后台,HEAD/GET 成功仍然不够。反馈是否落盘、编辑后 303 跳转是否正确、附件能否读取,都要走一遍真实业务流程。

迁移完成后,还要观察什么

我把监控分成四段:

时间 重点
0–48 小时 301、404/5xx、证书、API、CDN 缓存、服务器负载
第 1–4 周 抓取统计、索引量、搜索流量、关键词和外链访问
第 2–3 月 旧 URL 是否退出索引,新 URL 是否稳定增长
第 6、12 月 旧域剩余流量、外链、证书续期和保留策略

最值得报警的不是“排名今天掉了两个位置”,而是这些明确的工程异常:

  • 旧域出现非 301;
  • 301 目标返回 404/5xx;
  • 重定向链超过一次;
  • sitemap 混入旧域、noindex 或 404 URL;
  • API 错误率上升;
  • 旧域证书续期失败。

最后复盘:域名迁移其实是一次“信号一致性工程”

回头看,域名迁移并不难,难的是让每一层都表达同一件事:

  • Nginx 说:内容永久搬到了新域;
  • 页面 canonical 说:新域是规范版本;
  • hreflang 说:各语言版本都在新域;
  • sitemap 只提交新域 URL;
  • 搜索平台收到明确的地址变更;
  • 统计平台按新的站点身份记录数据;
  • 旧域证书和 301 继续稳定工作。

其中任何一层说反话,迁移都会变慢,甚至让人误以为“301 没效果”。

所以我现在对迁移的定义是:

不是把网站复制到另一台服务器,而是让用户、浏览器、搜索引擎、统计平台和所有外部链接,对网站的新地址达成一致。

当这五方都指向同一个最终 URL,域名迁移才算真正完成。

参考资料