再见了,WordPress,我把网站迁移到了 EmDash

先说结论:如果你是个人站长,WordPress 和其他服务挤在同一台小服务器上,又没有精力天天打补丁,那么把网站搬到 EmDash 这类无服务器的 CMS,是一笔很划算的买卖。我刚搬完,下面是完整的复盘。
9 月 27 日早上 7 点,新加坡那台服务器的 CPU 突然被打满。
我登上去一看,一个来自印尼的 IP 正在用 Acunetix(AWVS)漏洞扫描器,以每分钟 300 到 400 次请求的速度,一页一页地"体检"我的 WordPress。它没有攻进来,但也不需要攻进来。这台 2 核 2G 的突发型实例用的是 AWS 的 CPU 积分制度:基准性能只有 20%,超出的部分靠积分撑着,积分一旦用完,CPU 就被限流在 20%。六个小时后,积分烧光了,整台机器彻底卡死,任何任务都运行不了。我在 AWS 后台看到 CPU 一直停在 20%,宝塔面板里的 CPU 则一直是 100%。
更要命的是,这台机器上不止跑着博客。网盘、iClone 的安装包下载站、抖音截流工具的后端、直播推流,全挤在同一个宝塔面板、同一个 nginx 里。一个扫描器冲着 WordPress 来,结果所有服务陪着一起瘫。
这不是第一次。Cloudflare 防火墙里那条"屏蔽 IP"规则,在这之前已经攒了 8 个 IP,每一个背后都是一次类似的扫描或攻击。
那天我把火灭了:在 nginx 里补上真实 IP 识别、封掉扫描器、加了页面缓存和按 IP 限速,机器总算缓了过来。然后我做了一个决定:
别再修了,搬家。
第二天,baoge.vip 从 WordPress 迁移到了 EmDash,跑在 Cloudflare 上。这篇文章讲讲为什么、怎么搬、搬完之后有什么不一样。
一、WordPress 的问题,不在 WordPress 本身
先说句公道话:WordPress 没有错。按 W3Techs 的统计,全世界 40.2% 的网站在用它,子比主题也陪了我好几年。问题出在"一个人维护的小站 + 一台共享的小服务器"这个组合上。
事后复盘,那次瘫痪暴露了几个长期存在的隐患:
1. 每一次访问都在跑 PHP。
服务器是 nginx,但装的是 LiteSpeed Cache 插件。LiteSpeed 的页面缓存只在 LiteSpeed 服务器上生效,在 nginx 上等于没装。源站返回 no-store,Cloudflare 也就老老实实地不缓存。结果是:每个访客、每个爬虫、每个扫描器的每一次请求,都要完整执行一遍 PHP + MySQL。扫描器每分钟几百次请求,就是几百次完整的页面渲染。
2. 攻击面太大。xmlrpc.php、wp-login.php、wp-json、主题和插件里每一个 PHP 文件,都是扫描器的目标。我用的 PHP 7.4 早在 2022 年 11 月 28 日就停止支持了,子比主题停在 8.6,插件要一个一个跟着升级。Cloudflare 在介绍 EmDash 时引用了 Patchstack 的数据:WordPress 网站 96% 的安全问题来自插件。WordPress 创始人对这个说法和对比方式公开表示过异议,但对我这种装了一堆插件的小站来说,方向是对的:安全这件事,靠的是你永远不忘记更新。
3. 一个服务出事,所有服务陪葬。
博客、网盘、下载站、直播、业务后端共用 CPU、内存、磁盘和 nginx。扫描那天我还顺手发现:磁盘已经用到 88%,光 baoge.vip 的访问日志就有 3.7G。
4. 看不见攻击者。
nginx 没配 Cloudflare 的真实 IP,日志里全是 Cloudflare 节点的地址。想知道是谁在打,得去抓 php-fpm 进程的参数。
这些问题每一个都能修,而且我那天也确实修了。但修完我意识到:我在给一个本来就不适合的架构打补丁。
二、为什么选 EmDash

EmDash 是 Cloudflare 开源的内容管理系统,官方的说法是 WordPress 的"精神继任者"。就在我搬家的同一天,9 月 28 日,它发布了 1.0 稳定版。
它吸引我的地方有三个:
- 没有服务器。 基于 Astro,用 TypeScript 写成,直接跑在 Cloudflare Workers 上。数据库是 D1,图片存在 R2。没有 PHP,没有 MySQL,没有宝塔,没有需要我半夜 SSH 上去的机器。
- 插件在沙箱里跑。 WordPress 的插件和站点同权限运行,一个插件出了漏洞,整个站都暴露。EmDash 的插件运行在隔离环境里,只能访问自己的私有存储,碰不到站点内容、用户、密钥和网络;需要额外能力时必须先声明,再由管理员批准。
- 没有密码可以爆破。 EmDash 默认用通行密钥(Passkey)登录,没有可泄露的密码,也就没有暴力破解的入口。
- 后台还是后台。 我不想换成"改个错字也要 git push"的纯静态站。EmDash 有完整的可视化中文后台,写文章、改首页、调颜色、换菜单都在网页里完成,这点和 WordPress 的体验很接近。
三、清晰对比:搬家前 vs 搬家后

对比项 | 以前:WordPress + 子比主题 | 现在:Astro + EmDash |
|---|---|---|
运行环境 | 新加坡 2 核 2G 突发型实例,宝塔面板 | Cloudflare Workers,全球边缘节点 |
技术栈 | PHP 7.4(已停止维护)+ MySQL | TypeScript + D1 数据库 + R2 存储 |
页面缓存 | 实际没生效,每次访问都跑 PHP | 边缘缓存,页面和图片由 Cloudflare 直接返回 |
被扫描时 | CPU 打满、积分耗尽、整机卡死 | 请求落在边缘,没有一台"我的服务器"可以被打满 |
故障影响范围 | 博客、网盘、下载站、直播一起受影响 | 网站与其他业务彻底分开,互不拖累 |
登录入口 |
| 只有管理员一个账号,通行密钥(Passkey)登录,无密码可爆破 |
会员 / 评论 | 开放注册、评论、论坛模块 | 全部关闭,没有公开账号 |
插件安全 | 插件与站点同权限运行 | 支持沙箱插件,按声明的权限授权 |
日常运维 | 更新 PHP、主题、插件,清日志,看磁盘 | 基本为零,升级时改版本号、部署即可 |
备份与回滚 | 宝塔备份 + 手动导出数据库 | D1 时间点恢复 + 整站导出 + Worker 一键回滚 |
给 AI 读的内容 | 无 | 自动生成 |
如果只能挑一行来说明这次迁移,我会选"被扫描时"那一行。以前被扫描是事故,现在被扫描只是 Cloudflare 日志里多了几行记录。
四、搬家是怎么做的
整个迁移用了一天多,9 月 28 日晚上正式切换上线。步骤大致如下,给想搬家的朋友参考。
EmDash 官方提供两种导入途径:在 WordPress 后台导出 WXR 文件,或者安装 EmDash Exporter 插件,附件媒体会自动迁进媒体库。我的站有不少定制需求,所以走了一条自己写脚本的路线:
第 1 步:把 WordPress 的内容完整拉下来。
用 WordPress 自带的 REST API 导出文章、分类、标签和 SEO 信息,存成 JSON 快照,作为迁移的唯一数据源。一共 37 篇文章、83 个标签。
第 2 步:把图片搬到本地。
60 张文章配图全部下载到本地备份,再统一上传到 R2。这里踩了一个坑:旧站对"非浏览器"的请求直接返回 404,而 Cloudflare 会把这个 404 缓存下来,导致真实访客也看到裂图。最后不得不去 Cloudflare 后台手动清掉缓存。教训:迁移脚本请求线上旧图时,要带上浏览器的 Accept 头,再加一个随机参数,绕开共享缓存。
第 3 步:生成种子文件,导入 EmDash。
把快照转换成 EmDash 的种子文件(seed),里面包括内容模型、页面区块、菜单、分类和全部文章。新建站点时选择导入种子,再跑脚本上传图片、恢复每篇文章原来的发布日期。
第 4 步:保住旧网址,SEO 一点不丢。
这是最重要的一步。旧文章的网址是 /247.html 这种格式,新站原样沿用,文章的 slug 就是原来的 WordPress ID。旧的图片地址 /wp-content/uploads/…、旧的搜索链接 /?s=、/?p= 全部 301 跳转到新地址。新写的文章也接着编号,从 935 开始。
第 5 步:整理排版。
写了一个脚本给旧文章统一格式:加粗行变成小标题、自动生成目录、编号段落变成列表。脚本在写入前会逐篇核对文字、链接、图片和代码与原文一致,只动格式,不动一个字。
第 6 步:部署和切换。npm run deploy 一条命令构建并部署到 Cloudflare Workers,再把 baoge.vip 绑定为 Worker 的自定义域名。切换前在预览域名上验收了一遍;同时保留回滚方案:解绑域名、恢复原来的 DNS 记录,几分钟就能切回旧站。
如果你也想搬,最小的路径其实很短:
npm create emdash@latest
npm run dev # 本地 http://localhost:4321/_emdash/admin
npm run deploy # 部署到 Cloudflare难的不是部署,而是迁移内容时"网址不变、图片不丢、格式不乱"这三件事。
五、搬完之后,也有代价

说清楚好处,也要说清楚代价:
- 生态还很年轻。 EmDash 1.0 刚发布不久,没有 WordPress 那样海量的主题和插件。想要的功能,很多时候得自己写。
- 要懂一点代码。 主题是 Astro 组件,定制页面要改代码。好在后台已经能覆盖日常的大部分操作。
- 放弃了一些功能。 评论、会员、论坛我都关了。对我的站来说这些本来就是负担,但如果你的站靠社区运营,要慎重。
- 备份方式不同。 D1 的原生导出不支持 EmDash 的全文搜索表,要用 EmDash 自带的整站导出,加上 D1 的时间点恢复。
- 沙箱插件有门槛。 在 Cloudflare 上,EmDash 通过 Worker Loader 以 Dynamic Worker 的方式运行沙箱插件,这需要 Workers 付费计划。我现在用的两个插件(SEO 和配色)都是跟站点代码一起部署的原生插件,没有走沙箱,所以装什么插件仍然要自己把关。
- 版本要锁死。 我把 EmDash 的版本号精确锁定,每次升级先读更新说明、先备份、本地验证,再上线。
六、写在最后
回头看,那个印尼扫描器反倒帮了我一个忙。它让我看清楚:对个人站长来说,最稀缺的不是服务器性能,而是注意力。每一台需要我盯着的服务器,每一个需要我记得更新的插件,都在消耗这种注意力。
现在的 baoge.vip 没有服务器可以被打满,没有登录页可以被爆破,旧文章的网址一个没变。我终于可以把时间花在写内容上,而不是守着 CPU 曲线。
再见了,WordPress。谢谢你这几年。
新站地址还是那个:https://baoge.vip ,欢迎来逛逛。
参考来源
- Cloudflare:Introducing EmDash — the spiritual successor to WordPress that solves plugin security,https://blog.cloudflare.com/emdash-wordpress/
- Cloudflare:EmDash 1.0: the stable CMS with a secure plugin registry,https://blog.cloudflare.com/emdash-cms-plugin-registry/
- EmDash 源码仓库,https://github.com/emdash-cms/emdash
- PHP 官方:Unsupported Branches,https://www.php.net/eol.php
- W3Techs:Usage statistics of WordPress,https://w3techs.com/technologies/details/cm-wordpress



