这个博客是怎么搭起来的:安全加固版

5100 字
26 分钟
这个博客是怎么搭起来的:安全加固版

这段时间博客改得比较多,已经和刚搭起来时不太一样了。最开始它更像一个把页面跑起来的模板站:能写文章,能访问,样式也差不多够看。后来慢慢加上了后台、相册、友链、项目、评论、动态、搜索、构建发布和一些防护机制之后,它的形态就更接近一个完整的个人内容站。

所以我想重新记一次现在的技术方案。不是把每个文件、每个接口都摊出来讲,那样没有必要,也不适合公开写;更重要的是把架构和取舍说清楚。这个博客为什么不是纯 Markdown,为什么也没有做成完全动态的站,为什么要把 CMS、构建服务、前台和入口层分开,这些决定才是它现在能继续维护下去的关键。

从模板站到内容系统#

博客这类项目很容易一开始就做得很随意。拿一个主题,改一下配置,写几篇 Markdown,页面能打开,好像就结束了。这个阶段确实很轻松,但只要内容类型开始变多,问题就会慢慢出现。

文章还好说,Markdown 文件能解决大部分需求。可是当你想加友链、相册、项目页、留言、评论、站点公告、导航配置、个人资料、背景图、页面开关、搜索索引时,单纯靠手写文件就会变得越来越散。每改一点东西都要去找配置,内容和代码混在一起,长期维护会很烦。

现在这套博客的思路是把它拆开:内容交给 Strapi 管,前台交给 Astro 生成,构建服务负责把内容同步成静态页面,线上入口由 Nginx 统一处理。这样看起来多了几个服务,但每个部分的职责反而更清楚。

Strapi 更像内容仓库。文章、分类、标签、项目、友链、相册、公告这些东西都可以放在那里维护。Astro 更像展示层,它不关心内容是怎么编辑出来的,只关心构建时能不能拿到干净的数据。构建服务负责把这两者接起来,让内容变化能变成新的静态页面。Nginx 则站在最外面,负责把公开页面、后台入口和动态请求分清楚。

这种拆法不是为了把事情搞复杂,而是为了让每一层都少做一点不该自己做的事。

我现在更愿意把这个博客看成一条内容生产链,而不是一个单独的前端项目。写作只是链路里的一个环节,后面还有整理、发布、索引、归档、展示、评论和维护。以前只盯着页面能不能渲染,现在会更关心这条链路是否顺手:内容能不能很快改,改完之后能不能稳定发布,发布之后能不能被搜索到,出问题时能不能知道问题在哪一层。

这也是它和普通主题站最大的区别。主题站更关注“页面长什么样”,而现在这套结构更关注“内容怎么长期流动”。如果只写两三篇文章,当然没必要这么做;但如果要把博客当作一个长期使用的站点,就不能只靠临时修改和手动复制。

为什么选择 CMS + 静态构建#

我一开始也想过直接做成动态博客。动态博客的逻辑很直观:请求进来,后端查数据库,渲染页面,返回结果。后台和前台都在一个系统里,内容更新后立刻生效,不需要构建。

但对个人博客来说,这个方案有点重。大多数页面其实不需要每次访问都查数据库,文章发布之后也不会每秒变化。把公开访问链路做成静态页面,会更稳、更轻,也更容易迁移。哪怕后台服务临时不可用,已经构建好的页面仍然可以访问。

Astro 很适合这个场景。它可以把文章、页面和组件在构建阶段生成出来,同时保留局部交互能力。搜索可以用 Pagefind 这类静态索引方案解决,RSS、OG 信息、归档页也都能在构建时准备好。访问者打开页面时,看到的是已经生成好的 HTML 和资源,不需要等后端临时拼页面。

CMS 的价值则体现在维护体验上。写文章不一定非要登录后台,但当站点内容变多后,有一个结构化的内容管理层会舒服很多。分类、标签、封面、摘要、友链、相册这些信息,放在 CMS 里更适合长期整理。前台只拿最终导出的结果,不直接承担内容编辑的复杂度。

这就是现在这套方案最核心的取舍:编辑体验靠 CMS,访问体验靠静态站点,中间用构建流程把两边接起来。

这里还有一个实际感受:静态构建会逼着内容边界变清楚。动态站点很容易把很多临时逻辑塞到请求时处理,今天页面缺一个字段,就在渲染时兜底一下;明天某个配置不完整,就在接口里顺手补一下。短期很方便,长期会让数据和页面之间越来越难拆。

静态构建不太一样。构建阶段如果内容结构不对,问题会暴露得比较早。文章、页面、配置、资源路径这些东西都要在构建时整理好,前台拿到的是相对确定的结果。这种确定性对个人站也很有价值,因为它减少了线上运行时的偶然性。

当然,这也意味着内容更新不是保存后立刻变成页面,而是要等一次构建。我觉得这个代价可以接受。博客不是聊天消息,也不是实时看板,文章发布慢几十秒并不影响体验。换来的是更简单的访问链路和更容易缓存的页面。

前台不是只有文章列表#

前台基于 Astro,但它不是一个只会把 Markdown 渲染成文章页的极简站。现在页面里已经有不少内容模块:文章、归档、搜索、RSS、项目、友链、相册、留言、动态、评论,还有一些偏个人化的视觉组件。

这些功能如果全都堆在页面里,会很快变得难维护。所以前台做了比较明显的分层:配置层负责站点信息和开关,内容层负责从生成数据里读取文章和页面,组件层负责布局和交互。像导航、侧边栏、个人资料、主题、背景、公告这些东西,尽量不要写死在页面里,而是通过统一配置来控制。

Astro 的好处是它允许页面大部分保持静态,同时在需要交互的地方引入前端组件。比如搜索、显示设置、归档筛选、分享、一些浮动控件,这些地方确实需要浏览器端状态;但文章正文、归档列表、RSS、项目展示这些内容没有必要全部变成客户端渲染。

这种写法比较适合博客。页面打开时不应该让读者先等一套完整应用启动起来。文章站最重要的还是阅读,交互只是辅助。把静态内容和局部交互分开,可以让页面保持轻,同时不牺牲必要的体验。

在页面设计上,我也尽量让功能服务于内容。比如归档页要方便回看旧文章,搜索要能快速定位主题,RSS 要给习惯订阅的人留入口,项目页和相册则承担一些文章之外的展示。它们不是彼此独立的小页面,而是围绕个人站点的内容组织方式展开。

个性化组件也是这样。页面里有一些视觉效果和小组件,但它们不应该抢走阅读本身的注意力。博客可以有个人气质,但不能变成一个只展示效果的页面。前台结构之所以拆成配置层和组件层,也是为了让这些增强能力可以开关、替换和继续调整,而不是永远绑死在页面里。

这部分后面还会继续磨。阅读体验、移动端表现、搜索命中质量、文章推荐逻辑,这些都不是一次写完就结束的东西。内容站会随着内容变多而改变,前台也要跟着调整。

内容同步这条线#

内容同步是这套博客里很关键的一环。后台维护的是结构化内容,前台需要的是适合 Astro 读取的本地内容。中间必须有一个转换过程。

构建时,站点会从 CMS 取出已经发布的内容,再写入前台的生成目录。文章会变成带 frontmatter 的 Markdown,站点设置和页面配置会变成前台可直接导入的数据。然后 Astro 再按自己的内容集合规则读取这些文件。

这样做有几个实际好处。

内容源是统一的,不会出现一部分文章在 CMS、一部分文章在前台目录里互相打架。构建产物是确定的,出了问题也比较容易定位是内容导出、同步脚本还是 Astro 构建阶段的问题。同步后的文件可以被前台工具链正常处理,搜索索引、RSS、页面路由都围绕同一份生成内容工作。

我比较在意的一点是,前台不要在运行时依赖 CMS 的实时响应。CMS 是写作和管理入口,不应该成为每一次阅读的必要条件。这个边界划清之后,公开站点会稳定很多。

同步脚本本身也承担了一点“翻译”的工作。CMS 里的字段更适合后台管理,前台的 frontmatter 更适合 Astro 内容集合。两者不应该强行长得一模一样。中间转换层可以把发布时间、摘要、标签、分类、封面和正文整理成前台需要的形状。

这种转换层还有一个好处:以后如果 CMS 字段发生变化,前台不一定要跟着大改。只要导出结果保持稳定,展示层就能继续工作。反过来,前台想调整展示方式,也不必要求 CMS 立刻改变内容结构。

我不想让博客变成“后台字段牵着页面跑”,也不想让“前台组件需要什么就随便改 CMS”。同步层处在中间,虽然多了一步,但它让两边都有一点缓冲。

后台承担的是维护工作#

这个博客有独立的管理界面,不是为了做得多华丽,而是为了把日常维护集中起来。

后台主要处理几类事情:内容维护、媒体管理、互动内容查看、构建状态确认,以及一些站点配置。平时改文章、改友链、整理项目、看评论和触发重建,都可以在一个入口里完成。相比直接面对 CMS 原始后台,这种方式更贴近自己的使用习惯。

后台和前台的关系也比较清楚。前台负责展示,不承担复杂管理能力;后台负责维护,不直接干扰读者访问。构建服务则处在中间,把后台里的变化转成新的前台页面。

这种设计并不新鲜,但对个人站很实用。很多博客后来维护不下去,不是因为技术太难,而是每次改内容都太麻烦。入口一多、配置一散,就会越来越不想碰。把维护路径收拢起来,反而能让站点继续更新。

后台现在更像一个“站点工作台”。它不需要覆盖所有底层能力,也不需要把每个 CMS 功能都重新做一遍。真正常用的东西放在前面,不常动的配置保持克制。这样日常维护时不必在多个入口之间来回跳。

我对后台的期待也不是越复杂越好。个人站的后台如果做得太重,维护它本身又会变成新的负担。现在更倾向于把它做成刚好够用:能改内容,能看状态,能处理互动,能触发构建,能留下必要记录。剩下的部分慢慢补,不急着一次铺满。

部署层的分工#

生产环境使用 Docker 组织服务。数据库、CMS、构建服务和 Web 服务各自运行,外部访问由 Nginx 统一进入。这样的结构迁移起来比较方便,也能把数据、内容服务、构建流程和静态文件服务分开处理。

构建服务的职责很单纯:收到重建请求后,同步内容,执行前台构建,生成搜索索引,再把产物放到 Web 服务使用的位置。它不负责管理内容,也不负责直接对外展示页面。只做发布链路里的那一段。

Nginx 的作用也不只是“转发请求”。它需要处理静态资源缓存、页面访问、后台入口、动态请求和基础安全头。静态资源适合较长缓存,页面内容需要更容易更新,动态请求则要和普通页面访问区分开。入口层把这些规则统一起来,后面的应用就不必每一层都重复处理同样的问题。

这套部署方式算不上复杂,但比把所有东西直接跑在一个进程里更稳一些。出了问题也比较容易判断是哪一层:内容源、构建、静态产物、入口转发,边界都是清楚的。

Docker 在这里的价值主要是降低环境漂移。博客依赖不少前端工具和 CMS 运行环境,如果直接在服务器上手动装,很容易过一段时间就忘了当初装过什么。容器化之后,服务之间的关系、端口、挂载目录和启动顺序都更明确。

Nginx 则像是站点的门面。它不参与内容生产,也不理解文章是什么,但它决定外部请求怎么进入系统。静态文件、后台、动态请求、资源缓存都在入口层被整理好,后面的服务才能保持相对单纯。

这套部署还在继续维护。现在能稳定跑,但后续还会补更完整的备份、构建后检查和故障恢复流程。站点一旦放到线上,部署就不是“能启动”这么简单,还要考虑哪天迁移、重启、更新或恢复时是不是足够可控。

安全不是单独加一个开关#

这次博客改动里,安全防护占了不少比例。但公开文章里没必要写具体规则和触发细节,讲清楚思路就够了。

我的理解是,个人站点的安全不应该只靠某一个点。不是“加了登录就安全”,也不是“写了几个响应头就安全”。更实际的做法是分层:入口层先把明显不该进入应用的请求挡在外面;应用层再处理身份、来源、格式和输入;内容层尽量减少运行时暴露;审计层记录关键行为,方便之后排查。

入口层主要关注边界。哪些服务应该公开,哪些只应该内部访问,哪些请求需要更严格地处理,这些都应该在最外层先区分清楚。

应用层关注可信输入。后台操作、互动内容、上传内容、构建触发这类行为,都不能只看“请求到了就执行”。来源、格式、权限和内容都需要被检查。这里不追求把所有风险都讲得很神秘,很多防护其实都是朴素原则:少信任前端,少暴露内部能力,少让异常输入进入核心逻辑。

内容层的静态化也算一种安全边界。公开文章页不需要读数据库,不需要直接调用 CMS,也就少了一部分运行时攻击面。静态站点不是万能防护,但它能让公开阅读链路变得更简单。

审计层则是为了事后能看见发生了什么。个人站点也会被各种自动扫描扫到,也可能遇到奇怪的请求。能记录、能查看、能定位,比完全不知道发生过什么要好得多。

安全这件事很容易写得很吓人,也很容易被写成几个名词的堆叠。我更愿意把它当成日常维护的一部分。入口层少暴露一点,应用层少信任一点,内容层少依赖一点,后台操作多留一点痕迹,这些原则都不复杂,但坚持做会让系统稳很多。

博客不是高风险业务系统,但它也不是无人问津的本地页面。只要挂到公网,就会面对各种自动化探测。与其假设没人会扫到,不如把边界提前理清楚。该公开的公开,不该公开的收起来,能静态化的静态化,能记录的关键行为记录下来。

这里不会写具体防护规则,因为公开这些细节没有意义。真正值得记录的是设计方式:不要把安全压在某一个点上,而是让每一层都承担一点责任。

继续维护的方向#

这个博客还在继续维护,不是写完这篇文章就定型了。现在比较想补的方向有几个。

构建结果需要更自动化的检查。比如构建完成后,关键页面、RSS、搜索索引、文章路由是否都正常,可以通过脚本自动看一遍。这样比上线之后手动点页面更可靠。

内容预览也值得继续做。现在的构建链路已经能稳定发布,但写文章时如果能更自然地预览草稿,会更接近长期写作的习惯。

备份和恢复也要继续加强。个人站最怕的不是某个功能小 bug,而是服务器迁移或故障时内容丢失。数据库、上传文件、生成产物和配置都应该有清楚的备份策略。

后台体验也还有很多细节能磨,比如媒体管理、评论整理、构建状态提示、操作记录筛选,这些都不是很炫的功能,但会直接影响以后愿不愿意继续维护。

继续写下去#

这套博客方案不是为了把技术栈堆满。Astro、Strapi、Docker、Nginx 这些东西放在一起,如果没有清楚的边界,只会让项目变重。现在真正有价值的是:内容管理、静态构建、后台维护、部署入口和安全边界各自有位置。

它不是最简单的博客,也不是最完整的内容平台。它更像一个按自己使用习惯慢慢整理出来的个人内容系统。写文章的时候,不需要每次碰代码;读者访问的时候,不需要依赖后台实时渲染;需要改站点的时候,也有相对清楚的维护入口。

后面还会继续改。博客这种东西本来就不该一次做完,它更像一个长期在身边的工具。只要它还能稳定地承载内容,能让我愿意继续写下去,这套技术方案就算是走在正确的方向上。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
这个博客是怎么搭起来的:安全加固版
https://xustalis.site/blog/posts/how-this-blog-was-built/
作者
Xenith
发布于
2026-04-28
许可协议
CC BY-NC-SA 4.0
文章互动

点赞和收藏保存在当前浏览器;复制链接可用于分享。

评论区

评论使用站点内置账号系统,内容会在服务端做校验与纯文本渲染。
正在加载评论...
作者头像
Xenith
记录开发、设计与日常思考。
此刻天光
凌晨
此时

天色最安静的时候,适合把没说完的话先放下

去别处看看

一些经常会回来的入口

站点统计
文章
5
分类
1
标签
21
总字数
30,157
运行时长
0
最后活动
0 天前
熊猫助手 站内问答优先

目录