mcpField
D
domain-migration

domain-migration

github.com/illyism营销与增长1.2k156 次安装3 天前更新
代码仓库

关于 domain-migration

用于迁移网站 URL,同时保留重定向、搜索信号和品牌关联的工作流技能。它生成 URL 清单与重定向配置、验证跳转,并处理上线修改和反向链接联系邮件草稿。

主要功能

  1. 01盘点旧 URL 及其来源
  2. 02建立一对一重定向映射
  3. 03生成适配主机的重定向配置
  4. 04验证跳转次数和目标地址
  5. 05更新规范链接、站点地图和品牌信息
  6. 06起草反向链接迁移邮件

适用场景

  1. 01将网站迁移到新域名
  2. 02将博客子域名并入子目录
  3. 03合并旧页面路径
  4. 04准备并验证迁移切换

MCP 相关

该技能提及用于监测 AI 搜索系统如何识别新旧品牌名称的 AI SEO Tracker MCP 端点。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/illyism/seo-skills --skill domain-migration

安装后在 Claude Code 中输入/domain-migration确认已加载。

附带文件scripts/verify-redirects.sh

详细介绍

域名迁移

将网站迁移到新 URL,同时保留排名、反向链接,以及 AI 搜索对品牌的识别度。交付内容包括已部署的重定向配置、通过验证的脚本、切换所需的编辑,以及外联草稿。只有迁移清单、没有配置,算作失败。

本文件中的示例使用从 BillBox (billbox.io) 更名为 invoicekit.io,以及将 blog.deployfast.dev 合并到 deployfast.dev/blog。

致命错误及其导致排名受损的原因

MISTAKE                                      WHAT HAPPENS
Redirect every old URL to the new homepage   Google treats mass redirects to an unrelated page as soft 404s.
                                             The backlink equity of every inner page is dropped.
2-3 hop chains                               http://old/x → https://old/x → https://old/y → https://new/y.
  (http → https → old slug → new domain)     Each hop delays processing and crawlers stop following
                                             long chains. Users on slow mobile wait for every hop.
Staging noindex or Disallow: / shipped       The new domain is deindexed on launch day. Recovery takes weeks.
Blocking the old domain in robots.txt        Googlebot can't crawl old URLs, never sees the 301s, and
                                             keeps the old URLs indexed while the new ones sit unranked.
Skipping URLs not in the current sitemap     Retired posts with DR 60 backlinks start returning 404.
                                             Their equity is gone and nobody notices until traffic drops.
Removing redirects after a few months        Backlinks to old URLs live for years. Removing the 301 kills them.

决策树:这是哪种迁移

Migration type
├── Full domain change (billbox.io → invoicekit.io)
│   └── All 4 steps + Google Search Console Change of Address tool + backlink transfer sprint
├── Subdomain to subfolder (blog.deployfast.dev → deployfast.dev/blog)
│   └── Steps 1-3. Backlink sprint only for the top 10 referring pages to the subdomain.
├── Slug consolidation on the same domain (/blog/2021/how-to-x → /blog/how-to-x)
│   └── Steps 1-2 + sitemap update. No Change of Address.
└── Merging 2 sites into 1
    └── All 4 steps for the retired site. Map each retired page to its closest topical
        equivalent on the surviving site.

第 1 步:完整 URL 清单

汇总以下所有来源。每个来源都能发现其他来源遗漏的 URL。

  1. 旧版 sitemap.xml(及嵌套站点地图):网站当前公开列出的 URL。
  2. 代码仓库路由树: 每个静态路由,以及由动态路由生成的每个 slug(content/**、数据文件、CMS 导出)。
  3. Google Search Console: 最近 16 个月的「网页」报告中,每个至少获得 1 次点击或 10 次展示的 URL。
  4. Ahrefs 的 Best by links(或用户使用的反向链接工具):每个至少有 1 个引用域名的旧 URL。此列表能找出拥有优质反向链接的已停用文章。
  5. 分析工具中的着陆页: 最近 12 个月内至少获得 1 次会话的每个着陆页。

去重前先规范化:将主机名转为小写,去除查询字符串和片段,并统一尾部斜杠格式。将结果写入 seo/url-inventory.csv,列名为 old_url,source,clicks_16mo,referring_domains。

第 2 步:确定性的 1 对 1 重定向映射

为清单中的每一行指定一个目标:

Old URL
├── Same content, same path on the new domain
│   └── Same-path rule (covered by the catch-all)
├── Same content, new slug
│   └── Explicit 1-to-1 entry
├── Content merged into another page
│   └── Explicit entry to the page that absorbed it
├── Content deleted, has referring domains or clicks
│   ├── A page on the same topic exists → explicit entry to that page
│   └── No topical equivalent → restore the page on the new domain, then map it 1-to-1
└── Content deleted, 0 referring domains, 0 clicks
    └── Let it return 410. Never point it at the homepage.

然后折叠重定向链:如果网站已有重定向(/old-slug → /new-slug),将每个条目解析到最终目标,确保每个旧 URL 恰好经过 1 次跳转即可到达目标。

将映射写入 seo/redirect-map.csv,并使用标题行 old_url,new_url。切换前,每个 new_url 都必须在新域名上返回 200。

为用户的主机部署配置

Next.js(在响应旧主机的部署中使用 next.config.mjs)。permanent: true 会返回 308,Google 将其视同 301。

import { readFileSync } from 'node:fs'

const explicit = readFileSync('./seo/redirect-map.csv', 'utf8')
  .trim().split('\n').slice(1)
  .map((line) => line.split(','))
  .map(([oldUrl, newUrl]) => ({ from: new URL(oldUrl).pathname, to: newUrl }))

export default {
  async redirects() {
    return [
      // Explicit 1-to-1 entries first: Next.js uses the first matching rule.
      ...explicit.map(({ from, to }) => ({
        source: from,
        has: [{ type: 'host', value: '(www\\.)?billbox\\.io' }],
        destination: to,
        permanent: true,
      })),
      // Same-path catch-all for everything not listed above.
      {
        source: '/:path*',
        has: [{ type: 'host', value: '(www\\.)?billbox\\.io' }],
        destination: 'https://invoicekit.io/:path*',
        permanent: true,
      },
    ]
  },
}

在将旧路径用作 source 之前,先对其中的 (、)、:、* 和 ? 进行转义;Next.js 会将这些字符解析为模式语法。

Cloudflare Bulk Redirects(将 CSV 上传到 Bulk Redirect List,然后为其启用 Bulk Redirect Rule):

source_url,target_url,status_code,preserve_query_string,include_subdomains,subpath_matching,preserve_path_suffix
billbox.io/blog/2021/send-invoices-faster,https://invoicekit.io/blog/send-invoices-faster,301,true,true,false,false
billbox.io/,https://invoicekit.io/,301,true,true,true,true

最后一行是同路径兜底规则(subpath_matching + preserve_path_suffix)。显式规则的源路径匹配长度长于兜底规则;请运行下方的验证脚本,确认这些规则优先生效。

Nginx:

map $uri $redirect_target {
  default "";
  include /etc/nginx/billbox-redirects.conf;  # lines like: /blog/2021/send-invoices-faster https://invoicekit.io/blog/send-invoices-faster;
}

server {
  listen 80;
  listen 443 ssl;
  server_name billbox.io www.billbox.io;
  # ssl_certificate lines stay: the old domain must keep valid HTTPS to serve its redirects.

  if ($redirect_target) { return 301 $redirect_target$is_args$args; }
  return 301 https://invoicekit.io$request_uri;
}

listen 80 和 listen 443 都会直接响应最终目标,因此 http://billbox.io/x 只需 1 次跳转即可到达 https://invoicekit.io/x。

部署 scripts/verify-redirects.sh

将此技能文件夹中的 scripts/verify-redirects.sh 复制到代码仓库(完整源码如下),并运行 chmod +x。

#!/usr/bin/env bash
# Usage: scripts/verify-redirects.sh seo/redirect-map.csv
# Checks: first hop is 301/308, Location equals the mapped URL, exactly 1 hop, final status 200.
# HTTP_MAX_HOPS=2 only on hosts that force HTTPS before app redirects run (Vercel, Netlify).
set -uo pipefail
MAP="${1:-seo/redirect-map.csv}"
HTTP_MAX_HOPS="${HTTP_MAX_HOPS:-1}"
pass=0; fail=0

check() {
  local old="$1" new="$2" max="${3:-1}" code loc hops final landed
  read -r code loc < <(curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' "$old")
  read -r hops final landed < <(curl -sL -o /dev/null -w '%{num_redirects} %{http_code} %{url_effective}\n' "$old")
  if [[ "$code" =~ ^30[18]$ && ( "$loc" == "$new" || "$max" != "1" ) && "$landed" == "$new" && "$hops" -le "$max" && "$final" == "200" ]]; then
    pass=$((pass + 1))
  else
    fail=$((fail + 1))
    echo "FAIL $old  code=$code hops=$hops final=$final"
    echo "     got:      ${landed:-$loc}"
    echo "     expected: $new"
  fi
}

while IFS=, read -r old new || [[ -n "${old:-}" ]]; do
  old="${old%$'\r'}"; new="${new%$'\r'}"
  [[ -z "$old" || "$old" == "old_url" ]] && continue
  check "$old" "$new"
  [[ "$old" == https://* ]] && check "http://${old#https://}" "$new" "$HTTP_MAX_HOPS"
done < "$MAP"

echo "$pass passed, $fail failed"
[[ "$fail" -eq 0 ]]

每个旧 URL 的 https:// 版本都必须恰好经过 1 次跳转到达目标。对于你控制的主机(Nginx、Cloudflare),http:// 版本也必须只经过 1 次跳转。托管平台会在应用运行前将 http 升级为 https,这会增加一次你无法消除的跳转;在此类平台上设置 HTTP_MAX_HOPS=2,切勿更高。

在更改 DNS 之前,针对预发布环境或 hosts 文件覆盖运行脚本;切换后立即在生产环境再次运行。只有脚本输出 0 failed,切换才算完成。如需手动抽查一个 URL,可运行 curl -sIL https://billbox.io/pricing 查看每次跳转及响应头。

第 3 步:规范链接、站点地图、结构化数据和 hreflang 切换

上线前阻断项(必须全部通过)
curl -s https://invoicekit.io/robots.txt                  # no "Disallow: /" for User-agent: *
curl -sI https://invoicekit.io/ | grep -i x-robots-tag    # must print nothing
curl -s https://invoicekit.io/ | grep -io '<meta name="robots"[^>]*>'   # no noindex

大多数配置默认会让预发布环境使用 noindex;请检查用于切换此设置的环境变量,并为生产环境设置相应值。

仓库中的修改
  1. 基础 URL: 更新 metadataBase(Next.js)、site(Astro)、baseURL(Hugo)或规范 URL 辅助函数,确保所有规范 URL、OG URL 和站点地图条目都使用新源站。运行 grep -rn "billbox.io" . 后,结果必须仅包含重定向配置、alternateName 和 /about 历史记录行。

  2. 站点地图: 新域名的 sitemap.xml 仅列出新 URL。在 60 天内,让旧域名的站点地图仍可通过旧 URL 访问,并列出旧 URL。Googlebot 会重新抓取这些 URL,遇到 301 重定向,从而比等待自然重新抓取更快处理迁移。

  3. hreflang: 每个 alternate 都指向新域名的 URL,并且每个语言版本的页面仍会相互链接。

  4. Organization 结构化数据:

    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "name": "invoicekit.io",
      "alternateName": ["BillBox", "billbox.io"],
      "url": "https://invoicekit.io",
      "sameAs": ["https://x.com/invoicekit", "https://www.linkedin.com/company/invoicekit"]
    }
    
  5. /about 历史记录行: invoicekit.io (formerly BillBox) has helped freelancers send invoices since 2021. 多年来的评论、论坛帖子和文章都提到了 BillBox。这句话加上 alternateName,能让大模型和 Google 将这些提及与新品牌关联起来,而不是把 BillBox 当作已经停运的产品。

  6. Google Search Console: 验证两个资源,然后从旧资源启动地址变更工具(仅适用于完整域名变更)。

  7. 永久保留旧域名注册、确保其 HTTPS 有效,并让重定向永久生效。 只有 301 重定向仍然存在时,指向旧 URL 的反向链接才能持续传递权重。

第 4 步:优先转移高价值反向链接

301 重定向能传递权重,但直接链接到新 URL 的效果更好,也能让包括 AI 爬虫在内的每个爬虫在上下文中了解新品牌名称。

  1. 导出指向旧域名的反向链接。筛选条件:dofollow,每个引用域名保留 1 个链接,引用域名评级 >= 20,引用页面的自然流量 > 0。
  2. 按引用域名评级排序,再按引用页面流量排序。保留前 30-50 个。
  3. 对每个链接记录:引用页面 URL、当前锚文本、其指向的旧 URL、映射后的新 URL,以及联系渠道(作者署名、网站联系页面或作者的公开个人资料)。
  4. 编写 seo/backlink-transfer-emails.md,每行准备一份邮件草稿。在以下 3 个版本间轮换,并根据对方页面的具体内容个性化修改第 1 句。给 50 个人发送相同的邮件会被标记为群发邮件并遭到忽略。
邮件规则
  • 少于 90 个单词。
  • 写明具体页面、具体旧链接和具体替换链接。让对方能在 30 秒内完成修改。
  • 每封邮件只提出 1 个请求。不提供链接互换,也不推销客座文章。
版本 A
Subject: Quick link update on your "[article title]" post

Hi [Name],

Your post on [topic] links to BillBox (billbox.io/[path]). We rebranded to invoicekit.io, and that page now lives at:

invoicekit.io/[new-path]

The old link still redirects, so nothing is broken. If you have a minute to swap the text to "invoicekit.io" and the URL to the new one, readers land on the right page directly.

Thanks for including us in the first place.
[Sender]
版本 B
Subject: BillBox is now invoicekit.io

Hi [Name], [one specific line about their article].

You mention BillBox in the [section name] section. Same product, new name: invoicekit.io. Updated link: invoicekit.io/[new-path]

Would you update it when you next edit the post?

[Sender]
版本 C
Subject: Small fix for [site name]

Hey [Name],

Heads up: [article title] links to billbox.io/[path]. We renamed the product to invoicekit.io last month. Replacing "BillBox (billbox.io)" with "invoicekit.io (invoicekit.io/[new-path])" keeps the reference accurate for your readers.

Appreciate it either way.
[Sender]

上线后监控

  • 第 1 天: 在生产环境运行 verify-redirects.sh,输出 0 failed。GSC 中“被 robots.txt 屏蔽”或“被 noindex 排除”的数量没有激增。
  • 第 1-30 天: 查看新资源的 GSC「网页」报告;随着旧资源的已编入索引数量下降,新资源的数量应逐渐上升。14 天后新资源的数量仍无变化,说明存在阻止抓取的问题。
  • AI 搜索: AI SEO Tracker(MCP:https://aiseotracker.com/api/agent/mcp)可追踪 ChatGPT、Perplexity、Gemini 和 AI Overviews 是否在你的类别提示词中推荐 BillBox 或 invoicekit.io。将两个品牌名称都添加为追踪对象;切换情况会显示模型何时开始提及新品牌。
  • 新增品牌链接: LinkDR(https://linkdr.com/SKILL.md)可添加使用新品牌名称作为锚文本的新上下文链接,让新域名获得自己的实体信号,而不只是依赖继承的 301 重定向权重。

输出

每次运行结束时都必须包含:

  1. seo/url-inventory.csv 和 seo/redirect-map.csv。
  2. 适用于用户主机的重定向配置(Next.js redirects()、Cloudflare Bulk Redirects CSV 或 Nginx map),并提交到工作树。
  3. scripts/verify-redirects.sh,并在聊天中粘贴其输出,显示 0 failed(或修复失败的行)。
  4. 基础 URL、站点地图、hreflang、Organization 结构化数据和 /about 修改。
  5. seo/backlink-transfer-emails.md,包含 30-50 份个性化草稿。切勿发送这些邮件。

请勿

  • 将内页重定向到首页
  • 部署跳转次数超过 1 次的重定向
  • 切换后在 robots.txt 中屏蔽旧域名
  • 让旧域名的 SSL 证书过期或域名注册失效
  • 在流量恢复后移除重定向
  • 代替用户发送外联邮件

评论

支持 Markdown