1 静态博客是怎么回事
博客分两种:动态和静态。
动态博客(WordPress、Typecho 这类)需要一台服务器,每次有人访问,服务器现场查数据库、拼页面、再发给你。功能强,但要维护服务器、要操心数据库、访问量一大就慢。
静态博客(Hexo、Hugo、Jekyll 这类)是在你自己电脑上把文章提前编译成 HTML,然后把这一堆 HTML 文件扔到任何能托管文件的地方。访客拿到的就是现成的页面,没有数据库、没有后端。
静态博客的好处很实在:
——快。没有数据库查询,纯静态文件,秒开。
——省。托管到 GitHub Pages、Cloudflare Pages 都免费;自己有服务器的话资源占用也极低。
——安全。没有后端,也就没有后端漏洞可打。
——文章是自己的。全部是本地 Markdown 文件,随时能搬走。
代价是:评论、搜索这些“动态”功能得另外想办法(用第三方服务,或者干脆不要)。对我来说这笔交易很划算——我只是想安静地写东西。
这个博客就是用 Hexo 搭的,主题是 Stellar,部署在自己的服务器上。下面是我实际走了一遍的流程。
2 装环境
需要两样东西:Node.js 和 Git。
Node.js:去官网 https://nodejs.org/ 下 LTS 版本(长期支持版),一路下一步就行。装完在终端里敲 node -v,能输出版本号就成了。
Git:从 https://git-scm.com/ 下载安装。装完敲 git --version 验证。
两个都装好后,装 Hexo 的命令行工具:
1 | npm install -g hexo-cli |
如果这一步报网络错误,多半是 npm 源的问题,换成国内镜像:
1 | npm config set registry https://registry.npmmirror.com |
3 建站与目录结构
找个放博客的目录,执行:
1 | hexo init my-blog |
hexo init 会生成一套完整的目录骨架。装完依赖后,本地预览:
1 | hexo server |
浏览器打开 http://localhost:4000,能看到默认页面就成了。
3.1 目录结构
Hexo 的目录结构不复杂,但几个关键目录要分清:
1 | my-blog/ |
核心就一句话:source/_posts/ 里放 Markdown,_config.yml 里改配置,themes/ 里换主题。 其它都是自动的。
public/ 是编译产物,不要手动改——下次 hexo generate 会覆盖掉。要改样式改主题文件或配置,不要动编译结果。
3.2 常用命令
| 命令 | 作用 |
|---|---|
hexo new "标题" |
新建文章 |
hexo new page "关于" |
新建独立页面 |
hexo server |
本地预览(默认 4000 端口) |
hexo generate |
编译成静态文件 |
hexo clean |
删掉编译产物和缓存 |
hexo deploy |
部署 |
hexo clean && hexo generate |
改配置后必做 |
提醒一下:改了配置文件、主题、或者 front-matter,都要 hexo clean 再 hexo generate,否则可能读的是缓存。
4 写第一篇文章
1 | hexo new "我的第一篇文章" |
这会在 source/_posts/ 里生成一个 .md 文件,开头是文章元信息(front-matter):
1 |
|
下面的正文用 Markdown 写。不熟悉 Markdown 的话见Markdown 入门。
几个常用的 front-matter 字段:
| 字段 | 作用 |
|---|---|
title |
文章标题 |
date |
发布日期(决定排序) |
tags |
标签,写成 YAML 数组 [a, b] |
categories |
分类 |
description |
摘要,首页卡片和搜索结果会用到 |
cover |
封面图路径 |
banner |
文章页顶部大图 |
katex |
是否加载数学公式支持 |
建议每篇都写 description。 首页卡片如果没摘要会取正文前几十个字,效果通常很难看。
还有个细节:文件名决定 URL。Hexo 默认按 日期/标题 生成路径,如果你手动改了文件名,URL 也会跟着变,已经发出去的链接会失效。想固定 URL 的话,最稳妥的做法是一开始就用“日期+序号”这种不含中文的名字,比如 202609200100.md。
5 主题:我用的是 Stellar
Hexo 自带一个很朴素的主题。我试过几个之后选了 Stellar。
5.1 主题信息
| 项目 | 内容 |
|---|---|
| 名称 | Stellar |
| 作者 | xaoxuu |
| 仓库 | https://github.com/xaoxuu/hexo-theme-stellar |
| 文档 | https://xaoxuu.com/wiki/stellar/ |
| 版本 | 我用的 1.44.0 |
| 许可 | 开源 |
选它的原因有几个:
——自带的功能够全。标签页、归档、搜索、相关文章、目录、代码高亮、数学公式,开箱就有,不用自己一个个装插件。
——Wiki 系统。这是它比较特别的地方:可以把文章组织成项目式的“书架”,适合写系列文章。这个博客的数学、Abaqus、MATLAB 几个专栏就是用这套东西组织的。
——配置文件分开放。主题自己的配置在 _config.stellar.yml,和站点的 _config.yml 分开,升级主题时不会被覆盖。
——可定制程度高。想改样式可以直接注入自定义 CSS,不用去改主题源码。
5.2 安装
两种方式,选一种:
1 | # 方式一:Git 克隆(推荐,方便升级和改源码) |
然后在 _config.yml 里指定:
1 | theme: stellar |
建议用 Git 克隆的方式。 因为主题文档里推荐的很多效果(自定义样式、局部改版)需要能看到主题源码;npm 装的话文件在 node_modules 里,改起来不方便。
5.3 配置
Stellar 的配置分两个文件:
| 文件 | 作用 |
|---|---|
_config.yml(站点根目录) |
站点信息:标题、作者、部署方式、theme |
_config.stellar.yml(站点根目录) |
主题配置:菜单、侧栏、样式、插件 |
主题自己的默认配置在 themes/stellar/_config.yml,不要直接改它。 正确做法是在站点根目录建一个 _config.stellar.yml,把要改的项写进去——同名文件会覆盖主题默认值。这样升级主题时你的配置不会丢。
常改的几项:
1 | # 站点标题与副标题 |
主题还支持注入自定义内容(inject.head),这是自定义样式的入口。我的做法是把所有自定义 CSS 写成一个 <style> 块塞在里面——好处是升级主题不会丢,坏处是这个文件会越来越长。
5.4 我改动的部分
主题再好也有不合适的地方,我改了几处。这里记一下,因为升级主题时这些改动会被覆盖:
| 文件 | 改了什么 | 不改的后果 |
|---|---|---|
layout/_partial/main/article/related_posts.ejs |
兼容 wiki 页面的标签格式 + 去重 | wiki 页面整页报错 |
layout/page.ejs |
让 wiki 页面也显示相关文章 | wiki 页没有相关文章 |
layout/tags.ejs |
一级标签优先排序 | 标签页顺序混乱 |
layout/_partial/head.ejs |
微信 X5 浏览器的 viewport 适配 | 微信里字号偏小 |
教训是:改主题源码一定要记下来。 我第一次升级主题时忘了这回事,几个功能直接坏了,排查了半天。现在我在项目根目录放了一份改动清单,升级前先看一遍。
还有一点值得说:主题的配置项和主题的源码是两回事。配置项(_config.stellar.yml)升级不会丢,源码改动会丢。所以能用配置解决的,别去改源码。
6 部署:我用的是自己的服务器
编译一次看看:
1 | hexo clean # 清掉旧的编译产物 |
public/ 里就是完整的静态站点。把它放到任何能托管静态文件的地方就行。下面三种方案我都了解过,我最终选的是方案 B。
6.1 方案 A:GitHub Pages(免费,最省事)
(1)在 GitHub 建一个仓库,名字必须是 <你的用户名>.github.io。
(2)装部署插件:
1 | npm install hexo-deployer-git --save |
(3)改 _config.yml:
1 | deploy: |
(4)部署:
1 | hexo deploy |
等一两分钟,访问 https://<用户名>.github.io 就能看到了。
缺点:国内访问 GitHub Pages 时快时慢;想绑自己的域名要额外配置;不能跑任何服务端逻辑。
6.2 方案 B:自己的服务器(我用的这个)
有服务器和域名的话,可以自己搭。思路是:服务器上放一个 Git 裸仓库,本地推送,服务器收到后自动把文件同步到网站目录。
这套流程的好处是完全自主——域名、HTTPS、缓存策略都由你定,访问速度也比 GitHub Pages 稳定。代价是要自己维护服务器。
我的环境是 Ubuntu + Nginx,下面是完整步骤。
服务器端准备
(1)装 Nginx 和 Git:
1 | apt update && apt install -y nginx git |
(2)建两个目录——一个放裸仓库,一个放网站文件:
1 | mkdir -p /var/repo/blog.git |
(3)关键一步:在裸仓库里加一个 hooks/post-receive 钩子,让 Git 收到推送后自动把内容同步到网站目录:
1 |
|
给它执行权限:
1 | chmod +x /var/repo/blog.git/hooks/post-receive |
这行命令的意思是:把 master 分支的内容强制检出到 /var/www/blog。每次推送,网站目录就自动更新了,不需要你手动上传文件。
(4)配置 Nginx,把站点根目录指向 /var/www/blog:
1 | server { |
(5)重载 Nginx:
1 | nginx -t && systemctl reload nginx |
本地配置
改 _config.yml 的部署设置:
1 | deploy: |
然后 hexo deploy 就会推送到服务器。
免密推送
每次部署都输密码很烦,配一下 SSH 免密:
1 | # 本地生成密钥(已有的话跳过) |
之后 hexo deploy 就不用输密码了。
HTTPS
用 Certbot 申请免费证书最省事:
1 | apt install -y certbot python3-certbot-nginx |
它会自动改 Nginx 配置并设置证书自动续期。
6.3 方案 C:Cloudflare Pages / Vercel(免费,自动构建)
把博客源码推到 GitHub,然后在 Cloudflare Pages 里连上这个仓库,每次推送它自动编译部署。适合不想在自己电脑上存编译产物的人。
缺点:构建过程你看不到细节,出问题不好排查;国内访问速度一般。
6.4 三种方案怎么选
| GitHub Pages | 自己的服务器 | Cloudflare Pages | |
|---|---|---|---|
| 费用 | 免费 | 服务器+域名费用 | 免费 |
| 国内速度 | 一般 | 取决于服务器线路 | 一般 |
| 自定义程度 | 低 | 完全自主 | 中 |
| 维护成本 | 几乎为零 | 要自己维护 | 极低 |
| 绑定域名 | 要额外配置 | 直接配 | 支持 |
| 适合谁 | 只想写文章 | 想完全掌控 | 不想碰服务器 |
我的选择是方案 B,主要图两点:一是访问速度可控(服务器线路自己挑),二是这套流程本身有学习价值——配下来会顺带搞明白 Git hook、Nginx、SSH、HTTPS 是怎么回事。
7 部署脚本
每次都要敲三四条命令挺烦的,写个脚本一次搞定。Windows 下用批处理:
1 | @echo off |
存成 deploy.bat,以后双击就行。
不过光看部署命令不报错,不代表真的推上去了。SSH 偶发超时、远端仓库有问题,都可能让部署静默失败。所以更稳妥的做法是在部署后加一步验证:
1 | @echo off |
返回 200 才算成功。这个博客的部署脚本就是按这个思路写的,还会顺带检查站内失效链接。
8 进阶:几个值得做的事
① 站内搜索。 Hexo 有 hexo-generator-searchdb 之类的插件,生成一个 JSON 索引,前端搜索。Stellar 主题内置了支持。
② 图片优化。 原始截图动辄几 MB,直接放上去会让页面很慢。建议统一压成 WebP,长边控制在 1920 以内。我写了个脚本批量处理——这一步对加载速度的影响比任何前端优化都大。
③ 失效链接检查。 文章一多,改了文件名、删了图片,就会出现死链。写个脚本在部署前扫一遍 HTML 里的站内链接,能避免上线后才发现。
④ 备份。 博客源码要备份。最省事的做法是把整个目录(除了 node_modules 和 public)放进一个 Git 仓库,推到私有仓库里。
⑤ 统计。 想知道哪些文章有人看,可以接 Google Analytics、Umami、或者自建统计。不喜欢被追踪的话,用 Nginx 日志自己分析也行。
9 几个踩过的坑
① 改了配置不生效。 Hexo 会缓存编译结果,改完配置先 hexo clean 再 hexo generate。
② 图片不显示。 检查路径写法。放在 source/assets/ 下的图片,引用路径是 /assets/...(对应网站根目录),不要写成相对路径。文章可能在首页、归档页、标签页等多个位置渲染,相对路径很容易失效。
③ 部署成功但网站没变。 先按 Ctrl+Shift+R 强制刷新(可能是浏览器缓存);还没变就检查是不是推到了别的分支;再不行就登服务器看 /var/www/blog 里文件的时间戳。
④ 主题升级后功能坏了。 如果你改过主题源码,升级会全部覆盖。记住自己改了哪些文件——这是我踩过最深的坑。
⑤ 中文文件名或路径报错。 尽量全部用英文命名目录和脚本文件。有些工具链对中文路径的编码处理不可靠。尤其是 .bat 文件——cmd 按代码页解析批处理,里面的中文注释会被切分误读,导致莫名其妙的语法错误。
⑥ 部署时 SSH 偶发失败。 Could not read from remote repository 这类错误,多半是网络抖动。在脚本里加自动重试(等 30 秒重试,最多试三次)能省很多心。
⑦ 服务器磁盘被日志撑满。 Nginx 的 access log 长期不清理能涨到几个 GB。配一下 logrotate,或者定期清理。
10 值不值得
如果你只想写文章、不想碰技术,用现成的平台(知乎、语雀、Notion)效率更高。
但如果你想完全掌控自己的内容——排版、域名、数据、以后能不能导出——那静态博客是很好的选择。搭一次花一个周末,之后就是纯粹的写作。
而且这个过程本身有收获:你会顺带搞明白 Git、命令行、Nginx、DNS、HTTPS 这些东西是怎么回事。这些东西学一次,以后到处都用得上。