先把结论说清楚:10分钟搭一个能真正上线的个人博客,在今天完全不是噱头。你不需要租服务器、不需要懂数据库、也不需要熟悉什么高深的网络协议。要准备的东西只有三样——一台电脑、一个 Git 环境、一个 GitHub 账号。这篇文章就把我常用的这套“静态博客最小工作流”完整拆开给你看:为什么这么搭、每一步在做什么、上线之后会遇到哪些坑,一次讲清楚。
我见过不少人卡在第一步,不是不会写文章,而是被眼花缭乱的选型劝退了:WordPress 要买服务器、Notion 建站要考虑二次发布、各种框架各有各的学习成本。折腾一个月,域名还是空的。其实对一个以“写”为主的个人博客来说,工具链越简单越好,最好简单到让“发布”这个动作变成一种肌肉记忆。下面这套流程,是我用了三年的方案,稳定、免费、可控,换电脑也不影响继续写。
1. 先定路线:为什么静态博客是个人写作者的合适起点
1.1 静态站点和动态站点的核心差异
个人博客的发展方向大致分两类:动态站和静态站。
动态站以 WordPress 为代表,文章内容存在数据库里,每次有人访问,服务器要实时拼接页面再返回。优点是后台界面友好,鼠标点一点就能写文章;缺点也很明显,你需要一台长期运行的服务器,还要维护 PHP 环境、数据库、插件更新,稍不注意就会被扫描工具盯上,各种安全补丁让人疲于奔命。说实话,绝大多数个人博客根本用不上这种级别的系统,却得承受它的全部维护成本。
静态站则完全换了一种思路。文章平时就是本地的一个个 Markdown 文件,写完后用构建工具渲染成纯 HTML、CSS、JS,再推到托管平台对外提供访问。整个过程没有数据库,也没有后台,别人访问到的是一堆已经生成好的文件,加载速度自然快,而且几乎不用做安全防护。
对只想安静写点东西的人来说,静态站显然是更省心的路线。你需要做的只是在本地写作,然后执行一次发布命令,剩下的都由工具链自动完成。
1.2 主流静态框架怎么选到适合你的
静态站生成器有很多,常见的包括 Hugo、Hexo、Astro。我直接给一个对比表格,方便你从自己的情况出发对号入座。
| 框架 | 语言 | 构建速度 | 上手成本 | 适合谁 |
|---|---|---|---|---|
| Hugo | Go | 极快,数千篇文章秒级构建 | 低,单个可执行文件即可运行 | 想最快上线、专注写作的人 |
| Hexo | Node.js | 中等 | 中等,依赖 Node 生态 | 熟悉前端工具链、喜欢老牌生态的用户 |
| Astro | Node.js | 中等 | 偏高,可自由组合组件 | 前端开发者,愿意折腾页面细节的人 |
我最终选择 Hugo,原因是几个维度综合下来它最接近“工具隐形”的目标:
第一,安装包是一个独立的二进制文件,不依赖任何运行时环境,解压即用。第二,构建速度非常快,哪怕博客写到上千篇,发布也是瞬间完成。第三,PaperMod 这类成熟主题已经把站点地图、RSS 订阅、归档、搜索这些基础能力内置好了,你不需要自己从零写前端。
Hexo 也很好,但 Node 生态的依赖链相对重,尤其是升级 Node 版本后偶尔会遇到包兼容问题。Astro 更适合把博客当成前端练手项目的人,如果目标是快速稳定输出,没必要在这上面花时间。
1.3 为什么“模板起步”比“从零搭建”更接近目标
很多人一上来就搜教程,试图从零理解静态站原理,这其实走偏了。写博客的长期价值在于“持续输出”,而不是“系统架构设计”。
Hugo 主题仓库里的 exampleSite(示例站点)本身就是一套完整的可运行博客,包含配置、文章模板、页面布局、归档逻辑。你要做的是把它复制过来,改掉站点名称、个人信息,然后开始写第一篇文章。这个复用的过程,正是把 10 分钟从口号变成现实的关键。等将来熟悉了,再逐步自定义外观也不迟。
2. 最小工具链:一条跑通的自动发布流水线
2.1 流水线的四个角色分别负责什么
一套最简单的静态博客发布链路,可以拆成四个环节:
- 本地写作端:用 Markdown 写文章,文本格式简单,未来可迁移性也最好。
- 构建工具(Hugo):把 Markdown 和主题模板合并,生成静态站点文件。
- 版本管理(Git):记录所有文件的每一次改动,让你可以随时回滚。
- 托管平台(GitHub Pages 或类似服务):存放最终站点文件,并向互联网提供访问。
它们的协作顺序很清晰:本地写文章、构建验证,然后 git 提交并推送,托管平台检测到推送后自动执行构建与更新。把这套链路跑通之后,以后每次发布新文章,你真正需要亲手敲的命令只有三条左右。
2.2 本地环境安装:macOS、Windows、Linux 的差异
安装 Hugo 和 Git 的第一步,我会直接在终端里处理。
以 macOS 为例,前提是装了 Homebrew,直接执行:
brew install hugo gitWindows 用户如果使用的是新版系统,可以用 winget:
winget install Hugo.Hugo.Extended Git.GitLinux 用户用对应发行版的包管理器,但要注意部分发行版源里的 Hugo 版本比较旧,建议优先从 Hugo 官网下载预编译的二进制文件,解压后放入 PATH 即可。
装完之后,在终端验证一下:
hugo version git --version能看到版本输出就说明环境没问题。这里提个醒,Hugo 有两个版本:普通版和 Extended(扩展版)。如果后面想使用依赖 Sass 的主题,需要 Extended 版本,所以稳妥起见直接装 Extended 就行。
2.3 托管端准备:GitHub 仓库和 Pages 设置
GitHub 账号注册好之后,需要新建一个仓库。这里有一个非常重要的建议:仓库名直接命名为“你的用户名.github.io”。比如你的用户名是zhangsan,仓库名就叫zhangsan.github.io。
这样命名的好处是,站点会被部署到https://zhangsan.github.io这个固定的根路径,不会带上奇怪的后缀路径,后续写图片路径和自定义域名都会省很多事。
仓库先创建为空仓库即可,不需要初始化 README。等到后续推送时再关联本地目录。
另一个常见选择是 Cloudflare Pages,它同样支持从 Git 仓库自动构建,且自带免费 CDN。操作逻辑和 GitHub Pages 很像。考虑到教程的通用性,下面以免费的 GitHub Pages 为主展开。
3. 实操开始:从空目录到线上博客
3.1 创建站点骨架并挂载主题
先在本地找一个合适的目录,比如~/workspace,然后执行:
hugo new site my-blog cd my-blog执行完hugo new site后,Hugo 会生成一个标准的站点骨架,包括content、layouts、static、config等目录。这时站点是空白的,需要引入主题。
以我现在使用的 PaperMod 主题为例,用 git submodule 的方式引入到主题目录:
git init git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod为什么用 submodule 而不是直接下载 ZIP 解压?因为 submodule 让主题目录和主仓库保持一个清晰的引用关系,后续想升级主题,只需要执行一条命令拉取最新代码即可。如果直接解压,主题文件会混进自己的 Git 仓库,升级时需要手动替换,比较麻烦。
3.2 用主题自带的示例配置快速起步
PaperMod 的仓库里有一个exampleSite目录,里面是一整套可以直接运行的示例博客。我们要做的是把它复制到自己的站点根目录。
cp -r themes/PaperMod/exampleSite/* .Windows 用户不用纠结cp命令,直接打开文件管理器,把示例目录里的文件复制过来也是一样的效果。复制完成后,站点根目录下会出现config、content、assets等文件夹,这些就是模板自带的初始内容。
这里要特别留意旧版本的默认配置。如果你执行hugo new site时生成的是hugo.toml,而 exampleSite 里同样有配置文件夹,需要把默认的hugo.toml删掉,否则两个配置同时存在,Hugo 可能读取到你不想要的那份。
PaperMod 的示例配置结构比较清晰,核心配置文件一般在config/_default/hugo.yaml或类似位置。打开它,重点修改这几个关键字段:
baseURL: "https://yourname.github.io/" title: "我的技术博客" theme: PaperMod params: description: "记录开发学习中的思考与踩坑" ShowReadingTime: true ShowShareButtons: true ShowWordCount: truebaseURL必须改成你最终的站点地址,本地预览时影响不大,但线上部署后,站点地图和 RSS 都会依赖这个地址。title会显示在浏览器标签页和站点头部。params里的开关项控制文章阅读时长、分享按钮、字数统计等细节,按个人喜好调整。
3.3 写第一篇文章的正确姿势
现在创建第一篇博客:
hugo new posts/hello-world.md这条命令会在content/posts/目录下生成一个 Markdown 文件,文件头部有一段 YAML 格式的 front matter,也就是文章的基本信息。把内容改成这样:
--- title: "你好,世界" description: "我发布的第一篇文章" date: 2025-01-01T10:00:00+08:00 draft: false tags: ["博客"] ---注意两个关键点:
第一,draft: true一定要改成false。这是新手最容易踩的坑。Hugo 的约定是,草稿状态的文章在正式构建时会被直接跳过,本地预览用-D参数才会显示。很多人在本地能看到文章,push 到线上后却消失不见,多半就是忘了这一步。
第二,date建议用当前时间。Hugo 默认不会构建“发布时间在未来”的文章。如果你把日期填成几天后,这篇文章在当天之前都不会出现在线上。虽然可以用--buildFuture强行构建,但更好的做法是养成良好的日期填写习惯。
接着在分隔线下面写正文,Markdown 语法和常见的写作平台类似:
## 我为什么要写博客 这是搭好个人博客后的第一篇文章。 写博客的过程,本质上是把零散的想法整理成完整表达的过程。然后在终端启动本地预览服务:
hugo server -D浏览器访问http://localhost:1313,你应该能看到一个已经可以正常浏览的站点。到这一步,本地的部分已经全部完成。
3.4 推送到 GitHub 并让 Actions 自动部署
本地内容就绪后,下一步是推到 GitHub 仓库。依次执行:
git checkout -b main git add . git commit -m "feat: 初始化博客" git remote add origin https://github.com/你的用户名/你的用户名.github.io.git git push -u origin main推送完成后,还需要添加一个 GitHub Actions 工作流文件,让平台在每次接收推送时自动执行 Hugo 构建并发布。在项目根目录创建.github/workflows/hugo.yml,内容如下:
name: Deploy Hugo site to Pages on: push: branches: ["main"] workflow_dispatch: permissions: contents: read pages: write id-token: write concurrency: group: "pages" cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: hugo-version: '0.140.0' extended: true - name: Build run: hugo --minify - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: ./public deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4这个文件的逻辑是:每当有代码推送到main分支,就自动在 GitHub 的云端环境中安装 Hugo、执行构建、把生成的public目录打包并部署到 Pages 服务。这里面有一个细节,checkout时必须带上submodules: recursive,因为主题是通过 submodule 引入的,如果漏掉这一步,线上构建时找不到主题,博客会显示为空白。
保存文件后再次提交并推送:
git add . git commit -m "ci: 添加自动部署工作流" git push然后进入 GitHub 仓库的 Settings → Pages,在 Source(发布源)里选择GitHub Actions。一切设置好后,Actions 标签页会开始执行工作流,等进度条跑完,直接访问https://你的用户名.github.io,就是你的博客了。
3.5 10分钟的时间是如何分配的
看到这里,你可能会觉得步骤还是不少。我按实际用时拆解一下,并说明哪些环节会波动:
| 环节 | 预估用时 | 说明 |
|---|---|---|
| 安装 Hugo 和 Git | 1~2 分钟 | 如果环境已装好,几乎为 0 |
| 新建站点并引入主题 | 1 分钟 | 主要是等待 git submodule 下载 |
| 修改配置 | 2 分钟 | 改 baseURL、title、站点描述 |
| 写第一篇文章 | 2 分钟 | 不用长,一句“你好,世界”也算 |
| 创建仓库并推送 | 2 分钟 | 需要提前建好 GitHub 仓库 |
| 开启 Pages 并等待部署 | 1~2 分钟 | Actions 自动完成,此时可以喝水 |
总计确实在 10 分钟左右,前提是环境安装预先完成、网络正常。第一次操作因为要理解每一步在做什么,多花几倍时间很正常,但第二周再发新文章时,整个流程会缩短到 3 分钟以内。
4. 最容易翻车的四个环节与排查顺序
工具链越简单,出问题时反而越需要清晰的排查思路。下面这四类问题,是博客群里最常见的求助主题。
4.1 推上去之后访问 404
现象是 Actions 执行成功了,页面地址也给出来了,但打开是 404。按顺序排查:
第一,确认仓库名是否严格等于“用户名.github.io”。如果不是,站点实际地址会带上仓库名作为子路径,比如用户名.github.io/my-repo/。这时baseURL也要相应修改。
第二,确认baseURL是否和你访问的地址完全一致。少了https://,或者多了一个斜杠,站点内部的 CSS、链接就可能拿不到正确地址。
第三,检查 Pages 设置里的发布源。如果没选 GitHub Actions,而是默认的分支发布,它会在仓库里找已经生成好的静态文件,我们的仓库里没有,自然就 404 了。
第四,看 Actions 构建日志,确认hugo命令执行成功且public目录有产物。日志里只要出现Error或Failed,先从这里找原因。
4.2 本地正常,线上却迟迟不更新
这个问题的出现频率极高,原因通常不是部署没执行,而是文章并没有被构建进来。
最常见的是开头提到的draft: true。本地预览时启动命令可能带了-D,它能显示草稿文章,但正式构建不会。解决办法很简单:把 front matter 里的draft改成false,重新推送。
还有一个隐蔽的原因:date字段写成了未来时间。Hugo 把“未来文章”排除在默认构建范围之外。我见过有人为了补前几天的空档,故意把日期写成昨天,结果写成了明天,文章死活不出来。
如果这两个都没问题,那大概率是浏览器缓存或者托管平台的缓存延迟。强制刷新页面(Windows 下 Ctrl+F5,macOS 下 Cmd+Shift+R),再等一两分钟再访问,基本都能解决。
4.3 文章排版变形与代码高亮消失
文章正常显示了,但排版和预期不一样,常见原因有三个。
一是 front matter 格式写错。YAML 对缩进和冒号非常敏感,比如tags: ["博客",“随笔”]这种中英文符号混用的写法,会导致 Hugo 无法正确解析整个文章信息。
二是代码块的标记语言写错或漏写。Markdown 中代码块应当用三个反引号包裹,并在第一行写明语言类型:
```js console.log("hello world"); ```如果漏掉语言标记,Hugo 不知道用什么插件做高亮,代码块就会变成普通文本,主题自带的代码高亮自然失效。
三是列表和段落的缩进问题。Markdown 里嵌套列表要求子项缩进四个空格或一个 Tab,若缩进不统一,浏览器会把它解析成普通段落,视觉上就会错乱。写完后在本地预览页扫一眼,这些问题当场就能发现。
4.4 图片就是显示不出来
图片报错通常有两种表现:本地正常,线上打不开;或者本地和线上都打不开。
本地和线上都打不开,说明图片路径本身就写错了。Hugo 项目中,图片最常见的位置是static/images目录,Markdown 里引用时写成:
static目录里的文件会被原样复制到站点根目录,因此/images/example.png可以正常访问。
更好的做法是使用页面级资源,也就是把文章变成一个目录。创建文章时不用hugo new posts/my-post.md,而是:
hugo new posts/my-post/index.md然后把图片放在my-post/目录里,Markdown 中写成相对路径:
这样图片和文章始终绑定在一起,移动文章目录时不会出现图片失联。
如果本地能显示、线上打不开,优先检查baseURL是否设置正确,以及图片文件名是否存在大小写全角字符的问题。hugo 生成的站点对路径大小写是敏感的,这在 macOS 本地可能不报错,但线上 Linux 环境会严格区分。
5. 上线之后,把博客变成长期习惯
5.1 建立一套稳定的发布流程
博客搭建只是起点,让更新成为习惯才是真正有价值的部分。我的日常发布流程已经固定成这几步:
hugo new posts/2025-01-01-title.md # 编辑文章,关闭 draft hugo server -D # 本地预览 git add . git commit -m "post: 新文章标题" git push时间一长,动作就完全内化了。还有一个小技巧:Git 本身就替你保存了每一次修改的历史,如果某篇文章改了又改,不用担心写坏了,随时可以从 commit 历史里找回旧版本。
内容结构上,建议从第一天就按主题划分目录,比如posts/技术、posts/随笔、posts/读书笔记。虽然 Hugo 支持用标签和分类管理文章,但目录结构越清晰,后续批量调整越轻松。
5.2 用零成本方案补齐评论、统计、搜索
静态站没有后台,但不代表不能有评论、统计和搜索。三个轻量方案可以直接抄作业:
- 评论系统:giscus。它基于 GitHub Discussions,访客用 GitHub 账号登录后就能留言。评论内容存放在仓库的 Discussions 区域,不需要你自己维护数据库。
- 访问统计:GoatCounter或Cloudflare Web Analytics。GoatCounter 主打隐私友好,简单到只需要往模板里塞一段统计代码;Cloudflare 的分析则不需要在页面上引入 JavaScript,登录 Cloudflare 控制台就能看数据。
- 站内搜索:Fuse.js配合给文章生成 JSON 索引文件,前端在本地做模糊匹配。Hugo 社区有人专门做了这种搜索组件,改造成了 PaperMod 主题的一部分,你也可以通过主题配置开启。
这些功能都属于“锦上添花”,完全可以在博客稳定更新一个月后再考虑加装。
5.3 绑定自定义域名与 HTTPS
如果手头有域名,让博客用上自己的域名并不复杂。基本思路是:在仓库设置里的 Pages 配置中,填入自定义域名,然后在域名服务商那边把记录解析到你的用户名.github.io即可。
具体来说,根域名可以添加一条 A 记录,指向 GitHub Pages 的服务器 IP;子域名(比如blog.example.com)则用 CNAME 记录解析到你的用户名.github.io。配置完成后,仓库会自动生成一个CNAME文件,里面写着你的自定义域名。之后在 Pages 设置里开启“Enforce HTTPS”,等待证书自动签发。
这里有一个容易踩的坑:CNAME 文件内容只能保留一个域名,如果你在 Pages 设置里填了blog.example.com,又在本地手动创建了一个 CNAME 写着example.com,下次部署时就会互相覆盖,导致域名绑定失效。
最后说点我自己的体会。这套流程我用了三年,中间换过主题、换过托管、换过构建脚本,唯一没换的就是“本地 Markdown + Git 推送 + 自动部署”这条主线。它的好处是,哪怕换一台电脑,只要 clone 一下仓库,所有文章都还在,写作状态不会因为环境变化而中断。
搭建博客真正难的地方从来不是工具,而是能不能在第一周内连续写出三篇自己真正想表达的内容。所以别再纠结主题和功能了,先把第一篇文章发出来,不管长短。页面只要有字,你的博客就已经开始了。