微软在 2023 年 10 月 10 日停止了对 Windows Server 2012 / 2012 R2 的支持。这台 ECS 上跑着 WordPress 站点,系统还停留在 2012 R2,已经拿不到任何安全补丁。
阿里云的服务器迁移中心(SMC)提供了原地操作系统迁移能力,可以在保留系统盘数据的前提下把 2012 R2 转成 2019。这篇文章记录完整步骤,以及过程中踩到的四个坑——其中三个坑都出现在迁移之后。
一、最大的坑:别选"更换系统盘"
控制台上有两条看起来很像的路:
- SMC 操作系统迁移:原地转换升级,保留系统盘数据
- 更换系统盘:相当于重装,系统盘数据全部清空
如果选了后者,网站文件、数据库、SSL 证书、win-acme 续订配置会一起消失。这一步选错,后面全是白干。
另外提醒:2012 R2 可以一步到位升到 2019,但 2008 R2 不行,必须先过渡到 2012 R2 作为中间版本。
二、迁移前的硬指标
阿里云对 Windows 操作系统迁移有明确限制,不满足会直接中断:
- 实例规格必须 2 vCPU 2 GiB 及以上
- C 盘未使用空间至少 20 GiB,且未使用空间要大于
C:\Windows目录的大小 - 不支持跨语言迁移(中文版只能升中文版)
- 实例下不能有正在创建的快照,要等快照建完再开始
- 仅限特定地域(国内大部分地域都支持)
如果 C 盘空间不够,先扩容或者清理,否则会在"Windows 安装程序找不到用来存储临时安装文件的有效硬盘驱动器"这一步卡住。
三、实操步骤
第 1 步:先停掉安全软件(避坑 1)
这一点非常重要,也是我踩的第一个坑。服务器上装了云锁这类 WAF,它的驱动会拦截迁移过程中的文件和注册表操作,导致迁移失败或者迁完系统异常。迁移前先把防护关掉,迁完再开回来。
第 2 步:备份
虽然 SMC 会自动给云盘创建快照,但自己再留一份更稳。我这边是:数据库 dump 一份、htdocs 打包一份、证书目录和 win-acme 配置单独复制一份,统统下载到本地电脑。
第 3 步:控制台操作
- 进入 SMC 控制台 → 操作系统迁移 → 开始迁移
- 按实例 ID 和地域选中目标实例,点前置检测(约 10 秒)
- 前置检测通过后,勾选同意为全部云盘创建快照
- 选择目标操作系统:Windows Server 2019 数据中心版 64位中文版
- 点检测是否可迁移(约 30 秒),通过后再点确定迁移
第 4 步:等待,什么都别做
迁移过程中实例会自动重启多次,业务无法访问。这时候千万不要人工去停止、重启或释放实例,否则会导致迁移失败。
迁移状态变成"已完成"后,实例会自动启动进入系统初始化阶段,大约需要 15~30 分钟,期间同样不要操作。
迁完之后,实例 ID、镜像 ID、VPC、公/私网 IP、主机名都保持不变,只有操作系统版本变了。
四、迁移之后的四个坑
坑 1:快照一直在扣费(避坑 2)
迁移时 SMC 会自动创建名为 SMC_Backup_Snapshot_XXX 的按量付费快照。它不是免费的,会一直扣费。确认系统稳定之后(建议 2~4 周)一定要到快照列表里删掉。
坑 2:VC++ 运行库变成 0 字节,程序报"损坏的映像"(避坑 3)
这是迁完最隐蔽的一个问题。执行 PHP 时报错:
PHP Warning: PHP Startup: Unable to load dynamic library 'intl' (tried: C:\xampp\php\ext\intl ... 找不到指定的模块。)
检查发现系统目录里的运行库大小是 0 字节:
dir C:\Windows\System32\msvcp140.dll 2021/10/05 22:33 0 msvcp140.dll
这个空壳文件导致所有依赖 VC++ 运行库的程序加载失败。试图用 VC_redist 覆盖安装时,还会弹出"php.exe - 损坏的映像 / 错误状态 0xc0000020"——比空的还麻烦。
解决办法:从别处借一份完好的 DLL 放进程序自己的目录。Windows 加载 DLL 的顺序是程序所在目录优先,这样不用动系统文件,零风险。我这边是从 MariaDB 11.4 的 bin 目录借的(官方包自带完整运行库):
copy C:\xampp\mysql\bin\msvcp140.dll C:\xampp\php\ copy C:\xampp\mysql\bin\concrt140.dll C:\xampp\php\ copy C:\xampp\mysql\bin\vcruntime140_1.dll C:\xampp\php\ copy C:\xampp\mysql\bin\msvcp140_1.dll C:\xampp\php\ copy C:\xampp\mysql\bin\msvcp140_2.dll C:\xampp\php\
这里还有个容易忽略的点:Apache 和命令行是两个不同的宿主进程,找 DLL 的起点不一样。命令行从 php 目录找,网站从 apache\bin 找。所以我只给 php 目录补的时候,命令行 php -m 已经能看到 intl,但 WordPress 健康检测还在报缺失——必须把 apache\bin 也补上,并且重启 Apache,才真正生效:
copy C:\xampp\mysql\bin\msvcp140.dll C:\xampp\apache\bin\ copy C:\xampp\mysql\bin\vcruntime140.dll C:\xampp\apache\bin\ copy C:\xampp\mysql\bin\concrt140.dll C:\xampp\apache\bin\
坑 3:系统明显变慢,真凶是 Defender(避坑 4)
迁完之后网站从秒开变成 6 秒多,远程桌面也卡。排查发现是 Windows Defender 在 2019 上持续实时扫描网站文件,MsMpEng 进程累计占用了 5000 多秒 CPU,Apache 线程被耗尽并出现 PHP 120 秒超时。
关闭 Defender 并精简系统服务后,响应时间从 6.4 秒回落到 0.63 秒。详细过程见《升级 Windows Server 2019 Datacenter 后优化实战》。
坑 4:C 盘变大了,但内存更紧张
迁移后 C 盘从 40GB 变成 51GB,可用空间从 15GB 涨到 26GB——SMC 按目标系统重建了分区。但 2019 本身就比 2012 R2 吃资源,2 核 4GB 的配置会明显感觉紧。如果预算允许,升级后建议顺带把内存加上去。
五、迁移后检查清单
- 确认系统版本:
winver或命令行ver - Apache、MySQL 能否正常启动,网站前后台是否可访问
- PHP 扩展是否齐全(WordPress 后台 → 工具 → 站点健康会提示缺失模块)
- 证书续订计划任务是否还在,并确认"上次结果"为 0:
schtasks /query /tn "win-acme renew (acme-v02.api.letsencrypt.org)" /fo LIST /v | findstr /i "上次结果 上次运行"
- 外部访问是否正常(HTTPS、证书有效期、无重定向异常)
- 把之前关掉的云锁开回来,并给上传目录加白名单
- 确认稳定后删除
SMC_Backup_Snapshot_XXX快照
小结
整个迁移本身阿里云做得挺顺,真正的麻烦都在迁移之后:服务起不来、扩展加载不了、系统变慢。把上面四个坑提前记住,能省下大半天排查时间。
最后一句经验:迁移当天不要顺带做别的升级。一次只改一样,出问题才好定位。我这次就是迁完系统之后才动 MariaDB 和 Redis,每步都留了回滚方案,全程零数据丢失。