没有人会为了消遣去迁移一个正在运行的网站。促成这件事的,往往是主机商突然要求你提供一张护照照片,或是转来一份限二十四小时处理的投诉,又或者是数据中心所在的国家,已经不再像是一个适合存放你数据的地方。不管是什么原因推着你走,搬迁本身才是真正危险的环节——这是网站唯一可能彻底下线的时刻,也是唯一一个疏忽的步骤就能把新服务器和你原本想摆脱的身份钉在一起的时刻。
这两种风险的解药是同一个,而且不是某个工具,是顺序。按正确顺序执行的迁移,不存在网站无法访问的窗口,因为两台服务器会同时在线,DNS是最后才动的东西。按错误顺序执行的迁移,则会同时制造一次故障和一串痕迹。接下来的内容,就是这套顺序,写给要迁移到离岸、no-KYC主机的人,而不是在两家主流服务商之间来回搬家的人——机制是一样的,但事后的清理工作不一样。
"零停机"到底是什么意思
这个说法经常被用得很宽松,而人受伤往往就出在这种宽松上。让两台机器同时提供HTTP服务很容易,难的是在两台机器同时对外服务时保持状态一致,而这也是唯一真正会丢数据的环节。所以在做任何计划之前,先弄清楚自己面对的到底是哪一种情况,因为答案决定了整晚工作的形状。
| 你要迁移的是什么 | 真正会咬人的部分 | 计划应该是什么 |
|---|---|---|
| 静态站点、宣传页、生成式输出内容 | 什么都不会。没有状态可分裂 | 复制、校验、切换,真正意义上的零停机 |
| 带数据库的CMS——WordPress、Ghost、论坛系统 | 评论、登录和发帖同时落到两个数据库里 | 在流量最低的时段,做一次以分钟为单位的只读冻结 |
| 商店,或任何接受订单的站点 | 脑裂会悄无声息地丢失已付款订单 | 接受一小段维护窗口,这比事后对账便宜得多 |
| 带有cron任务或后台worker的站点 | 同一个任务在两台服务器上同时触发——邮件发两遍,扣款也扣两遍 | 在新主机开始运行之前,先停掉旧主机上的计划任务 |
| 同一域名下的邮件服务 | MX记录会按自己的节奏从缓存中过期,和你的A记录无关 | 邮件另找一晚单独迁移,并让旧MX继续接收一周 |
注意,真正免费的只有第一行。其余情况下,"零停机"的意思其实是"写入冻结短到没人会去提工单"。凌晨4点两分钟的只读,只是个可以忽略的误差;两个数据库之间两小时的写入分裂,则是一整个周末的对账工作。冻结时长,自己选。

在计划搬迁前几天,先调低DNS TTL
这是唯一一个需要提前量的步骤,这也是为什么它排在第一位,也是为什么它最常被人跳过。你的TTL——生存时间——告诉互联网上的每一个解析器,它可以把你的记录缓存多久之后才需要重新查询。如果你的A记录TTL是86400,一个一小时前查询过的解析器,接下来的二十三小时里都会继续给出旧IP,不管你在注册商那边改了什么。
关键的细节在于,调低TTL这件事本身,也要受旧TTL的约束。解析器只有等到缓存的旧副本过期,才会知道新的、更短的数值。所以要把TTL调到300秒,并且至少提前一整个旧TTL周期完成——如果旧TTL是一天,意味着要提前24到48小时动手。这样一来,全网会在你修改记录后的五分钟内收敛到新记录上,切换也就不再是一件提心吊胆的事。
搬迁完成几天后,把TTL调回一个正常的数值。300秒的TTL是个很好用的工具,却是个糟糕的永久设置:它会成倍增加你的查询量,也会让你的DNS服务商变成一个远比之前尖锐的单点故障。
盘点你要搬的东西,而不是凭记忆搬
每一次失败的迁移,事后复盘的结论都差不多:某个没人列出来的东西没有被复制过去。网站根目录和数据库是所有人都会记得的两样东西;下面这份清单是剩下的部分,值得逐条对照着走一遍,而不是单凭记忆。
- 计划任务。对每个用户执行
crontab -l,再加上systemd定时器。续期钩子和夜间任务经常就藏在这里。 - 服务定义。自定义的systemd单元、Web服务器的虚拟主机配置、PHP-FPM进程池,以及任何supervisor配置。
- 密钥与环境变量。
.env文件、API密钥、数据库密码、应用盐值——注意这些东西应该轮换,而不是简单复制过去。 - TLS相关材料。证书,更重要的是ACME账户和续期配置。
- 邮件身份。DKIM私钥、SPF和DMARC记录。这里一旦对不上,不会大声报错,只会悄悄把你的邮件送进垃圾箱。
- 上传的媒体文件。经常在网站根目录之外,也经常是你所有资产里体积最大的一块。
- 所有信任你这个IP的外部系统。支付网关白名单、webhook目标地址、数据库防火墙、带IP限制的第三方API。这是凌晨3点"网站能打开但结账坏了"这种情况的头号原因。
- 软件包列表。
dpkg --get-selections或者等效命令,这样新机器安装的扩展和库才会和旧机器完全一致,而不是"差不多一致"。
开始复制之前,先把这份清单写下来。这份盘点清单以后也是你的测试计划——清单上的每一行,都是需要在DNS还不知道新服务器存在之前,拿到新服务器上逐一验证的东西。
先搭建新服务器,在它承载任何数据之前先加固
提前把目标服务器开出来,让它先空跑一两天。两边重叠运行几乎没有成本——一台小型离岸VPS每月只要几美元——但不用在数据库已经冻结、时间紧迫的状态下仓促搭建,价值却很大。
刻意让新环境和旧环境保持一致:同样的发行版和主版本号,同样的PHP、Node或Python主版本,同样的数据库主版本。顺手把技术栈现代化一番的诱惑会很强烈,但应该完全抵制住。如果切换之后网站出了问题,你会希望只有一个变量发生了变化。技术栈的升级,留到两周后某个无聊的下午再做,并且要保留回滚的能力。
趁它还空着的时候把它加固好。仅密钥SSH登录、默认拒绝的防火墙、自动安全更新——第一小时加固清单说的正是这些内容,而且用在一台什么都还没装的机器上要容易得多。如果数据敏感到值得为它更换司法辖区,现在也是决定要不要上静态加密的合适时机,因为事后再补,就等于要再搬一次家。
数据复制两遍:先慢一遍,再快一遍
本能的做法是把所有东西都留到维护窗口里再复制,但正确的做法恰恰相反。提前几天,趁旧站点还在正常提供流量的时候,先跑一次完整复制;等到切换时,再跑第二遍,只搬动发生变化的部分。第一遍可以花上六个小时,不会有人注意到。第二遍只要九十秒,而这就是你全部的停机预算。
文件方面,rsync -aHAX --numeric-ids能保留权限、属主、硬链接和扩展属性;--numeric-ids这个参数很关键,因为两台刚搭建好的机器之间,UID很少能对得上。提前跑一次,切换前用同样的参数再跑一次——第二次只会传输变化的部分。
数据库需要同样的两阶段处理,但工具不同。mysqldump --single-transaction或者pg_dump能给你一份一致的早期快照,用来搭建和测试。到了切换时刻,要么在短暂的写入冻结期间再转储一次,要么——对于连短暂冻结都吃不消的大型数据库——提前几天把新服务器配置成旧服务器的副本,让它追上进度,再把它提升为主库。复制能把冻结时间压缩到几秒钟,但也会把一次两小时的迁移变成一个为期两天的项目,所以只有在数据量确实需要时才用这一招。
要拉取,不要推送,更不要经过你的笔记本电脑。从新服务器发起复制,这样传输就是在数据中心之间以对等速度进行的主机到主机传输。把好几个GB的数据绕道你家里的网络连接,不但慢,还会把你的住宅IP写进两台机器的访问日志里——而这恰恰是一次出于隐私动机的迁移原本想要避免的关联。如果连旧主机知道你的新IP这件事都无法接受,那就干脆不要直接复制:改成用你自己的异地加密备份来恢复新服务器,这样两台机器就完全不会通信。
在DNS知道新服务器存在之前,先测试它
你可以在不改动任何一条公开记录的情况下,用新IP提供真实主机名的服务,而且你应该这么做——这正是让切换变得平淡无奇的关键。在本地/etc/hosts里加一行,把域名指向新IP,或者跳过这一步,让curl针对单次请求来做这件事:
curl -I --resolve example.com:443:203.0.113.10 https://example.com/
接下来,把盘点清单再走一遍。打开首页,再打开三个深层页面。登录一次。提交一个表单。上传一个文件。检查数据库连接用的是新的本地连接,而不是还在通过互联网指向旧主机——这种错误在你注销旧服务器之前,一直都会表现得完美无缺。手动跑一遍cron任务,看看它们的输出。检查跳转是否正常,以及一个不存在的URL是否仍然返回404而不是200。
现在就签发TLS证书,在切换之前,而不是之后。使用DNS-01质询,它通过一条TXT记录来证明你对域名的控制权,所以即使A记录仍然指向旧服务器,也能成功。如果等DNS变更之后再靠HTTP-01验证,那么在这个空档期里,每一个早到的访客都会看到证书警告——在你本来想保护的这个窗口期里,自己给自己制造了一次故障。
切换步骤,按顺序来
到这一步,新服务器已经搭建完成、完成加固、填充了数据、在真实主机名下测试过,并持有一张有效证书。切换本身现在只是一份简短、乏味的清单,而这正是目标所在。
- 如果还有别人依赖这个网站,先公布这次窗口时间,然后把旧站点切换成只读或维护模式。
- 停用旧主机上的cron和后台worker。这一步要在新主机上启用它们之前完成,绝不能放到之后。
- 跑最后一次
rsync增量同步,以及最后一次数据库转储,并把它导入进去。 - 在新服务器上启动应用,再用
--resolve针对最终数据重新跑一遍冒烟测试。 - 把A记录和AAAA记录改成新IP。TTL是300秒的话,全网会在五分钟内跟上。
- 启用新主机上的cron和worker。
- 把两边的访问日志并排盯着看。流量会从旧服务器上退去,出现在新服务器上;等旧服务器彻底安静下来,切换就完成了。
- 让旧服务器继续运行、继续提供服务,一周之内不要动它。它就是你的回滚方案。
第八步是最常被人省掉的一步,也是这份清单里最便宜的保险。只要多花几美元,你就能在自己真正确认没问题之前,一直保留把DNS指回去的能力——一次只需要五分钟就能完成的恢复。
这次迁移会留下什么
这是通用迁移指南通常会省略的部分,如果你是为了隐私而不是为了价格才搬家,这部分恰恰最重要。搬迁一个网站,并不会抹去它的历史。旧安排留下的好几种公开或半公开记录,会永久留存下来,搞清楚具体是哪些,决定了你得到的究竟是一次真正的干净决裂,还是一种虚假的安全感。
| 什么会记录下这次搬迁 | 谁能读到它 | 你实际能做什么 |
|---|---|---|
| 被动DNS——历史A记录 | 任何人,通过商业化的历史查询服务 | 什么都做不了。旧IP会永久和这个域名绑定在一起。就当它是公开信息来做计划,因为它本来就是 |
| Certificate Transparency日志 | 任何人,永久可查,可以按域名搜索 | 每一张签发过的证书都会被列出来——包括你早就忘记的、听起来像内部用途的子域名。比起有描述性的名字,更应该优先选用通配符证书 |
| 旧主机商的账户记录 | 旧主机商,以及任何能强制要求它们交出数据的人 | 银行卡信息、注册邮箱、登录IP。no-KYC目的地保护的是未来,不是过去 |
| WHOIS历史记录 | 商业化的WHOIS历史存档服务 | 如果这个域名曾经用真实信息注册过,那个快照就已经被抓取存档了。事后再开启隐私保护,也无法撤回它 |
| 统计分析和广告标识符 | 服务商,以及任何查看你页面源代码的人 | 沿用同一个追踪ID,会把两个网站确凿无疑地关联起来。换一个新的,或者干脆不用 |
| 留在旧硬盘上的转储和备份文件 | 下一个被分配到这块存储的人 | 注销之前先删除并覆写。在共享存储上,要假设"删除"只是一种提示,而不是保证 |
已发送邮件里的Received:头 | 每一个收件人,永久可见 | 没有任何追溯手段。只有搬迁之后发出的邮件,才会带上新的路径 |
| 复制过程中你自己发起的连接 | 你的ISP,以及两边主机的访问日志 | 这一项完全由你自己掌控。永远不要用一个能指认出你身份的IP去碰这两台机器中的任何一台 |
老实说,一次迁移无法改写过去——它只能让过去不再继续累积。这依然很有价值,但它会改变你的判断:如果你的威胁模型要求任何观察者都无法把新站点和旧站点关联起来,那么把同一个域名搬到新主机上,并不能做到这一点,不管切换过程中你多么小心也不行。那种情况需要一个新名字和一次真正的重新开始,这个话题接下来会讲到。但如果你的目标只是从今天起不再产生新的身份记录,并把法律意义上的重心,搬到一个你自己选定的司法辖区,那么这次迁移恰好能做到这一点。我们的服务器反侦察指南介绍了搬迁之后如何保持这份干净。
域名怎么办:带过去,还是重新开始?
网站和域名是两个独立的决定,但人们经常把它们混为一谈。你完全可以今天就搬迁主机,却永远不去动注册商那边;服务器的变更,并不要求你对域名做任何事。至于你该不该动它,完全取决于这个域名已经掌握了多少关于你的信息。
- 保留域名,更换注册商。当这个域名本身有价值时——外链、排名、一个人们会主动输入的名字——这么做是合理的。它能修正WHOIS记录的未来,而不是它的历史,而且能让所有排名信号原封不动地保留下来。对大多数商业网站来说,这是正确答案。
- 保留域名,只换主机,别的都不动。如果你搬家的原因是司法辖区、正常运行时间或DMCA应对策略,而不是匿名性,这么做完全合理。这是最简单的一种搬法,没有任何SEO风险。
- 换新域名,把旧域名重定向过去。能保住排名,但也会公开且永久地把两个名字关联起来。为了延续性可以这么选,但绝不要为了隐私这么做——重定向本身就是那条关联链。
- 换新域名,彻底决裂。这是唯一真正切断关联的选项,代价是失去你原有的全部排名和外链。从一开始就用隐私方式注册它,因为一个域名的匿名程度,取决于它第一次注册时的状态。我们关于用加密货币匿名注册域名的指南,详细介绍了具体做法。
想清楚了再选,并且要在切换之前选好,而不是切换过程中临时决定。等DNS都改完了才改主意,就等于把这个精细的部分再做一遍。
妥善注销旧主机
切换完成一两周后,等新服务器的日志变得平淡无奇、旧服务器的日志变得空空如也,就该关闭旧账户了。请按下面这个顺序来做,因为那个最诱人的捷径——直接点取消——恰恰是会把你的数据留在别人硬盘上的那一个。
- 确认没有任何东西还指向旧IP:检查第三方webhook、白名单、监控系统里有没有写死的地址,以及任何被你忘掉的DNS记录,比如一个散落在外的
mail或cpanel子域名。 - 轮换掉曾经存在于那台机器上的每一个密钥——数据库密码、API密钥、应用盐值、DKIM密钥、SSH密钥。不要把它们原样搬到新机器上。
- 从旧服务器上移除你的SSH公钥,以及任何技术支持权限。
- 删除应用程序、转储文件和备份,然后覆写剩余空间,这样这块回收的存储被随手读取时,也不会得到任何东西。
- 做完这些之后,才终止服务,并从旧账户里移除任何已保存的支付方式。
任何存在于你不再掌控的硬件上的东西,按定义就已经算是泄露了。这不是因为你的旧主机商心怀恶意,而是因为那块硬盘会被放回资源池里重新分配,而你永远不会知道擦除之后到底还有什么残留下来。轮换一个数据库密码只要两分钟。而几个月后才发现,一台已经注销的服务器上的某把密钥居然还能打开点什么,要花的时间可就长得多了。
整套流程,一页讲完
去掉所有的推理过程,一次主机迁移其实就是九个步骤,其中只有两个真正有时间紧迫性:
- 提前两天:把DNS TTL调低到300秒。
- 提前两天:开出目标服务器并加固它,逐个版本对齐旧的技术栈。
- 提前几天:写好盘点清单——cron、密钥、TLS、邮件密钥、媒体文件、IP白名单、软件包。
- 提前几天:跑第一次完整数据复制,主机到主机直连。
- 窗口开始之前:用DNS-01签发证书,并通过
--resolve测试所有功能。 - 窗口期(几分钟):冻结写入、停用旧的cron、跑增量复制和最后一次转储、启动新应用。
- 窗口期(几秒钟):修改A记录,然后启用新主机上的cron。
- 接下来的一周:让旧服务器继续存活作为回滚方案,同时盯着两边的日志文件,然后再把TTL调回去。
- 之后:轮换密钥、擦除数据、注销账户——并且记住这次搬迁抹不掉的那些东西。
这份清单里没有一步是真正困难的。每一个让人吃苦头的步骤,都是因为顺序做错了——TTL在当晚才调低,证书在DNS变更之后才签发,cron任务留在一台已经不再是权威服务器的机器上继续待命。把顺序理顺之后,一次迁移里真正有意思的部分,就变成了该把服务器放在哪里,而不是搬迁这件事本身。如果你还没想清楚放在哪里,司法辖区选择指南是个不错的起点。