静态博客这事儿我折腾过好几轮最早用动态后台后来发现光维护环境和数据库就够喝一壶的索性彻底转向静态生成。Hexo 是我来回对比之后留下来的那一个它把 Markdown 渲染成纯 HTML整个站点就是一堆文件扔到代码托管平台的静态页服务上就能跑服务器、数据库、后台登录统统不用管。这套流程的核心价值在于写作归写作运维归运维你本地敲hexo new写文章一条命令生成、一条命令推送剩下的交给平台。这篇内容面向三类人完全没碰过静态博客的新手、用过 Hexo 但一直被部署和仓库同步折腾的中级用户以及想把博客源码做版本管理、换电脑不丢数据的老用户。下面从选型、环境、配置、部署同步到问题排查把我踩过的坑和最终跑通的方案完整摊开。1. 动手之前的方案选型为什么是 Hexo 加静态托管1.1 静态站点与动态博客的取舍逻辑先把这个决定讲清楚因为后面所有操作都是围绕它展开的。动态博客的运行链路是请求进来 → 服务器执行程序 → 查数据库 → 拼页面 → 返回好处是评论、后台编辑、实时统计都现成坏处是你要为一个可能一个月只更新两篇的东西长期养着一台机器和一个数据库实例还得盯着程序版本升级和安全补丁。静态博客把这一步彻底砍掉文章在本地编译成 HTML、CSS、JS 三件套上传的就是最终产物访问时平台直接把文件吐给你没有执行环节。这个差异带来的实际影响比想象中大。第一是访问速度静态文件不需要经过任何服务端计算首字节时间基本取决于平台的就近分发能力第二是抗压能力同一篇爆款文章突然来几万访问动态站可能直接被打挂静态站只是多传几个文件而已第三是数据归属你的全部内容就是一堆 Markdown 文本存在自己电脑上、自己仓库里哪天平台不做了换个托管照样发不存在导不出来的风险。代价也很明确没有实时后台改文章得在本地改完重新生成推送原生不支持评论、搜索、阅读量这类需要服务端的功能得靠第三方组件或静态化方案补每次发布是一次全量或增量编译文章多了之后生成时间会线性增长。这三点能不能接受基本就决定了你适不适合走这条路。1.2 Hexo 在同类工具里的位置静态博客生成器不止一个同类里有偏 Go 的单二进制方案、有偏 Ruby 的老牌方案、也有前端框架衍生的方案。我最后留在 Hexo 上主要看三点一是生态成熟度主题和插件数量足够多遇到问题搜到的答案大概率对得上二是写作体验hexo new建文件、Front-matter 写元信息、hexo s本地预览链路短三是它对非前端出身的人足够友好配置文件是 YAML改主题基本靠改配置而不是改代码。需要提醒的是Hexo 本质是 Node.js 应用它的所有依赖都走 npm 生态。这意味着你的 Node 版本、包管理器行为会直接影响构建结果后面环境准备那一章我会专门讲版本对齐这是新手翻车率最高的地方。1.3 一套完整方案需要哪些组件把整条链路拆开看一个能长期用的 Hexo 博客由四层构成我在动手前会先把这四层对应到具体工具避免做到一半发现缺东西。层次作用常见选择我的取舍理由运行时执行生成与部署命令Node.js 长期支持版版本太新容易撞依赖编译问题太旧缺 API版本控制管理源码与发布产物Git 客户端部署插件内部就调用它绕不开内容载体存放文章与配置Markdown 文件 YAML 配置纯文本迁移零成本托管平台对外提供静态访问代码托管平台的静态页服务与仓库同源推送即发布省一次上传这张表看着简单但第二层和第四层的同源是这套方案最舒服的地方代码托管平台既是你的源码仓库又能直接对外提供页面一次推送同时完成备份和发布。后面第四章的双仓库同步就是围绕这个特性设计的。注意不同平台对静态页服务的开放程度不一样有的需要手动开启、有的对仓库公开性有要求、有的对构建频率有限制。选平台之前先确认它的静态页功能当前是否可用、有没有额外条件别等配置全写完了才发现开不了。2. 从零搭起本地写作环境2.1 Node.js 版本选择与安装要点Hexo 官方对 Node 版本有最低要求装之前先去官网确认当前推荐版本别凭印象装。我一般选当前长期支持版LTS而不是最新特性版原因很直接Hexo 的大量依赖是几年前发布的包遇到 Node 大版本跳跃时某些包里的原生模块可能编译失败报错信息还特别难懂通常是一长串 node-gyp 相关的输出。安装时有两个细节值得留意。一是安装路径别带中文和空格Node 的某些子工具对非 ASCII 路径处理得不好后面跑构建脚本容易莫名其妙失败二是装完立刻验证不要跳过这一步。node -v npm -v两条命令都正常输出且版本号符合要求才算环境就绪。如果node -v有输出但npm -v报错多半是安装时没勾选把 npm 加入环境变量。包管理器方面npm 自带够用也可以换成更快的第三方客户端但要注意锁文件格式差异。如果你打算把项目源码提交到仓库锁文件一定要一起提交否则换台机器装出来的依赖树可能完全不同——这是本地好好的换电脑就构建失败的经典成因。实操心得如果npm install卡在某个包上下不动先换镜像源再重试比反复删node_modules有效得多。国内访问官方源偶尔会慢配置一个就近的镜像源能省很多等待。npm config set registry 就近的镜像源地址 npm config get registry改完记得用get确认一下有时候配置写错文件了但命令不报错实际没生效。2.2 Git 身份配置与密钥准备Hexo 的部署插件在底层就是执行 Git 推送所以本地 Git 必须能免交互地完成推送否则每次hexo d都要你输密码。这里要区分两种推送方式走 HTTPS 的需要凭据管理走 SSH 的需要密钥对。我固定用 SSH因为一次配置长期有效。生成密钥对ssh-keygen -t rsa -b 4096 -C 博客部署密钥一路回车即可然后把公钥内容~/.ssh/id_rsa.pub完整复制粘贴到代码托管平台的 SSH 公钥设置里。注意复制的是公钥.pub结尾那个文件私钥绝对不能外传也不建议提交到任何仓库。配置完用一条命令验证连通性ssh -T git平台域名第一次连接会问你确认主机指纹输入 yes。看到带用户名的欢迎语就说明通了如果提示权限被拒Permission denied通常是公钥没粘全或者粘错了行。同时把全局身份配好否则提交记录里的作者信息会是默认值git config --global user.name 你的名字 git config --global user.email 你的邮箱 git config --global core.autocrlf false最后那条core.autocrlf false是我踩坑之后加的。Windows 下默认会把换行符转换配置文件和 Markdown 混着改的时候容易出现整文件 diff 变红的情况关掉省心。2.3 Hexo 初始化与目录结构初勘环境齐了就开始建站。先全局装命令行工具再初始化站点npm install -g hexo-cli hexo init blog-demo cd blog-demo npm installhexo init会把模板文件拉下来npm install才是真正装依赖。这两步顺序不能反我见过有人直接npm i hexo然后在空目录里敲命令结果当然是找不到配置。初始化完成后目录长这样每个目录的职责必须弄清楚后面调配置全靠它blog-demo/ ├── _config.yml 站点主配置 ├── package.json 依赖清单 ├── scaffolds/ 新建文章的模板 ├── source/ 内容源 │ ├── _posts/ 文章正文 │ ├── _drafts/ 草稿 │ └── about/ 独立页面 ├── themes/ 主题 ├── public/ 生成产物自动创建 └── .deploy_git/ 部署中转目录自动创建关键认知只有source/和_config.yml、themes/是你要亲手维护的public/和.deploy_git/是构建产物永远不要手动改也不要提交到源码仓库。很多人第一次提交把public/也塞进仓库导致仓库体积膨胀、diff 一团乱后面清理相当麻烦。2.4 首次本地预览与端口排查生成并启动本地服务hexo generate hexo server浏览器打开http://localhost:4000能看到默认主题的首页说明链路通了。如果打不开先看终端有没有报错再按这个顺序排端口被占用换端口hexo server -p 4001页面空白但控制台 200多半是主题资源路径错检查_config.yml里的url和root修改后不生效先hexo clean再重新生成hexo clean这个命令要养成习惯。它会清掉public/和缓存数据库db.json。Hexo 有增量生成的缓存机制改主题、改配置、换插件之后缓存经常对不上表现就是我明明改了怎么还是老样子。我的规则很简单只要不是改文章正文一律先 clean 再 generate。3. 主题、插件与站点配置的实操调优3.1 _config.yml 里真正需要改的字段配置文件看着字段多实际必须动手的就那么几个剩下的可以保持默认。我把改动的优先级排了一下字段是否必改说明title / subtitle必改站点标题与副标题直接影响首页与标签页author必改作者名主题侧边栏和文章页会用到language必改改成zh-CN否则日期和分页文案是英文timezone建议改填Asia/Shanghai解决文章日期差 8 小时问题url必改填最终访问地址影响 RSS、站点地图和绝对链接root视情况项目页部署时必须填成/仓库名/permalink建议改文章永久链接格式建站初期定好后期再改会断链theme必改填主题目录名必须完全一致url和root这两个字段是部署后样式丢失的头号元凶。规则很简单如果你的站点挂在https://域名/根路径下root就填/如果挂在https://域名/子路径/下root就必须填/子路径/前后斜杠都不能少。生成器靠这个值拼接 CSS 和图片路径填错就是整站裸奔——HTML 有了样式全 404。permalink我一般用:year/:month/:day/:title/这种带日期的结构理由是文章多了之后按时间归档更直观而且日后想换域名不影响路径结构。如果担心中文标题进 URL 出问题可以配hexo-abbrlink插件生成短哈希但要提前定中途换等于全站链接失效。注意permalink一改旧链接全部失效。如果站点已经有外部引用或搜索引擎收录改动前先做跳转方案别图一时痛快。3.2 主题安装与嵌套仓库的坑主题安装有两种方式克隆到themes/目录或者用 npm 安装。我偏好克隆因为改主题源码方便出问题也好定位。cd themes git clone 主题仓库地址 my-theme克隆完把_config.yml里的theme改成my-theme目录名和字段值必须逐字符一致大小写敏感。这里有个几乎所有新手都会撞的坑必须重点说克隆下来的主题目录本身带着.git文件夹而你的博客根目录也是一个 Git 仓库。当你在博客根目录git add .时Git 会把themes/my-theme识别成一个嵌套仓库表现为一个灰色的提交引用实际文件一个都没进仓库。换台电脑 clone 下来themes/是空的构建直接失败。解决办法有三个按推荐度排删掉主题目录里的.git让主题变成普通文件夹随博客仓库一起提交。简单粗暴缺点是主题更新要手动拉。用 Git 子模块submodule挂载主题。规范但每次 clone 需要额外初始化命令对新手不友好。主题的修改用独立补丁文件维护主题本体走子模块。适合主题改动量大的场景。我选第一种因为我改主题改得不多能接受偶尔手动更新。删除命令rm -rf themes/my-theme/.git如果是 Windows 命令提示符用rd /s /q themes\my-theme\.git。删完再用git status看一眼主题文件应该全部变成正常的待添加文件。3.3 写作流Front-matter 与草稿机制建文章hexo new post 文章标题会在source/_posts/下生成一个 Markdown 文件头部带 Front-matter--- title: 文章标题 date: 2025-01-01 10:00:00 tags: - 标签一 categories: - 分类一 ---几个字段的含义要拎清。tags是多对多一篇文章可以打多个标签写法和列表一致categories是多层级的写- 前端再写- 构建工具会生成父子分类关系注意它是按缩进层级解析的不是随意写两个就行。date如果不写Hexo 会用文件创建时间兜底但建议显式写避免复制文件导致时间混乱。草稿机制特别值得用。写一半的文章先扔草稿区hexo new draft 半成品草稿默认不会被生成本地预览时加参数才能看到hexo server --draft写完了转正hexo publish draft 半成品文件会从_drafts/移到_posts/。这个流程的好处是仓库里不会出现半截内容公开站点永远是完整状态。实操心得文件名尽量用英文或拼音别用中文和空格。虽然现代工具链对中文支持不错但在 URL 生成、图片引用路径、某些插件处理上仍然偶发问题。标题可以写中文文件名保持干净。3.4 常用插件与能不加就不加的原则插件生态是 Hexo 的优势也是拖慢构建的元凶。我的态度是只装解决真实痛点的不装看起来有用的。下面这几个是我长期保留的插件解决什么问题是否必须部署插件让hexo deploy能推送到仓库必须搜索插件生成静态搜索索引前端实现站内搜索建议站点地图生成 sitemap 便于收录建议RSS 生成输出订阅源可选短链接把中文标题转成短哈希路径可选图片懒加载长文图片多时改善加载视主题支持安装方式统一是npm install 包名 --save注意加--save让依赖写进package.json否则换机器又要凭记忆重装一遍。要警惕的是那种装了就变慢的插件比如在生成阶段做图片压缩、做全文加密处理的文章一多每次构建都要多花几十秒。我的做法是这类重活儿放在专门的脚本里一次性跑完不挂在构建钩子上。构建速度直接影响写作欲望等两分钟才看到预览写东西的节奏就断了。4. 部署把静态文件同步到代码托管仓库4.1 先搞清楚仓库类型别一上来就配错代码托管平台的静态页服务通常按仓库命名分成两种模式配置差异很大搞错了就是白忙活。用户页模式仓库名和账号名完全一致页面地址是根路径。这种模式下生成的文件要推到默认分支访问地址不带子路径root填/。项目页模式仓库名随便起页面地址带仓库名子路径。文件推到专门的分支常见是gh-pages或master看平台约定访问地址形如https://域名/仓库名/此时root必须填/仓库名/。这两种模式最直观的区别就是root。我见过太多部署成功但页面全白的案例最后都是项目页却把root写成了/。判断方法很简单看你的最终访问地址里域名后面有没有一段子路径。模式仓库命名访问地址root 配置推送分支用户页与账号名一致域名根路径/默认分支项目页任意命名域名/仓库名//仓库名/部署分支4.2 部署插件配置逐行拆解先装插件npm install hexo-deployer-git --save然后打开站点_config.yml找到deploy段改成这样deploy: type: git repo: git平台域名:用户名/仓库名.git branch: gh-pages message: 站点更新: {{ now(YYYY-MM-DD HH:mm:ss) }}四行配置每一行都有讲究。type固定写git这是插件注册的部署器名称写错了会提示找不到部署器。repo用 SSH 地址还是 HTTPS 地址决定了推送时要不要交互。用 SSH 地址形如git...配合前面配好的密钥推送全程无交互用 HTTPS 地址则可能需要凭据缓存。我统一用 SSH省去每次输密码。branch填平台约定的部署分支。注意不同平台约定不同有的用gh-pages有的直接用master。填之前先确认平台文档别照抄别人的配置。message是提交信息可以用模板变量插入时间戳。加时间戳的好处是让每次部署的提交记录可追溯哪天发现线上内容和本地不一致翻提交历史一眼就能看出哪次部署出了问题。配置文件里还有一个容易忽略的地方_config.yml顶部的url字段和deploy.repo必须指向同一个仓库。我见过有人url写着旧仓库地址repo指向新仓库结果 RSS 里的链接全指向一个已经不存在的站点。4.3 双仓库同步源码私有页面公开这是整套方案里我最想强调的部分。很多人的做法是博客源码不纳管只有生成后的页面在仓库里。后果是换电脑、误删目录、硬盘故障全部文章一次性蒸发——这不是危言耸听我身边真发生过。正确做法是两套仓库源码仓库建议私有存_config.yml、package.json、source/、scaffolds/、themes/无.git。这是你的全部家当。发布仓库必须公开或平台允许静态页访问存public/里的生成产物由部署插件自动推送你不需要手动管理。源码仓库的.gitignore建议这样写node_modules/ public/ .deploy_git/ db.json *.lognode_modules不提交是因为体积巨大且可由package.json重建public和.deploy_git是产物db.json是增量缓存提交了反而会在换机器后造成生成异常。初始化并推送git init git add . git commit -m 初始化博客源码 git remote add origin 源码仓库地址 git push -u origin master日常写作的完整闭环就变成了三条命令git add . git commit -m 新增文章: 某某标题 git push hexo clean hexo generate hexo deploy前三条管源码备份最后一条管线上发布。两条线独立哪条出问题都不影响另一条。我习惯把最后一条写成脚本避免每次手敲漏掉clean。#!/bin/bash set -e hexo clean hexo generate hexo deploy git add . git commit -m 部署更新 $(date %Y-%m-%d %H:%M) git pushset -e的作用是任何一步失败就中断避免生成失败了还继续执行部署把空目录推上去覆盖线上内容——这个事故我亲自制造过一次线上白屏了半小时才发现。注意源码仓库设为私有后主题如果用子模块方式挂载克隆时可能因为权限问题失败。这种情况下要么把主题改成普通目录提交要么确保部署密钥有对应仓库的读取权限。4.4 部署后的验证清单推送完成不等于部署成功。平台通常需要一点时间处理处理完之后按这个清单逐项过首页能否打开样式是否正常加载随便点开一篇文章URL 结构是否符合permalink设定图片能否显示相对路径是否被正确处理站内搜索、RSS、站点地图等附加功能是否返回正常手机端访问布局是否错乱如果首页正常但文章 404多半是permalink改了但旧产物没清如果首页白屏但源码是 HTML基本锁定root配置错。这两类问题的排查路径完全不同别混在一起猜。5. 常见问题与排查实录5.1 部署后样式丢失、页面全白这是出现频率最高的问题我把成因按概率排了序。第一位是root配置。项目页部署却没设root生成的 HTML 里 CSS 路径是/css/style.css而实际文件在/仓库名/css/style.css浏览器当然 404。打开开发者工具看 Network 面板如果一片红色 404几乎可以确诊。第二位是url配置。这个字段影响绝对路径的生成包括站点地图、RSS、以及部分主题里的分享链接。填错的直接表现是功能能用但链接指向别处。第三位是主题资源没跟着提交。有些主题把静态资源放在自己的source/目录下克隆时如果走了嵌套仓库那条坑资源文件根本没进仓库本地看着正常因为本地有文件部署上去就缺资源。排查顺序建议先看 Network 面板定位 404 的具体路径再对照_config.yml的root反推正确值最后确认主题资源是否完整。这套顺序能覆盖九成情况。5.2 推送被拒、权限报错的几种典型推送环节的报错信息往往很直接但新手容易慌。我把常见的几种列出来报错特征大概率原因处理方式Permission denied (publickey)公钥未配置或配错重新粘贴公钥用ssh -T验证rejected: non-fast-forward远端有本地没有的提交先git pull --rebase再推failed to push some refs分支名不匹配确认branch字段与实际分支一致remote: 权限不足用只读凭据推送检查账号对该仓库是否有写权限non-fast-forward这个在双仓库方案里特别容易遇到你在网页端手动改过一次文件本地又提交了一次两边分叉了。处理方式是先拉取合并再推送别直接强推--force强推会把远端别人或者另一个设备的你的提交抹掉。实操心得多设备写作时养成动笔前先 pull的习惯。我吃过一次亏在办公室电脑写了一篇回家用笔记本又写了一篇两边都推结果一台机器的提交被覆盖幸好本地文件还在。5.3 本地正常、线上异常这类玄学问题有一类问题最耗时间本地hexo s完全正常部署上去就不对。原因通常藏在三个地方。一是缓存。本地的db.json记录了增量生成的中间状态换环境后缓存对不上生成结果就不同。解决办法是hexo clean后全量重新生成别依赖增量。二是依赖版本漂移。package.json里的版本号如果带^前缀不同时间安装可能拿到不同的小版本行为差异就此产生。要彻底解决就提交锁文件让每次安装的依赖树一致。三是大小写敏感。Windows 和部分系统对文件名大小写不敏感本地引用Image.PNG和image.png都能找到部署到区分大小写的环境就断链。这个问题排查起来极其折磨因为你本地永远复现不了。预防办法是统一命名规范图片一律小写加短横线。5.4 一张速查表收尾把上面这些整理成一张能直接对照的表出问题先在这里找一遍能省掉大量搜索时间。现象优先排查快速验证页面全白无样式root配置看 Network 面板 404 路径文章页 404permalink与缓存hexo clean后重新生成日期差 8 小时timezone字段检查 Front-matter 的 date部署命令找不到部署插件未装npm ls看依赖树主题改动不生效缓存未清hexo clean图片线上 404大小写 / 相对路径对比本地与仓库文件名推送被拒远端有新提交git pull --rebase换机器构建失败主题目录为空检查.git是否被嵌套还有一类问题值得单独提一句文章越写越多之后构建时间从几秒涨到几十秒甚至几分钟。这时候先看是不是装了什么在生成阶段做重活的插件把它们摘掉或改成独立脚本通常能立竿见影。其次看图片大图直接扔进source/会让仓库和构建都变重我的做法是图片走外部图床或者单独的对象存储仓库里只留链接。6. 长期维护的几点个人做法6.1 备份节奏与写作习惯我的备份节奏是写完就推。一篇文章写完、本地预览确认没问题先提交源码仓库再部署顺序不能反。原因是部署动作会触发一次完整的生成和推送如果源码没先备份而部署过程出了问题比如网络中断、插件异常你可能处在一个线上是旧的、本地是新的、但新内容还没入库的尴尬状态。另外我会定期做一次冷备份把源码仓库完整克隆到一个外部存储一年也就几次。版本控制能防误删但防不了仓库本身被误操作删除多一层保险成本很低。写作习惯上我坚持草稿区写作不直接在_posts/里改半成品。原因前面说过但还有个隐性好处草稿不会被生成所以你写一半的时候完全不用担心哪天手滑部署把半成品推上线。6.2 换电脑与迁移的完整动作换设备是检验这套方案是否合格的唯一标准。完整流程如下git clone 源码仓库地址 blog-demo cd blog-demo npm install hexo clean hexo server四步能起来就说明方案是健康的。如果起不来排查顺序是Node 版本是否与package.json里的引擎要求匹配、themes/目录是否为空、_config.yml里的url和root是否还指向正确位置。这里要再强调一次主题那个坑。如果当初没删主题目录的.git克隆下来themes/一定是空的hexo server会提示找不到主题模板。这时候不用慌重新克隆一次主题并把.git删掉然后补一次提交问题就永久解决了。6.3 后续可以扩展的方向这套基础跑通之后能加的东西不少但我不建议一次全上。我的经验是每加一个功能就跑一次完整部署验证确保出问题能定位到具体那一次改动。值得优先考虑的几个方向域名绑定把平台分配的地址换成自己的注意配置后url字段要同步更新、评论组件选静态化方案避免引入服务端依赖、访问统计选轻量脚本别引入拖慢首屏的大文件、内容归档页与标签页大部分主题自带改配置即可。这些都属于加完就不太需要维护的部分性价比高。至于那些需要持续投入的功能比如全文检索服务、图片自动压缩流水线我建议等你确实感到痛了再上。工具是服务于写作的别让维护博客本身变成一件比写博客还累的事——这是我折腾好几轮之后最实在的体会。