1. 项目概述:为什么我要重建我的GitHub Pages博客
几年前,我随手用Jekyll搭了个博客,扔在GitHub Pages上,想着能写点东西就行。那时候觉得,免费、省心、能绑定域名,还要啥自行车?确实,GitHub Pages这套组合拳——静态站点生成器加托管——对于技术分享、个人记录来说,初期简直完美。但随着时间推移,问题一个个冒出来了:访问速度时快时慢,尤其是在某些网络环境下;主题老旧,想改个样式发现当初选的主题文档不全,牵一发而动全身;更别提那些零散的插件和自定义配置,连我自己都快忘了当初是怎么拼凑起来的。每次想写新文章,都得先跟这个陈旧的系统“搏斗”一番,写作的热情被磨掉大半。
所以,“重建”这个念头不是一时兴起,而是一次彻底的“系统重装”。这次的目标很明确:在保留GitHub Pages核心优势(免费、与Git工作流无缝集成)的前提下,打造一个更快、更稳、更易维护的现代化静态博客。重建不是推倒重来那么简单,它涉及到生成器选型、部署优化、CDN加速、评论系统迁移等一系列环节。简单说,我想从一个“勉强能用”的状态,升级到一个“用得顺手,甚至有点享受”的状态。如果你也在用GitHub Pages,但总觉得哪里差了点意思,或者正准备从零开始搭建,那么我踩过的坑、总结的方案,或许能帮你省下不少折腾的时间。
2. 核心需求与方案选型:不止于“换个主题”
重建的第一步是明确需求。我列了个清单,问自己到底想要什么:
- 极致的访问速度与稳定性:全球访问都应该是快速的,且具备抗DDoS等基础安全能力。
- 高度的可维护性与可定制性:主题结构清晰,文档齐全,方便后续自定义样式和功能。
- 平滑的内容迁移:旧博客的文章(Markdown文件)必须能无损迁移,URL结构最好也能保持,这对SEO很重要。
- 完整的博客生态:评论、搜索、分析等周边功能需要易于集成。
- 未来的扩展性:能方便地集成自动化工作流,比如自动部署、资源优化等。
基于这些需求,我评估了几个主流方案:
2.1 静态站点生成器(SSG)选型:为什么最终还是Jekyll?
市面上SSG很多,Hugo、Hexo、Next.js、Gatsby都很火。Hugo以编译速度著称,Hexo生态丰富(尤其对中文用户),Next.js则代表了前沿的React框架。我为什么还是选了“老牌”的Jekyll?
- 原生集成与零配置:GitHub Pages对Jekyll的支持是“亲生儿子”级别的。你只需要把符合Jekyll目录结构的代码推送到
gh-pages分支或主分支的特定目录,GitHub会自动识别、构建并部署。这意味着你完全不需要在本地或云端配置构建环境,也无需关心依赖安装。对于追求简洁和“开箱即用”的场景,这是巨大的优势。其他生成器大多需要配置GitHub Actions来实现自动构建,多了一个环节,就多了一份出错的概率。 - 内容迁移成本最低:我的旧博客就是Jekyll的,文章都是Markdown文件,Front Matter(文章头部的YAML配置)格式通用。迁移到另一个Jekyll主题,几乎只需要复制粘贴文章文件,并微调一下Front Matter中的标签分类即可。如果换用其他生成器,虽然也有迁移工具,但难免会遇到格式兼容性问题,需要手动调整,工作量不可控。
- 足够的主题与插件生态:Jekyll社区历史悠久,有大量成熟、高质量的主题。更重要的是,许多主题作者都考虑到了GitHub Pages的兼容性,会避免使用需要额外构建步骤的插件。对于我的需求(博客),它的功能完全够用。
当然,Jekyll的缺点也很明显:Ruby环境在非Mac/Linux系统上可能有点麻烦(但GitHub Pages托管帮你省了这一步),编译速度对于超大型站点可能较慢。但对于一个个人博客来说,这些都不是核心痛点。选型的核心原则是:用最少的持续维护成本,满足核心需求。Jekyll+GitHub Pages的组合,在“省心”这一点上目前依然很难被超越。
2.2 主题选择:从“功能堆砌”到“简洁核心”
以前我喜欢找功能丰富的主题,评论、相册、音乐播放器啥都有。这次我反其道而行之,选择了一个结构极其清晰、代码注释完整、专注于写作和阅读体验的极简主题。原因有三:
- 专注:博客的核心是内容。花里胡哨的功能会分散读者(和自己)的注意力。
- 可维护:简单的主题意味着更少的代码,更清晰的逻辑。当我想自定义某个部分时,我能很快找到对应的文件并理解其作用,而不是在一堆复杂的模板和脚本中迷失。
- 性能:更少的JavaScript和CSS,意味着更快的加载速度。很多功能可以通过外部服务(如评论用Disqus或Gitalk,搜索用Algolia)来集成,保持核心站点的轻量。
我最终选择了一个基于minima主题深度定制并完全重写的开源主题,它保留了Jekyll的标准目录结构,但样式现代,且所有布局文件(_layouts/)和包含文件(_includes/)都写得非常易懂。
2.3 加速与安全方案:引入Cloudflare CDN
这是本次重建提升体验最关键的一步。GitHub Pages的服务器主要在美国,国内访问速度不稳定是众所周知的痛点。直接解决方案就是加一层CDN(内容分发网络)。
- 为什么是Cloudflare?首先,它免费套餐的功能对于个人博客来说已经非常强大:全球CDN、DDoS防护、SSL证书(支持灵活SSL和完全SSL)、防火墙规则、缓存优化等。其次,它的配置界面相对友好,与域名服务的集成(修改NS记录或CNAME)是标准操作。
- 核心价值:
- 加速:用户访问你的博客
blog.yourdomain.com时,请求会先到达离他最近的Cloudflare节点。如果该节点有缓存,直接返回,速度极快;如果没有,Cloudflare会回源到你的GitHub Pages地址(yourusername.github.io)获取内容并缓存。对于静态资源(图片、CSS、JS),缓存效果显著。 - 隐藏源站:你的真实服务器(GitHub Pages)IP对公众是隐藏的,由Cloudflare作为代理,这在一定程度上提升了安全性。
- HTTPS无忧:Cloudflare提供免费的SSL证书,你只需要在控制台一键开启“SSL/TLS”的“完全”模式,它就会帮你处理浏览器到Cloudflare、以及Cloudflare到GitHub Pages之间的加密,无需自己在服务器上管理证书。
- 加速:用户访问你的博客
注意:使用Cloudflare CDN后,你的访客和GitHub看到的访问IP都将是Cloudflare节点的IP,这会导致GitHub Pages内置的访问日志统计失效,也会影响一些基于IP的功能(如果你有的话)。通常这对于博客来说是可以接受的,统计可以交给Google Analytics或Cloudflare自家的分析。
3. 详细实施步骤:从零到一的完整记录
3.1 本地环境准备与主题初始化
虽然GitHub Pages会自动构建,但在本地预览和调试是必不可少的。你需要一个本地Jekyll环境。
安装Ruby与Jekyll(以macOS为例,其他系统请参考官方文档):
# 使用Homebrew安装Ruby(如果系统Ruby版本旧) brew install ruby # 将新安装的Ruby路径添加到shell配置(如.zshrc) echo 'export PATH="/usr/local/opt/ruby/bin:$PATH"' >> ~/.zshrc source ~/.zshrc # 安装Jekyll和Bundler gem install --user-install bundler jekyll安装后,运行
jekyll -v和bundle -v确认安装成功。创建新博客项目:
jekyll new myblog --skip-bundle cd myblog--skip-bundle参数是为了先不安装依赖,因为我们可能要换主题。替换主题: 删除自动生成的
minima主题相关文件(主要是_layouts,_includes,_sass目录和index.md等),然后将你选中的新主题文件全部复制过来。或者更推荐的方式是,直接Fork或Clone你心仪的主题仓库,以此作为起点。这样能保证目录结构完全正确。安装依赖并本地运行:
bundle install bundle exec jekyll serve访问
http://localhost:4000,你应该能看到新主题的预览效果。
3.2 内容迁移与配置调整
这是最需要耐心的一步。
文章迁移:将旧博客
_posts目录下的所有.md文件复制到新项目的_posts目录。检查每篇文章的Front Matter,确保关键字段如title、date、layout、categories、tags与新主题的要求一致。通常title和date是通用的,layout可能需要根据新主题的布局文件名称修改(如从post改为default)。静态资源迁移:将旧博客的图片、附件等资源(通常在
assets、images或uploads目录)复制到新项目的对应目录。建议借此机会整理资源,删除无用文件,并使用压缩工具优化图片体积。配置文件
_config.yml:这是Jekyll的核心。你需要仔细配置:title,description,url,baseurl:站点基本信息。theme:如果你用的主题是Gem-based,这里填主题Gem名;如果是直接复制文件的,则删除或注释掉这一行。plugins:列出需要的插件,如jekyll-feed(RSS)、jekyll-sitemap(站点地图)。确保它们在Gemfile中也有定义。defaults:为特定路径的文件设置默认Front Matter,非常有用。例如,可以为所有_posts下的文件默认设置layout: post。- 主题特定的配置:如社交链接、评论设置(Disqus shortname)、Google Analytics ID等,参考主题文档填写。
测试与验证:本地运行
bundle exec jekyll serve,逐一点开每篇文章,检查格式是否正确、图片是否显示、链接是否有效。特别检查分类页和标签页是否正常工作。
3.3 部署到GitHub Pages并绑定自定义域名
创建GitHub仓库:在GitHub上创建一个名为
<你的用户名>.github.io的公开仓库。这是使用GitHub Pages个人站点的最简单方式。推送代码:
git init git add . git commit -m "Initial commit with new blog" git branch -M main git remote add origin https://github.com/<你的用户名>/<你的用户名>.github.io.git git push -u origin main等待构建:推送后,GitHub Actions会自动开始构建(对于Jekyll项目)。你可以在仓库的“Actions”标签页查看构建状态。成功后,访问
https://<你的用户名>.github.io就能看到新博客。绑定自定义域名:
- 在域名注册商处,为你的域名(例如
blog.yourdomain.com)添加一条CNAME记录,指向<你的用户名>.github.io。 - 在你的博客项目根目录下,创建一个名为
CNAME的文件(无后缀),里面只写一行你的域名:blog.yourdomain.com。 - 将
CNAME文件提交并推送到GitHub仓库。 - 在GitHub仓库的 Settings -> Pages 页面,Custom domain部分,填入你的域名并保存。GitHub会尝试验证,并为你自动配置一个用于验证的A记录,你可以选择使用它,也可以稍后在DNS处自己配置。建议先使用GitHub提供的验证方式,成功后再进行下一步的CDN配置。
- 在域名注册商处,为你的域名(例如
3.4 配置Cloudflare CDN加速
这是将访问体验提升一个档次的关键。
将域名接入Cloudflare:
- 在Cloudflare官网注册并添加你的网站(例如
yourdomain.com)。 - Cloudflare会扫描你现有的DNS记录,并给出两个Cloudflare的Nameserver地址(如
lara.ns.cloudflare.com)。 - 回到你的域名注册商控制台,将域名的Nameserver修改为Cloudflare提供的那两个。这个过程称为“更改NS记录”,生效需要几小时到48小时。
- 在Cloudflare官网注册并添加你的网站(例如
配置DNS记录:
- 等待NS生效后,在Cloudflare的DNS管理页面,你需要添加一条记录来指向你的博客。
- 重要:这里有两种方法:
- 方法A(推荐,更清晰):为博客子域名单独设置。类型:
CNAME,名称:blog,目标:<你的用户名>.github.io,代理状态:已代理(橙色云朵)。 - 方法B(根域名):如果你想用根域名(
yourdomain.com)访问博客,GitHub Pages要求配置A记录指向其IP。你需要添加多条A记录,名称:@,目标分别指向GitHub Pages的四个IP:185.199.108.153,185.199.109.153,185.199.110.153,185.199.111.153,代理状态同样开启。
- 方法A(推荐,更清晰):为博客子域名单独设置。类型:
- 确保之前在GitHub仓库中创建的
CNAME文件内容与你这里设置的记录一致(例如blog.yourdomain.com)。
配置SSL/TLS:
- 在Cloudflare控制台的SSL/TLS选项卡下,将加密模式设置为“完全(严格)”。这个模式要求从Cloudflare到你的源站(GitHub Pages)的连接也是加密的。由于GitHub Pages本身就支持HTTPS并提供有效证书,所以这个模式是安全的。
- “边缘证书”部分,确保“始终使用HTTPS”选项是开启的。这会将所有HTTP请求重定向到HTTPS。
优化缓存与速度:
- 速度选项卡:可以开启“Auto Minify”,自动压缩HTML、CSS、JS代码。
- 缓存选项卡:这是重点。配置“缓存级别”为“标准”。在“缓存规则”中,可以创建一条规则来缓存所有静态资源。例如,创建一个页面规则,如果URL匹配
*blog.yourdomain.com/*.jpg或*.css或*.js,则设置“缓存级别”为“缓存所有内容”,并设置一个较长的“边缘缓存TTL”(如一个月)。对于博客文章页面(HTML),由于内容会更新,缓存时间可以设短一些,或者使用“标准”缓存级别,并依靠Cloudflare的“浏览器缓存TTL”设置。
验证:等待DNS完全生效后,访问你的自定义域名(如
https://blog.yourdomain.com)。打开浏览器开发者工具的“网络”选项卡,查看请求的响应头。你应该能看到CF-Cache-Status: HIT(缓存命中)或MISS(未命中,但下次访问可能就是HIT了),以及Server: cloudflare等字样,这表示流量已经成功经过Cloudflare加速。
4. 周边功能集成与优化
博客的核心是内容,但一些周边功能能极大提升互动性和可管理性。
4.1 评论系统:从Disqus到更轻量的选择
过去Disqus是标配,但它臃肿、加载慢、有广告。现在有更优选择:
- Giscus:我目前使用的方案。它利用GitHub Discussions作为评论存储后端。访客使用GitHub账号登录即可评论。优点是完全免费、无广告、与开发者社区无缝集成,评论内容以Issues的形式保存在你自己的仓库里,数据自主。配置步骤:
- 确保你的博客仓库已启用Discussions功能(Settings -> General -> Features -> Discussions)。
- 安装Giscus App到你的仓库(授权)。
- 访问 giscus.app ,根据向导配置(选择仓库、映射方式等),生成一段脚本代码。
- 将这段脚本代码嵌入到你的Jekyll主题的评论布局文件(通常是
_includes/comments.html)中。
- Utterances:与Giscus类似,但使用GitHub Issues而非Discussions。原理和配置方式相近,也是一个轻量级的好选择。
- Twikoo:一个基于云函数的评论系统,支持多种登录方式,界面美观。需要自行部署一个后端云函数(如Vercel、腾讯云SCF),稍微复杂一点,但可控性更强。
实操心得:对于技术博客,Giscus非常合适,因为读者大概率有GitHub账号。它的加载速度比Disqus快得多,且没有隐私顾虑。唯一的“门槛”是访客需要有GitHub账号。
4.2 站内搜索:让内容更容易被找到
静态站点无法进行服务端搜索,需要借助前端JavaScript或第三方服务。
- Simple Jekyll Search:一个纯客户端的JavaScript搜索库。它会在构建时生成一个包含所有文章标题、内容和URL的JSON文件(
search.json)。访客搜索时,JS直接在这个JSON文件里进行匹配。优点是完全免费、无需外部依赖、隐私友好。缺点是文章数量巨大时(比如上千篇),JSON文件会比较大,影响初始加载,且搜索算法相对简单。- 集成方法:在
_config.yml中配置生成search.json。然后在主题中引入其JS文件,并添加一个搜索输入框和结果展示容器。很多Jekyll主题已经内置了此功能。
- 集成方法:在
- Algolia:专业的搜索即服务。它能提供更快、更相关、支持拼音纠错等高级功能的搜索体验。它提供免费的社区套餐(每月一定额度的搜索次数和记录数,对个人博客通常够用)。但需要将你的站点内容通过API或自动化脚本推送到Algolia,配置步骤稍多。
我选择了Simple Jekyll Search,因为它足够简单,且与静态博客“自给自足”的理念更契合。对于几百篇文章的博客,其性能完全可接受。
4.3 自动化与持续集成:让更新更省心
虽然GitHub Pages已经自动化了构建部署,但我们还可以做得更好:
自动提交Sitemap到搜索引擎:每次博客更新,都希望Google、Bing能尽快收录。可以在
_config.yml中启用jekyll-sitemap插件自动生成sitemap.xml。然后,可以利用GitHub Actions,在每次推送代码后,自动向Google Search Console等平台提交这个sitemap。这需要你配置一个包含相应API调用的Action工作流文件(.github/workflows/submit-sitemap.yml)。资源优化:可以在本地构建流程中集成图片压缩工具(如
imagemin),或者使用GitHub Actions在构建前自动压缩图片。同样,也可以集成CSS/JS的压缩和合并工具。链接检查:定期运行死链检查,确保博客没有失效的链接。可以设置一个每周运行的GitHub Action,使用
lychee或linkchecker这样的工具扫描你的站点,并将报告发送到你的邮箱或生成一个Issue。
这些自动化脚本一开始可能觉得麻烦,但一旦设置好,就是一劳永逸的“数字管家”,能帮你维护博客的健康状态。
5. 常见问题与排查实录
在重建和后续维护过程中,我遇到了不少典型问题,这里记录下排查思路。
5.1 本地运行正常,推送到GitHub后页面空白或样式错乱
- 问题描述:
bundle exec jekyll serve本地预览一切完美,但推送到GitHub Pages后,访问网站发现只有纯文本,没有CSS样式,或者布局全乱。 - 排查步骤:
- 检查
_config.yml中的url和baseurl:这是最常见的原因。url应设置为你的最终访问地址(如https://blog.yourdomain.com),baseurl如果你站点不在根路径则设置(例如/blog),否则就留空""。本地运行时,Jekyll可能会忽略这些设置或使用默认值,但GitHub Pages构建时会严格使用这些值来生成资源链接。错误的baseurl会导致所有CSS/JS的链接路径错误。 - 检查GitHub Pages构建日志:在仓库的“Actions”标签页,找到最新的Pages构建工作流,点开查看详细日志。构建失败(Build failed)会直接导致站点无法更新。常见失败原因:使用了GitHub Pages不支持的自定义插件(白名单外的插件)、Ruby版本不兼容、
Gemfile中依赖冲突或语法错误。 - 检查主题引用方式:如果你使用的是Gem-based主题,确保
_config.yml中theme设置正确,且Gemfile中包含该主题gem。如果你是把主题文件直接复制到项目里的,确保_config.yml中没有theme这一项,或者已被注释掉,否则Jekyll会去寻找一个不存在的Gem。 - 使用
github-pagesGem:在Gemfile中,使用gem "github-pages", group: :jekyll_plugins,并运行bundle update github-pages。这个Gem包确保了本地环境与GitHub Pages服务器环境的一致性,能最大程度避免“本地行,线上不行”的问题。
- 检查
5.2 Cloudflare CDN配置后,访问出现“重定向过多”错误
- 问题描述:配置Cloudflare并开启“始终使用HTTPS”后,访问网站出现
ERR_TOO_MANY_REDIRECTS错误。 - 原因与解决:这是SSL/TLS设置和源站配置冲突的典型表现。
- 首先,确认Cloudflare的SSL/TLS加密模式。强烈建议使用“完全(严格)”模式。如果使用“灵活”模式(浏览器到Cloudflare是HTTPS,Cloudflare到GitHub Pages是HTTP),而GitHub Pages又强制跳转HTTPS,就可能形成循环重定向。
- 其次,检查你的GitHub Pages仓库设置。在Settings -> Pages -> Custom domain下,确保“Enforce HTTPS”复选框是勾选的。这个选项告诉GitHub Pages,当通过这个域名访问时,强制使用HTTPS。这与Cloudflare的“始终使用HTTPS”是协同工作的,不是冲突。
- 如果问题依旧,可以尝试在Cloudflare的“SSL/TLS” -> “边缘证书”设置中,暂时关闭“始终使用HTTPS”,清空浏览器缓存再测试。如果关闭后正常,说明问题出在Cloudflare的HTTPS重定向与某些配置冲突。可以检查Page Rules(页面规则)里是否有额外的重定向规则。
- 标准配置:Cloudflare SSL模式为“完全(严格)”,开启“始终使用HTTPS”;GitHub Pages自定义域名处勾选“Enforce HTTPS”。这个组合是经过验证的稳定配置。
5.3 评论系统(如Giscus)不显示或加载失败
- 问题描述:按照文档配置了Giscus,但页面上看不到评论框,或者控制台报错。
- 排查步骤:
- 检查仓库配置:确保你的GitHub仓库确实已启用Discussions功能(Settings -> General -> Features -> Discussions)。
- 检查Giscus App安装:访问 https://github.com/apps/giscus ,确认已安装并授权给了你的博客仓库。可以配置为“All repositories”或仅此仓库。
- 检查数据映射:在giscus.app配置向导中,“页面<->Discussion映射关系”选择“URL pathname”。确保“Discussion分类”已正确创建(通常在配置Giscus时会自动创建)。
- 检查前端代码:核对嵌入的脚本代码中的
>