用Jekyll和GitHub Pages搭建个人博客:零成本、零维护的静态博客方案
2026/9/17 7:08:06 网站建设 项目流程

如果你正在纠结怎么搭一个自己的博客,又不想花钱买服务器、不想折腾数据库、不想天天担心安全问题,那 Jekyll 加 GitHub Pages 这套组合,应该是你能找到的最省心的方案之一。我自己的博客就是用这套东西跑起来的,从第一次提交到正式能访问,前后也就一个下午的时间。这篇内容我会把整个流程、关键配置、踩过的坑全部摊开讲,包括很多人纠结的“Jekyll 和 Hexo 到底选哪个”这个问题,也会给出我的判断。

这篇内容适合两类人:一类是完全没接触过静态博客的小白,想低成本拥有一个个人站点;另一类是已经用 Hexo 或其他工具搭过博客,但对 Jekyll 和 GitHub Pages 这套原生方案感兴趣、想迁移或对比的人。我会从环境准备讲到域名绑定,全程带命令和配置示例,你照着做基本就能跑起来。

1. 内容整体设计与思路拆解

1.1 我对个人博客的基本判断:从需求反推方案

在动手之前,先想清楚一个问题:你要的博客,到底是给谁看的,要承担什么功能?

如果只是想要一个写技术笔记、生活记录、作品展示的站点,那它的核心需求其实只有三个:能写内容、能发布、能长期稳定访问。剩下的什么评论系统、访问统计、搜索、标签分类,都属于锦上添花,早期完全可以不装。

按照这个需求去反推方案,你会发现很多传统建站方式的性价比很低。买一台云服务器,你得配置 Nginx、装数据库、处理 HTTPS 证书、定期打系统补丁,万一被攻击还得收拾烂摊子。用动态博客框架比如 WordPress,功能确实强大,但维护成本也跟着上来了。这些对一个小博客来说,都属于过度投资。

静态博客方案的优势恰好在这里。它把内容预渲染成纯 HTML 文件,发布的时候直接把文件丢到 CDN 上,不需要服务端动态执行代码。GitHub Pages 本身就是干这个的,它免费托管静态页面,还自带 HTTPS,全球访问速度也还不错。你唯一要做的,就是本地用 Jekyll 把 Markdown 文章渲染成 HTML,然后推送到 GitHub 仓库,剩下的构建和发布全自动完成。

1.2 零成本与长期维护,才是最关键的隐藏成本

很多人搭博客的时候只看“搭建当天”的成本,忽略了“运行三年”的成本。服务器续费一年几百块,域名续费一年几十块,看起来都不贵,但真正贵的是时间:系统出问题了你要排查,被攻击了你要处理,证书过期了你要续。这些小事情单看不难,积累起来非常消磨写作热情。

Jekyll 加 GitHub Pages 这套方案,长期维护成本趋近于零。GitHub 免费托管,HTTPS 自动配好,不用担心流量攻击,就算我这篇文章发了三五年,只要 GitHub 这个平台还在,它就还在跑。我自己博客运行这几年,真正花在“维护”上的时间加起来不会超过一天,大部分精力都可以放在写内容本身。

另外还有一个容易忽略的优势:内容可控。Jekyll 的文章就是纯 Markdown 文件,不依赖数据库。哪怕哪一天 GitHub Pages 不用了,我也可以把这些文件原封不动搬到任何其他静态托管平台,五分钟迁移完毕。这种“数据在自己手里”的安全感,用久了才知道多重要。

2. jekyll和hexo到底怎么选

2.1 两个工具的家底和脾气

Jekyll 和 Hexo 是目前最主流的两个静态博客生成器,网上关于“jekyll和hexo哪个好”的讨论从来没停过。先别急着站队,看清楚它们的底细再下结论。

Jekyll 是 Ruby 社区的作品,GitHub 的创始人 Tom Preston-Werner 写的,2013 年就被 GitHub Pages 官方支持。它的核心卖点和 GitHub 深度绑定,你推一个 Markdown 文件上去,GitHub 自动帮你构建发布,整个过程不需要额外配置。

Hexo 是 Node.js 生态的工具,国内社区非常活跃。它的特点是速度快、主题风格更现代,而且因为中文资料多、文档也友好,很多国内开发者第一次搭博客用的就是它。Hexo 通常配合 Travis CI 或者 GitHub Actions 做自动部署,本地生成静态文件后推送到仓库的 gh-pages 分支。

两个工具都能完成“写文章、生成静态页面、托管到 GitHub Pages”这个核心链路,风格差异大于能力差异。就像做同一道菜,一个用的是砂锅,一个用的是铁锅,最后的味道各有千秋,但都能吃饱。

2.2 我最终选Jekyll的三个理由

我第一次搭博客的时候,其实也纠结过这个问题。当时我花了一个晚上,分别用 Jekyll 和 Hexo 搭了两个demo,最后选了 Jekyll,核心原因有三个。

第一,GitHub Pages 原生支持 Jekyll,不需要额外的 CI 流程。用 Hexo 的话,本地生成 public 目录之后还得推送到专门的分支,或者配置 GitHub Actions 来实现自动化;用 Jekyll 加 GitHub Pages,我只需要把源文件推到主分支,平台自动完成构建。少一个环节,就少一个出错的地方。

第二,Jekyll 的模板语言 Liquid 虽然上手有点门槛,但它的数据文件机制很适合博客这种内容结构相对固定的场景。后面想加个相册页、读书清单页,直接用 YAML 数据文件就能实现,不需要额外开发。

第三,Hexo 换主题的时候经常要关注 Node 版本兼容问题,node_modules 一换版本就容易出幺蛾子;Jekyll 的主题是基于 gem 的,版本锁定相对简单,很少遇到依赖地狱。

2.3 什么情况下你应该考虑Hexo

不能说 Jekyll 一定比 Hexo 好,每个工具都有适合它的场景。如果你是前端开发者,日常就是跟 Node.js 打交道,那 Hexo 的学习成本对你来说几乎为零,ejs 模板你本来就会写,主题二次开发更顺手。

如果你对博客的颜值要求特别高,喜欢那种卡片式、瀑布流式的现代风格主题,Hexo 的主题生态在这方面确实更丰富。我用过一段时间 Hexo 的 Next 主题,颜值和交互手感都很棒,这一点 Jekyll 的主题相对朴素一些。

我的建议很简单:你在哪个技术生态里待得久,就选哪个。不要因为单纯比较性能参数而倒向某一方,毕竟博客的瓶颈从来不在生成速度上。如果你完全是个新手,哪个都不想深入了解,那就直接选 Jekyll,因为它的部署链路最短,碰到问题的概率最少。

3. 环境准备与本地搭建

3.1 先把Ruby环境装明白

Jekyll 是 Ruby 写的,所以第一步是装 Ruby。不同系统的安装方式不太一样,我把自己试过的整理一下。

macOS 用户要注意,系统自带的 Ruby 版本往往偏旧,而且直接往系统环境里装 gem 容易碰权限问题,不建议动系统 Ruby。最简单的方式是用 Homebrew 安装一个独立的 Ruby:

brew install ruby

安装完成后,需要把路径配置好。在~/.zshrc里加上这句:

export PATH="/opt/homebrew/opt/ruby/bin:$PATH"

然后执行source ~/.zshrc让它生效,再用ruby -v验证一下。如果版本号是新装的那个,就没问题了。

Windows 用户建议直接用 RubyInstaller,记得要选带 DevKit 的那个版本。安装的时候勾选“Add Ruby executables to your PATH”,后面操作会省很多事情。装完 DevKit 之后还要在命令行里跑一次ridk install,选择安装 MSYS2 组件,这一步是让本地编译扩展工具时能正常工作,很多新手在这里卡住,其实只要把提示的选项都装上就行。

Linux 用户直接走 apt 或者 yum 安装ruby-fullbuild-essential即可,版本一般不会太新但也够用。

装好 Ruby 之后,把 Jekyll 和 Bundler 一起装上:

gem install jekyll bundler

Bundler 是 Ruby 的依赖管理工具,它的作用类似于 Node 生态里的 npm。后面管理 Jekyll 的插件和主题都靠它,这一步建议务必装好。

3.2 创建第一个Jekyll站点

环境就绪之后,直接用 Jekyll 自带的命令创建新站点:

jekyll new my-blog cd my-blog bundle exec jekyll serve

打开浏览器访问http://localhost:4000,看到默认的欢迎页面,你的第一个 Jekyll 站点就起来了。这里有两个值得说明的细节。

第一,bundle exec前缀不是可有可无的。它保证当前环境下运行的是 Gemfile 里锁定的版本,而不是系统全局装的版本,可以避免很多版本冲突问题。

第二,jekyll serve默认带文件监听功能,本地改完 Markdown 文件,刷新浏览器就能看到效果,不需要手动重启。这个开发体验非常舒服,也是我很喜欢的点。

3.3 目录结构与模板引擎速览

Jekyll 项目跑起来之后,你会看到这样一个目录结构:

my-blog/ ├── _config.yml ├── _drafts/ ├── _includes/ ├── _layouts/ ├── _posts/ ├── _sass/ ├── assets/ ├── Gemfile └── index.md

每个目录各司其职,我用自己的理解给你梳理一下:

  • _config.yml是全局配置文件,站点的标题、描述、URL、主题都在这里设置,是整个博客的中枢。
  • _posts是文章目录,文件名必须遵循年-月-日-标题.md的格式,这是 Jekyll 识别文章日期的关键。
  • _layouts是页面模板,默认有 home、page、post 三个基础模板,你可以理解为 HTML 骨架。
  • _includes是公共组件,比如页头、页脚、导航栏,方便复用。

文章头部那段被两条---包围的 YAML 区域叫 Front Matter,它定义文章的元信息,比如标题、日期、标签、分类:

--- layout: post title: "我的第一篇文章" date: 2024-01-01 12:00:00 +0800 categories: blog tags: [随笔] ---

Jekyll 底层的模板语言是 Liquid,它跟 Python 社区常用的 Jinja2 有点像,控制结构也是{% if %}{% for %}这种标记语法。设计模板的时候需要写一些逻辑,但大部分情况下你只需要改改样式,不需要从零写模板。

4. 关键配置与写文章流程

4.1 _config.yml:最容易踩的url和baseurl

很多人第一次把 Jekyll 站点推到 GitHub Pages 之后,发现样式全丢了、图片全裂了,绝大多数情况都是_config.yml里的urlbaseurl配置有问题。

简单解释一下这两个参数:url是你站点的完整域名,baseurl是站点部署在域名下的子路径。GitHub Pages 的项目站点访问地址是https://用户名.github.io/仓库名/,这时候baseurl必须设置为/仓库名;用户站点的访问地址是https://用户名.github.io/baseurl留空即可。

如果baseurl配置错误,写src="/assets/style.css"这种根路径引用就会指错位置,页面自然没有样式。正确做法是在模板里用{% raw %}{{ site.baseurl }}{% endraw %}拼路径,比如:

<link rel="stylesheet" href="{% raw %}{{ site.baseurl }}{% endraw %}/assets/style.css">

本地调试的时候,url可以先填http://localhost:4000,正式发布前再改成线上域名。我之前有一次忘了改,本地一切正常,一上线上所有文章里的链接全是 localhost,排查了半天才发现问题。

4.2 写文章的正确姿势:Front Matter与Markdown

Jekyll 写文章用的是 Markdown,这个大家基本都会。但初学者容易忽略的是 Front Matter,也就是文章开头那段 YAML 信息。没有 Front Matter 的 Markdown 文件,Jekyll 不会当做文章处理,也就不会被渲染成 HTML 页面。

最简的 Front Matter 只需要一个属性:

--- layout: post ---

但实际写作的时候,我建议把titledateauthortags都写上。这些信息可以用来做文章列表的分组和筛选,后面想做分类页、标签页的时候就不用回头补数据了。我的习惯是每篇文章至少带上tags,这比单纯的分类更灵活,一篇跨领域的文章可以打多个标签,检索的时候很方便。

写作还有一个容易被忽略的点:文件名里的日期是 Jekyll 识别文章发布时间的核心依据,Front Matter 里的date字段反而是辅助性的。所以你如果手动建文件,文件名一定要按2024-01-01-标题.md的格式写,否则文章不会出现在正确的时间轴上。

4.3 本地预览与内容调试

写文章的过程中,我习惯开着本地服务实时预览。jekyll serve--drafts参数可以预览草稿,草稿文件放在_drafts目录下,不会被正式发布:

bundle exec jekyll serve --drafts

这里有个小技巧:本地草稿里的图片路径,最好一律使用相对路径写,比如../assets/images/xxx.png,而不是写死http://localhost:4000/assets/xxx.png。否则文章发布到线上之后,图片链接还是指向本地地址,全部会裂。我自己吃过这个亏,后来就把所有图片引用全部改成相对路径,一劳永逸。

本地预览还有一个作用,就是提前暴露 Markdown 渲染问题。Jekyll 默认用 Kramdown 做 Markdown 解析,它和 Typora 这类编辑器渲染出来的效果会有细微差别。例如,Kramdown 的 Markdown 内就不支持某些原始 HTML 标签的嵌套解析,如果你文章里嵌了不少花式 HTML,本地预览一步能帮你提前发现,省得线上出问题再改。

4.4 换主题:远程主题与本地主题

Jekyll 默认主题叫 Minima,结构干净但确实寡淡。想换主题,有两条路。

路由一:远程主题。GitHub Pages 支持jekyll-remote-theme插件,可以在_config.yml里直接指定一个 GitHub 仓库作为主题来源:

remote_theme: username/repo-name

用远程主题的好处是主题和你的文章分离,主题更新了直接在 GitHub 仓库releases里跟踪。不过也有局限,GitHub Pages 只允许白名单内的插件,主题里如果引入了白名单之外的插件,构建会直接失败。

路由二:本地主题。把主题的源文件整体下载到自己的仓库,放在_layouts_includesassets这些目录里,相当于完全接管了主题的代码。这样做的好处是任何效果都能自己改,坏处是主题官方更新的时候,你自己改过的文件会有冲突,合并起来费劲。

对于大多数人,我的建议是先玩远程主题,等确认某个主题自己确实要长期用了,再把它的自定义修改固定下来。我自己现在用的是远程主题加上两三个自定义布局文件,既保证主体功能跟着上游走,又能在局部作出自己的风格。

5. 一键发布到GitHub Pages

5.1 创建仓库与分支策略

到这一步,本地博客已经能跑了,接下来就是把内容搬到线上。先去 GitHub 新建一个仓库,名字有个讲究:如果你想拥有的是https://用户名.github.io这样的用户站地址,仓库名必须精确地叫<用户名>.github.io;如果名字起别的,比如my-blog,那最终地址会变成https://用户名.github.io/my-blog,也就是项目站点。

这两种方式我都试过。用户站点的地址干净好记,适合当个人主页用;项目站点的好处是一个账号下面可以挂多个不同的项目页。如果你只是想有一个个人博客,直接用用户站点方式最省事。

仓库建好之后,我习惯把主分支名称设置成main,因为 GitHub Pages 构建的默认分支一般就是它。分支策略上,源文件和构建产物不需要分家,因为 GitHub Pages 自己会读 Jekyll 源文件来构建,这也正是 Jekyll 方案最省心的地方。

5.2 让GitHub Pages自动构建

仓库建好之后,把本地内容推上去:

git init git add . git commit -m "first commit" git branch -M main git remote add origin https://github.com/你的用户名/你的仓库名.git git push -u origin main

推送完成后,到仓库的 Settings 页面找到 Pages 选项,在 Source 里选择 "Deploy from a branch",分支选main,目录选/ (root),保存即可。

保存后等一两分钟,GitHub Actions 会自动触发构建。你可以在仓库的 Actions 标签页看到构建日志,等状态变成绿色,访问https://你的用户名.github.io,你的博客就在线了。

这里有个我踩过的坑:GitHub Pages 构建 Jekyll 所用的版本和插件列表,跟本地环境不一定完全一致。所以本地能用,不代表线上就能构建成功。要避免这个问题,最稳妥的方式是本地也使用 GitHub 提供的github-pagesgem 来管理依赖。在你的 Gemfile 里改成这样:

source "https://rubygems.org" gem "github-pages", group: :jekyll_plugins

改完之后本地执行bundle install,这样本地用的就是和线上完全一致的 Jekyll 环境。这个细节能帮你省去九成以上的线上构建问题。

5.3 绑定自定义域名

GitHub Pages 默认的域名是用户名.github.io,如果你有自己的域名,可以在 GitHub Pages 设置页面里填入域名,GitHub 会自动帮你配置 HTTPS。绑定的步骤我拆开讲一下。

首先在域名服务商那边增加一条 CNAME 记录,把www指向用户名.github.io。如果你想让根域名比如example.com也能访问,还需要在 DNS 解析里加 A 记录,指向 GitHub Pages 的 IP 地址。GitHub 官网文档里给出的 IP 是185.199.108.153185.199.109.153185.199.110.153185.199.111.153,不同地区的访问建议配置多条 A 记录。

CNAME 记录配置完之后,还有一步容易被忽略:在 Jekyll 项目的根目录下放一个名为CNAME的文件,里面写你的域名,比如example.com。这个文件会跟着仓库一起提交,确保以后重新配置或者构建的时候域名不会丢。

HTTPS 证书是 GitHub 自动签发的,配置好域名之后等一段时间,Settings 页面里会显示 "Enforce HTTPS" 的选项,把那个按钮打开,整个站点就全程走加密连接了。我自己在绑定域名的时候遇到过一个情况,DNS 配置好了但一直显示证书颁发中,等了几个小时才生效。如果遇到类似情况不要急,过段时间再看,一般都会自动完成。

6. 进阶功能与维护技巧

6.1 评论系统:选配的开源方案

博客要跟读者互动,评论系统是绕不开的话题。Jekyll 是纯静态页面,没有服务端能力,所以要借助第三方评论服务。我推荐 giscus,它是基于 GitHub Discussions 的评论系统——评论内容会存到你的 GitHub 仓库的 Discussions 里,数据完全掌控在自己手上。

接入 giscus 的流程很直接:先到 GitHub 的仓库 Settings 里开启 Discussions 功能,然后到 giscus 官网按提示填仓库名,生成一段嵌入脚本,放到_includes目录下的评论组件里,在文章页模板中引入即可。

相比其他闭源评论服务,giscus 最大的优势是数据不属于某个第三方平台,你的读者留言都沉淀在 GitHub 上,哪天想迁移或者导出都很方便,不用看任何服务商的脸色。

6.2 访问统计:不牺牲隐私的轻量方案

静态博客无法直接统计访问量,但可以用轻量的脚本统计服务。我在用的方案是 GoatCounter,它对个人网站免费开放,一个简单的 JavaScript 片段就能接入。它不依赖 Cookie,隐私政策上可以写得很干净,访客也不会被无感追踪。

如果你不喜欢把数据放在别人那,也可以用 Umami 自托管,缺点是得有台云服务器,这就违背了“零维护”的初衷。所以我最终选了 GoatCounter,数据量虽然不大,但能看到每天的访问趋势、来源渠道、热门文章,够用了。

6.3 搜索与SEO:最容易被忽视的体验

静态博客没有后端数据库,站内搜索想实现得花点心思。如果你文章量不大,最简单的方式是直接用浏览器的 Ctrl+F 当前页搜索,再加一个支持站内搜索的第三方搜索服务。Jekyll 生态里也有基于 Lunr.js 的本地搜索方案,文章量在几百篇以内都能流畅运行,原理是启动时生成一份全部文本的 JSON 索引,前端搜索时本地匹配,无服务器依赖、无请求费用,值得一试。

SEO方面,Jekyll 先天就做得不错。Markdown 渲染出的 HTML 是语义化的,标题层级默认整齐,网站地图sitemap.xml可以用插件自动生成,Robots.txt 也可以手动维护。基础的 SEO 在 Jekyll 里不用刻意折腾,重点放在标题和 meta 描述上就好。

6.4 自动化发布:写内容就能上线

用 Jekyll 加 GitHub Pages 的完整工作流最简单的一种就是——直接在 GitHub 网页端点击 “Add file” 创建带正确文件名的 Markdown 文件,推送后 GitHub 自动构建,两分钟文章上线。如果平时用本地写作,git addgit commitgit push三条命令打完收工。

我自己的习惯是本地用 VS Code 写 Markdown,配合 Markdown 预览插件;写完推送到仓库后,GitHub Actions 自动构建,几分钟内就能在线上看到新文章。整套流程不依赖任何第三方工具,装好环境之后几乎不费心。

7. 常见问题与排查记录

7.1 GitHub Pages构建失败的常见原因

远程构建失败是新手最容易遇到的问题,大多数情况都不是代码写错,而是环境版本问题。我遇到过的典型场景如下表:

现象原因解决方案
Actions 日志提示You have already activated...本地 gem 版本与线上不一致,远程构建时依赖冲突本地 Gemfile 换成github-pagesgem,重新bundle install
构建日志提示插件不存在用到非白名单插件,远程环境不允许安装改用法白名单支持的插件或换实现方案
文章列表为空文件名日期格式不对,或 Front Matter 缺失检查_posts文件名是否严格为2024-01-01-标题.md
页面样式丢失baseurl配置错误,静态资源路径拼错修正_config.ymlurlbaseurl,模板中统一用site.baseurl拼接资源路径

排查的核心思路,是把线上构建日志当作第一个信息来源。Actions 页面里如果构建红了你先把日志从头到尾看一遍,大多数错误信息都是人话,定位会比瞎猜快很多。

7.2 本地正常,线上样式全丢

这个问题我前面提到过,核心在baseurl。本地预览的时候,baseurl是空的,资源路径会指向http://localhost:4000/assets/...,浏览器能正常加载。发布到线上的项目站点后,资源地址变成了https://用户名.github.io/assets/...,但实际文件在https://用户名.github.io/仓库名/assets/...,路径不匹配,样式就全丢了。

解决方案就一句话:所有引用资源的地方都加上{% raw %}{{ site.baseurl }}{% endraw %}前缀。检查的时候重点看_includes里的<head>部分,_layouts里的页脚和导航,以及每篇文章里手写的图片链接。养成写绝对路径前先拼接site.baseurl的习惯,就不会再出现这个问题。

7.3 本地和线上效果不一致

另外一个让很多人抓狂的问题是本地预览和线上效果不一样。原因通常是本地 Jekyll 版本和 GitHub Pages 用的版本不同,导致 Markdown 渲染结果有差异,少数插件在本地能运行但线上不支持。

为了避免这种不一致,我强烈建议本地环境直接用github-pagesgem。Gemfile 里写上这一行:

gem "github-pages", group: :jekyll_plugins

然后重新bundle install。这样本地跑的 Jekyll 就和线上完全同版本了,本地什么样线上就是什么样,不存在“本地好好的,一上线就坏”的尴尬。

7.4 一套实用排查思路

如果你遇到本地构建正常但线上失败,先把线上 Actions 日志完整贴到搜索引擎或者 Jekyll 官方文档里去查,大部分错误都能找到现成解释。如果是样式问题,按 F12 打开浏览器开发者工具,看 Network 面板里的静态资源请求状态码,是 404 还是路径错误一目了然。

还有一个小建议:刚开始搭建的时候,尽量用默认主题跑通全流程,再考虑换主题、加插件。默认主题配置最少、坑最少,能最快让你把“本地写文章、推送发布、绑定域名”这条主链路走完。主链路顺畅了,再去折腾花活心里也有底。我自己第一次搭博客的时候,就是死磕主题细节,结果前面一路顺风最后却在配置上浪费了一个晚上。

写在最后的一点体会

从我自己的使用体验来看,Jekyll 搭配 GitHub Pages 这套方案最打动我的地方,不是它有多炫酷,而是它让我把注意力从“搞博客”转移到了“写博客”上。Markdown 记录想法,推送命令完成发布,没有后台要打理,没有数据库要维护,也没有账单要担忧。如果你也在找一个低成本、可长期维护、内容完全自主的个人博客方案,并且不需要纠结太多功能上的花活,那这套组合值得你花一个下午试试。过程中遇到环境问题、配置问题,记住一个原则:先跑通最简版本,再做加法,能帮你少走很多弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询