Contents
1 前言
我一直想为基于 WordPress 的动态博客搭建一个同步更新的静态副本,一方面是出于对”全站缓存”和”永远在线”能力的追求——毕竟早期博客还没有实现灾备和双活部署,Wordpress 本身一旦宕机,整个站点就会出现访问异常;另一方面,也希望在一些特殊场景中,比如将博客发布到私有网络(如 DN42)中,或者在一些域名的443端口需要伪装时(用来掩饰这些域名上某些路径的特殊作用),能有一个脱离 WordPress 环境也能独立运行的只读副本。
其实早期我也尝试过其他路线的”动态博客静态化”方案,比如那篇用 Hexo基于cloudflare pages搭建静态博客的文章(参见:家庭数据中心系列 使用hexo搭建静态博客并部署到到cloudflare pages)。当时折腾这个其实就是为后续的”静态化”踩盘子:那时的思路是后续将 WordPress 文章导出为结构化数据,再导入Hexo 重新生成一个静态站点。这种方式理论上可行,但最终让我放弃了:从格式转换到样式定制以及argon主题在Wordpress上以及hexo上的差异,各种细节都需要额外折腾,而且生成的站点在视觉效果上总有些割裂感,离我想要的和WordPress动态博客几乎一模一样的”原汁原味”的静态博客还是有较大差距的。
直到最近,我发现了一款非常有意思的 WordPress 插件:Simply Static。它可以在保留原有风格和页面结构的基础上,直接将整个Wordpress网站静态化为 HTML 文件,并导出到宿主机的本地目录。这种方式既不依赖内容迁移,也不改变前端表现,更像是在 WordPress 后面套了一层”脱离数据库和 PHP 的快照层”,让我一下觉得这条”静态化”的路线终于靠谱了。
2 Simply Static插件介绍
Simply Static 是一款专注于将 WordPress 网站”全站静态化”的插件,它的思路并不复杂,却非常实用:通过模拟访问 WordPress 站点的所有页面,将这些页面”爬”下来,转换为标准的 HTML、CSS、JS 和静态资源文件,最终导出到指定的本地目录,或直接上传到远程目标(如 GitHub、S3、FTP 等)。
简单来说,它的原理更像是一个运行在 WordPress 内部的爬虫(crawler),会以访客身份访问你的网站,把动态页面渲染后的结果保存成静态内容。这一点与传统的缓存插件不同,缓存插件更多是在运行时提升响应性能,而 Simply Static 则是彻底”预渲染”,脱离 WordPress 环境后仍能独立运行。
这种方式的好处非常明显:
- 静态资源,极速访问:由于没有数据库查询和 PHP 执行开销,静态站点的加载速度通常远超动态站点。
- 极高的可用性:导出的 HTML 页面可以部署在任意静态站平台上,比如 Cloudflare Pages、GitHub Pages、Vercel 等,即便源站 WordPress 宕机,静态副本依然在线。
- 安全性大幅提升:静态站点没有后台、数据库等攻击面,即使被公开访问,也几乎不可能被入侵。
- 易于集成到自动化流程:通过计划任务或 Webhook,甚至可以实现定期静态化并自动部署,形成 CI/CD 式的内容更新流程。
当然,它的”静态化”并不是没有代价。因为静态站点不再具备 PHP 执行能力,所有依赖动态交互的功能(比如搜索、评论、登录)都会失效——不过,如果你的目标本来就是一个”只读副本”或者缓存加速层,这反而是一种非常清爽的实现路径。
Simply Static 本身支持三种导出模式:
- 本地目录导出(Local Directory):将生成的 HTML 文件写入 WordPress 宿主机的某个目录,适合再手动同步或部署。
- ZIP 文件打包(ZIP Archive):导出后自动打包为一个 ZIP 文件,便于下载或传输。
- 远程部署模式(Remote URL):可配置 FTP、S3 或 GitHub 等远程目标,导出后自动上传部署,非常适合做全自动部署链
我个人最推荐的是”本地目录导出”模式,配合一个 Git 仓库和定时脚本,不仅便于调试,也能把部署过程纳入现有的版本控制体系里。
注:为什么我不推荐直接使用 Simply Static 的远程部署功能将站点发布到 GitHub,而是选择自己手动用 Git 命令推送?其实理由很现实:因为买不起 Simply Static Pro(很多看上去”自动化、省事”的功能,背后往往都写着一行小字:”付费可用”)。与其依赖插件提供的远程同步功能,最终因为权限或频率限制踩坑,不如自己用 Git 管理来得清晰、可控,也更容易集成到自己的部署流程中。虽然略显”原始”,但对于个人用户来说,这恰恰是成本与效率之间的最优解,还是那句老话:”白嫖也可以嫖得有尊严“。
3 Git初始化(可选)
这部分内容不是必须的,仅当你计划将 Simply Static 导出的静态文件的存放到Git目录,通过 Git 命令推送到远程仓库(比如 GitHub)时才需要。本文不涉及这部分内容的具体操作(本来是有的,但是感觉文不对题,又不是必须的内容,就删了,以后专门用一篇讲”关于如何实现静态博客的完全自动化更新”的文章来讲),之所以这里要提一下,是因为如果有这个需求,就需要在Simply Static导出静态文件之前,就按照一定的顺序进行一系列Git相关的初始化操作,
如果你只是将导出的目录保存在本地,用 Nginx、Apache 或 OpenResty 等 Web 服务器直接发布网站,那么完全可以跳过这一步,不会影响站点的正常使用。简单来说,如果你没有”代码托管”或”自动部署”的需求,那 Git 在这里就不是必选项。
不过,即便只是单纯的静态网站,借助 Git 来管理导出的版本,也能带来一些额外好处:比如版本回滚、团队协作、自动化部署(CI/CD)等,尤其当你未来希望将这个静态站点同步到远程节点或集成到更大的发布流程中时,一个 Git 仓库会是非常有用的基础设施。
4 Simply Static插件安装及设置
4.1 Simply Static插件安装
直接使用插件市场安装:

安装完成后直接点击启用即可:

4.2 Simply Static插件设置
4.2.1 概述
Simply Static 插件的设置其实非常简单,核心就两部分:链接替换方式(Replacing URLs)和导出路径(Deployment Settings):前者决定导出的静态页面里所有站内链接该指向哪个域名、使用什么协议,以及是否强制替换;后者则负责指定这些静态文件最终导出到哪里,比如打包为 zip,或写入本地某个目录。大多数场景下,这两项配置设好后就可以直接生成静态站点了,其他设置几乎都可以保持默认(真实原因是其他设置几乎都是付费的~)。
4.2.2 “General”-“Replacing URLs”:

注:下文中会以我的”静态化”博客网址”
https://staticblog.tangwudi.com
“举例。
1、Replacing URLs(替换链接的方式)
这个选项决定了Simply Static 在导出 HTML 时,如何处理站内链接如:文章、页面、资源地址等,下拉菜单中有三个选项:
选项 | 含义与用途 | 推荐场景 |
---|---|---|
Absolute URLs | 所有站内的完整链接(“https://blog.tangwudi.com/xx/xx “)都会被替换,如 https://staticblog.tangwudi.com/xx/xx ,原本站内的”相对路径”不受影响。 |
推荐线上部署的静态站 |
Relative Path | 将站内完整链接替换为相对路径,如 /page/ 或 ../images/xx.jpg | 离线使用、便携 HTML 文件 |
Offline Usage | 所有链接变成纯粹的文件相对路径,如 ./page.html,适合无服务器使用的 zip 包 | 制作离线文档、拷贝进 U 盘等 |
对于打算部署到 Cloudflare Pages 或自建 OpenResty 的静态站,推荐选择 Absolute URLs,最稳定、最兼容。
2、Scheme 和 Host
当你选择 “Absolute URLs” 时,会出现两个额外配置项,用来定义链接前缀:
设置项 | 说明 | 示例 |
---|---|---|
Scheme | 选择链接使用的协议,通常是 http 或 https | 你的网站用 HTTPS,就选 https:// |
Host | 填写你的静态站点域名 | 如 staticblog.tangwudi.com |
最终效果是站内所有链接都会统一替换成形如:
https://staticblog.tangwudi.com/technology/article123/
这样就不会出现原始 WordPress 域名残留的问题,也避免资源跨域或加载失败。
3、Force URL Replacements
默认是关闭,这个选项的意思是:即便链接已经是正确的 URL,也强制再替换一遍成你指定的 Scheme + Host。
作用:
- 修复一些插件/主题输出中”漏网”的旧域名;
- 解决某些短代码、JS 插件留下的硬编码链接;
- 避免导出站混用多个域名,影响加载或缓存;
- 统一链接风格,有利于 SEO 与前端部署调试。
推荐启用(特别是要部署在公网域名、CDN 之上时)
4.2.3 “Deploy”-“Deployment Settings”:

这部分设置决定了:Simply Static 生成的静态 HTML 文件以什么方式以及最终导出到哪里。免费版支持两种导出方式,对应不同的使用场景。
1、Deployment Method(导出方式)
这是导出静态站点的方式,免费版下拉菜单中有两个选项:
选项 | 含义与用途 | 推荐场景 |
---|---|---|
ZIP Archive | 将导出结果打包为一个 zip 文件,用户下载后自行处理 | 手动备份、一次性传输场景 |
Local Directory | 将导出结果直接写入服务器本地某个目录,适合自动部署 | 推荐用于同步部署的场景,如 git 推送或反向代理发布 |
2、Path(导出目录路径)
这个路径是将静态文件实际写入的目录路径,仅在选择了 Local Directory 后才会显示。这个路径必须是 WordPress 所在服务器可以访问并写入的路径。
如果你是 Docker 部署的 WordPress(比如我这种),你需要通过”-v”参数将宿主机目标目录挂载到容器内部。比如将1Panel面板安装的openresty中创建的网站的默认路径挂载到Wordpress容器内部的”/export/static”路径,则使用”-v”参数如下:
-v /opt/1panel/apps/openresty/openresty/www/sites/staticblog.tangwudi.com/index:/export/static
然后在Wordpress中Simply Static插件的 Path 里填写:
/export/static
这样生成的静态站点内容会直接写入openresty网站对应的Web 服务目录中。
3、Clear Local Directory Before Deploy
这个复选框表示:在每次导出前,是否先清空目标目录。
- 建议勾选,确保导出目录不会出现旧文件残留;
- 如果你有一些额外文件不希望被覆盖,或者计划传到对象存储中,”Clear Local Directory”这个选项就不能勾选了,否则就不能实现”增量同步”的效果,相当于每次更新都要全部重新传一遍。
如果你打算自动化同步或集成到现有 Web 服务中,推荐选择 “Local Directory” 模式,并提前将宿主机的目标目录通过挂载方式暴露给容器,比如将 /opt/…/index 映射为容器内的 “/export/static”,然后在插件中配置对应路径即可(注意index目录的权限,不正确设置会导致Simply Static导出失败)。这样静态内容每次导出后就会直接进入 Web 服务目录,配合 Git 管理或反向代理使用非常方便。
5 导出静态站点
5.1 先诊断兼容性问题
开始导出之前先看看Simply Static和URLs、服务器、Wordpress、插件、文件系统、数据库这些有没有什么兼容性问题:

比如我这里和redis插件就有兼容性问题:

禁用redis插件之后再来看就正常了:

5.2 开始导出

然后根据宿主机的性能以及需要转换页面的多少不同,会花费不同的时间,我这次导出时间如下:

最终导出成果:

注:其实这种导出未必要在VPS上进行,要知道VPS的性能一般都不咋地,不太适合资源密集型操作(土豪随意),如果非要在VPS进行导出且文章数量又多的话,耗费几十分钟到n个小时都说不一定,且这个期间VPS的系统资源消耗会陡增。所以如果有条件,完全可以用家里的高性能电脑搭建一个Wordpress来进行这个导出操作,然后使用git命令或者github desktop来完成push操作,后续VPS只需要git clone下来使用即可。
5.3 发布
假设按照之前所说,Simply Static导出的目录直接指定为web服务软件网站的对应根目录(本例中是OpenResty),那么其实已经可以直接进行本地网络的访问了,只是要发布到公网上,还需要最后一步。
以通过cloudflare tunnel发布为例,只需要在tunnel里直接设置公共主机名指向OpenResty的80端口即可,一般对应直接在VPS上安装cloudflared的情形而言,直接指向localhost:80即可,而我因为是部署在家庭数据中心,结构较为复杂,cloudflared是部署在一个lxc上,而冗余Wordpress节点是在另一个虚拟机上,所以不能直接用localhost:80的方式,如下图:

5.4 实际效果展示

别说,还原度高得让我吃惊,除了fontawesome图标显示问题:

这是因为我在 WordPress 中使用 Font Awesome 图标时,选择了本地托管的方式(参见文章:家庭数据中心系列 WordPress 图标字体优化:本地托管 FontAwesome,告别 API 限制),目的是为了解决此前通过 CDN 引入时偶尔遭遇的超过fontawesome月API请求限制的问题。
但这种”优化”策略在转为”静态化站点”之后,反而变成了一个隐患。因为 Simply Static 等工具导出的是纯静态 HTML 文件,它并不会解析或验证 JS 和字体等资源是否真实可访问。一旦这些本地托管的资源路径没有被正确导出(比如遗漏字体文件、路径拼写变化、MIME 类型缺失),前端就会出现图标不显示或样式错乱的现象:
更关键的是,Font Awesome 通常依赖一整套字体文件(如 .woff2、.ttf 等)和相关 CSS 或 JS 文件,如果某一部分没有被导出或配置不当(例如缺少 MIME 响应头),就会导致浏览器加载失败。相比之下,CDN 托管方案虽然会受制于外部网络,但至少能保证资源完整、路径正确、类型匹配,部署更为省心。
因此,虽然本地托管在动态博客运行时更灵活可控,但在构建”静态化版本”时,反而可能带来额外的维护成本和兼容性问题。建议在导出静态版本时,优先采用稳定的 CDN 方案,或确保本地资源完整、路径正确、服务配置齐全,才能真正做到”还原度高、体验一致”的完美静态化。不过我这里就算了,懒得折腾了~~。
至于”静态化”后的实际效果,大家也可以直接体验:https://staticblog.tangwudi.com,以后我也会保持这个”静态化”博客和我的WordPress主博客同步更新。在实现了双活WordPress节点的高可用方案之后,现在又进一步实现了”静态化”博客的永远在线,这下我的心才算是彻底稳了。
不同的 WordPress 静态化方案,其还原程度并不可一概而论。我之所以能在”静态化”后实现高还原度,主要是因为所使用的 Argon 主题本身就是一个前端结构清晰、依赖较少的主题。它大量采用原生 HTML + CSS + 少量 JS 的方式构建页面,没有依赖太多动态渲染或异步加载的交互逻辑,也没有复杂的 Ajax 请求。因此,Simply Static 在导出过程中几乎可以原样还原出完整的页面结构和视觉样式。
此外,我在主题中本就极少依赖动态短代码或需要登录态参与的功能(如点赞、打赏、用户个性化推荐等),这也极大简化了静态化的复杂度。换句话说,Argon 主题本身的“纯前端友好性”使它非常适合被导出为静态站点。
综合来看,如果你选择了一个高度动态、强依赖数据库或登录态的主题,那么在静态化之后想要实现高还原就会困难许多,甚至还需做二次开发或定制导出流程。而像 Argon 这种结构清爽、逻辑简单的主题,在静态化上几乎是”开箱即用”的理想搭配。
6 后话
其实,Wordpress 动态博客的”静态化”还有一个极其适合的使用场景——那就是在国内使用备案域名发布博客内容。反正国内合规要求本就不允许开放评论功能,而评论又是 WordPress 最大的动态价值之一,这种情况下,保留动态逻辑反而是一种浪费。不如干脆导出纯静态版本,用国内的对象存储 + CDN 进行托管发布,轻松实现全站缓存,性能极佳,连 WAF 都省了——反正全是静态文件,没什么可攻击的面。
如果再进一步,结合 Cloudflare 的动态重定向功能(比如基于访问者 IP 国家或 ASN 实现跳转),就可以构建一个智能的访问策略:
- 国外访客自动访问动态 WordPress 主站,获得完整体验,包括评论、订阅、后台交互等功能;
- 国内访客则自动跳转到国内备案域名上,访问静态只读版本,页面加载速度飞快(因为使用国内CDN),且无需忍受 Cloudflare 在国内的不稳定和”负优化”。
这种做法既能兼顾功能性和性能,也绕开了国内各种合规限制和访问障碍,相当于实现了双入口和最优化的体验。最妙的是,这种结构还能天然支持”增量同步”甚至”自动化部署”,维护成本极低,非常适合希望面向中英文双语用户、兼顾国内外读者体验的博客站长。
下一步,就是整个流程全自动化:每周Simply Static定时自动导出、定时自动git到github仓库、自动部署到cloudflare pages,这样就会保持”静态化”博客和Wordpress主博客的每周定时自动同步,之后我会专门用一篇文章来记录这个流程的每一步操作。