由于自己很久没更新博客了,加上之前用的博客主题也更新了挺多,自己便趁放假的这段时间为自己的博客主题跟进了一些更新,也做了一些自定义,花了几天时间终于到达一个勉强令自己满意的程度。
TL;DR
本文主要从以下几个方面对自己托管在 Github Page 上的 Hugo 博客进行了优化:
- 大部分静态资源 (CSS / JS / 图片) 加上了 Cloudflare CDN
- 将托管在 Cloudflare CDN 做了简单的国内外流量分流
- 使用对国内环境友好且免费够用的 Cloudflare R2 作为图床
- 使用 Cloudflare Workers 反代 Google Analytics 4
- 更新 Workbox 进行 Service Worker 缓存
- 增加 Quicklink 来提高页面加载效率
还有一些则是自己在原来模板基础上,根据各种优化建议做的简单优化。
Domain
关于域名,我放弃了之前自己精心维护的域名 zeddyu.info ,也不再考虑续费,以后就主要使用 zeddyu.github.io 的这个域名作为博客域名。一方面是因为自己这个域名除了搭建一个静态博客之外,也就是在各种 CTF 比赛中使用,用处其实并不多;另一方面当然就是由于域名捆绑问题,域名商一开始会提供一个很便宜的价格吸引你续费运营该域名,但是之后几年的续费价格连年飙升,这里我猜测是域名商一旦发现你的域名访问量增加到一定程度,便会坐地起价,极大抬高续费价格,这对于我一个不把域名或者其与之有关的附加途径(比如静态博客)作为高盈利手段的人来说有一些得不偿失,这也是促使我直接放弃该域名的直接原因。当然,如果你想要运营一个域名并想从中获利也是有一些渠道的,但是我确实不太想那么做,这里也不再细谈。
除此以外,虽然我放弃了运营自己的域名,但是我也会准备一个用完即换的域名,用作 Cloudflare 服务以备其他需要用到域名场合,后面就会使用这个域名配合 Cloudflare Free Plan 为自己的博客做一些加速服务。
Info
请不要直接把我文中或者本站的 CDN 域名应用到你的博客,因为我使用了一些自定义配置,并且不保证其长期正常运行
Cloudflare
Cloudflare (以下简称 CF )无疑是我认知范围内最慷慨的云厂商,不仅免费提供 CDN 服务,还提供了很多其他免费的(一定限额)云服务,可玩性非常高,我这几天仅仅是花了一些时间复刻了几个可以免费为自己博客加速的操作,就感觉到其中的操作非常多。
Static Files Acceleration
这里我要首先介绍一下我目前博客的架构:
- 仅使用 zeddyu.github.io 作为主域名。因为我放弃了运营主域名,所以不同于其他博客的操作,我不再直接使用自定义域名托管 CF 上直接为博客加速。
- 使用一个其他域名托管在 CF 上用作加速服务。加速主要考虑的是为博客的静态资源,静态资源主要分为 CSS / JS / 图片资源。
- css / js 资源可以考虑直接使用 jsdelivr 等其他第三方 CDN 服务直接加速
- 其中有一些比较特殊,比如 Google Fonts 等资源,可能需要单独处理,比如使用 Proxy / 其他 CDN / 选择平替 Cloudflare Fonts
- 图片资源可以针对性考虑。首先考虑博客读者的网络环境,可以针对性使用不同云服务运营商的免费、付费托管服务,当然也可以直接放在 github 上然后使用 jsdelivr 进行加速。
- css / js 资源可以考虑直接使用 jsdelivr 等其他第三方 CDN 服务直接加速
这里稍微提一下,因为一些博客说到如果使用 CF 服务加速 css / js 等静态资源可能反而是副作用,但是在我这种情况下,国内网络环境下使用 curl 请求 20 次,直接访问 github.io 下的静态资源,平均时间在 3-4s 左右,甚至有时候到达 7s ,在使用了以下的加速配置后平均时间在 1s 左右,虽然期间也出现过一次 20s 的情况,但是考虑到网络波动等情况,这种情况能够接受。在国外的网络情况下,我使用首尔的 VPS 以及香港的 CMHK 网络环境测试,基本都差不多,都能在 1s 内,平均 0.1s ,那基本就无所谓了。
Traffic Diversion
首先我们考虑比较重要的网站架构资源 CSS / JS 文件资源。我参考了一些资料,直接使用CF 的 CDN服务为这些资源加速,虽然 CF 的 CDN 服务对于国内表现不算优秀,但是可以用他的 CF Workers 配合 CDN 做一些分流措施,将国外国内流量分流至不同的 CDN 服务获得最佳的效果。主要参考文章: 通过 Cloudflare 和 jsDelivr 免费加速博客 GitHub 图床等静态资源
首先在 CF 上托管自己的域名,并添加一个 CNAME 记录指向 cdn.jsdmirror.com ,开启代理状态。以下我们以 cdn.zdy.one 举例说明。
再到 CF 规则 / 重定向规则中,添加两个规则。
- 规则 1 : 主要为分流国内流量,使用自定义筛选表达式,按照图中配置,主机名使用刚才我们填写的 cdn.zdy.one ,国家地区选择 China ,下方重定向填写
concat("https://cdn.jsdmirror.com", http.request.uri.path)
- 规则 2 :主要为分流国外流量,类似规则 1 配置,只不过把国家地区选择不等于 China ,并且下方重定向表达式改为
concat("https://cdn.jsdelivr.net", http.request.uri.path)
- 以上步骤与参考文章步骤一致,更详细可以参考原文章。以下为我自己添加的配置
- 规则 1 : 主要为分流国内流量,使用自定义筛选表达式,按照图中配置,主机名使用刚才我们填写的 cdn.zdy.one ,国家地区选择 China ,下方重定向填写
为静态资源添加 CORS 头
- 到 CF 面板 / 规则 / 转换规则 / 修改响应头 / 创建规则
- 选择自定义筛选表达式,并按图配置,主机选择我们的 cdn.zdy.one 域名,按需设置一个 CORS 头部。
- 设置这个主要是因为我的静态资源在被引入使用的时候,而通过上面的配置,静态资源是通过 302 实现的地区分流,然而浏览器会因为 302 而会抛出 CORS 错误,所以我们需要配置这个来解决 CORS 的问题。当然你也可以按需配置一些其他的
OSS? S3? Cloudflare R2!
现在有很多免费的图床,虽然某些看起来可能不太可靠,但是有一些图床从我运营自己博客到现在,也一直持续了有几年时间,到目前(2025.1.3)为止,我印象里比较可靠的免费图床有:
- 路过图床: https://imgse.com/
- SM.MS: https://sm.ms/
当然也可以一些付费服务,比如各种云厂商提供的付费对象存储服务,阿里云 OSS / AWS S3 ,甚至 Cloudflare 在我不知不觉间也推出了自己的对象存储服务 Cloudflare R2,甚至免费额度还挺不错;另外还有一些另辟蹊径的服务用作图床,比如 Onedrive 等。
这里我之前是使用腾讯云的 COS 对象存储服务,虽然确实花费比较少,每个月几毛或者几分,但是有时候访问量高起来也有几块钱的开销。之前我也有考虑过使用 CF CDN 配上 COS ,这样可以节省一些流量访问,但是现在为了支持“降本增效”,我就把之前腾讯云的 COS 图床彻底迁移到了 CF R2 上,毕竟对于我来说其提供的免费额度足够我目前的使用,后期如果实在超出额度,或者 CF R2 变更了其免费计划再考虑其他方案,比如 Onedrive 等。并且,其速度在国内网络环境下表现也能接受,甚至有时候能大部分全绿。
其次,后面我会尽量少用图片,因为之前看自己的 Writeup 文章,用图片确实很奢侈,甚至拿到一个 FLAG 都要放张图,当时觉得无所谓,但是现在看起来,这其实没什么必要,因为这些图片跟你只用一句话解释“于是通过这样我拿到了FLAG”达到的表达效果其实并没有太多区别,一行文字能表达清楚的我就尽量不使用图片,除非这张图真的很有意义。
再者,对于真要放图的地方,我会考虑其对于阅读效果的影响。十分重要的,离开了这张图片就可能影响表达效果的,我就把他放到自己的 Github Repo 或者 CF R2 上;一般重要的,看情况放在 CF R2 上 或者 SM.MS 上;可以放张图,并且即使这张图挂了都不会影响阅读内容体验的图会放到 SM.MS / 路过等免费图床上。
在确定好自己的图床后,可以在 CF 上修改请求 R2 中图片的缓存时间,毕竟图片一般很少更改,我们可以直接增大缓存时间以获得良好的优化效果,我们可以在Cloudflare 面板中:
- 缓存 / Cache Rules 中增加一条规则
- 默认配置下本身他已经帮我们配置好了很多静态资源的扩展名,我们可以直接使用他的配置,并再增加一条匹配规则,使其只匹配我们的图床域名:
(http.host eq "yourdomain.com")
- 缓存资格:选择 符合缓存条件
- 边缘TTL:选择 忽略缓存控制标头,使用此 TTL,缓存时间设置为 1 年
- 浏览器TTL:选择 替代源服务器,使用此 TTL,缓存时间设置为 1 年
- 缓存密钥:开启 缓存欺骗盔甲
你可以自己选择觉得合适的缓存时间,我这里直接设置得比较大为一年。
除此以外,关于图床的优化还可以使用一些专门对于图片的缓存优化,比如 WebP Cloud ,详细参考以下:
- Free Image Hosting With Cloudflare Transform Rules and Backblaze B2
- 从零开始搭建你的免费图床系统 (Cloudflare R2 + WebP Cloud + PicGo)
Cloudflare Workers
CF workers 是 CF 推出的 Serverless 优秀工具,也是经常被用来作反代加速处理的不二选一,用好了的话可以在其免费额度内解决很多国内的网络环境问题,甚至某些魔法问题,可以参考:https://github.com/topics/cloudflare-workers
但是目前由于其官方分配的 workers.dev 很早就被屏蔽了,我们就需要绑定一个自己的域名来规避这个问题,后面我们会使用这个功能来实现一些 Google 服务的加速。
Theme Optimization
这部分就是本博客主题的优化了
CDN
既然为静态资源配置 CDN ,那接下来我们就得修改主题资源的 URL 使其指向这些 CDN 链接啦。
Warning
请在使用第三方 CDN 资源的时候注意配置 SRI 以免被投毒篡改
以我 stack 的主题为例,我为博客主题 stack 为例,在开发测试的时候,可以直接在 config.yaml 增加新的配置
|
|
如果使用的是生产配置模板 starter ,那么就需要在 config/_default/params.toml 中增加配置
|
|
这个配置是为了方便直接在 Hugo 主题 HTML 模板中引入 CDN 链接,接下来就是为需要的地方对应添加 CDN 链接了,主要位置就是在各种引入了 CSS / JS / 图片 前添加我们的 CDN 链接 ,主要思路就是先判断是否存在 CDN 配置,如果存在就使用 CDN 链接替换掉原来的链接,参考代码:
|
|
以下是我为主题替换的地方:
layouts/partials/sidebar/left.html: 左侧的头像图片
layouts/partials/head/style.html: 主要的 CSS 样式文件
layouts/partials/footer/components/script.html: 主要的 JS 文件,修改逻辑与上类似
layouts/page/search.html: search.js 文件,修改逻辑与上类似
layouts/_default/_markup/render-image.html: 为图片链接在 github.io 上的链接增加 CDN
Google Analytics 4
如果直接使用 Hugo 内置的 Google Analysis 模板的话,我们可以从 _internal/google_analytics.html 代码中看到,其直接使用了 script 标签引入 GA 4 的 JS 文件
|
|
而在早些年的一个篇分析中 A very Minimal Google Analytics 4 Snippet,我们可以从中知道如果直接使用的话,可能会遇到几个问题:JS 文件体积过于臃肿 / 可能会被用户浏览器的广告拦截器拦截,并且在这篇文章中,也给出了比较直接的解决方案,那我们何乐不为呢?
但是如果直接使用 www.google-analytics.com 域名的话,国内网络环境总是出现各种问题,从站长的测速来看福建联通稳定链接不上,所以我采用了另一种方案,就是使用 CF Workers 来进行 GA 4 的反代,这里主要参考:
在 CF Workers 上部署以上博客其中一个脚本,再配合修改使用 Minimal Google Analytics Scripts 即可,记得把其中的 collect_path 以及 GID 修改为自己的即可。
Service Worker
在三年前的 从 Hexo 搬迁至 Hugo 中,我用 Workbox 实现 Service Worker Cache 相关的操作;三年过去后 Workbox 没有比较大的更新,现在已经有更多的博主使用 Workbox 来优化他们的博客,所以我也参考了现在比较流行的一些配置,改进了一下我的 Workbox 脚本,具体代码可见 https://cdn.jsdelivr.net/gh/zeddyu/zeddyu.github.io/sw.min.js
主要按照 Google Workbox 官方的 workbox-recipes 文档进行了增改,同时也了解了一下 Workbox 的 precache 策略:
One feature of service workers is the ability to save a set of files to the cache when the service worker is installing. This is often referred to as “precaching”, since you are caching content ahead of the service worker being used.
从 workbox-precaching 理论上来说,我们可以在 Service Worker 的安装过程中就提前请求缓存所需要的资源,这个比较适合用来提前缓存首页加载所需要的内容资源。因为我们几乎所有静态资源都上了 CDN ,所以一开始我试图用来缓存我配置的 CDN 上的静态资源,但是令人比较意外的是这个函数严格限制了跨域资源的加载,并且不管你 CORS 与否,相关代码见 workbox/packages/workbox-core/src/copyResponse.ts#L26 :
|
|
这就让我不得不放弃对 CDN 资源使用 precaching 策略,尽管也有 Warm Page Cache 作为平替,但是最好的做法当然不适用 Cache 这些 CDN 上的资源了,而且使用 StaleWhileRevalidate 的策略也不会影响太多。虽然我们也可以放弃对我们页面静态资源加 CDN ,直接请求 github.io/style.min.css 来使用,但是按照国内网络环境这速度,我觉得还是加上 CDN 为好,毕竟第一次打开还是更费时的。
Speculation Rules
在了解 precaching 的过程中,我还意外找到了另一种优化策略: Speculation Rules API ( 这里突然想起之前的某个 CTF 就出过类似的题目,没想到将之用于自己的博客优化上,搜了一下竟然只有上个月的 SECCON CTF ,但是我应该有印象的不是在这个比赛的题目… )
The Speculation Rules API is designed to improve performance for future navigations. It targets document URLs rather than specific resource files, and so makes sense for multi-page applications (MPAs) rather than single-page applications (SPAs).
回到主题,Speculation Rules 不难从其名字就能知道,这个是用来推测用户行为的一个 API ,有点类似于我之前在使用 Hexo 主题的时候使用的一个插件 instant.page ,大概效果说白了就是按照一定的规则,根据用户的鼠标行为(例如悬停,点击等)提前让浏览器做出行为,比如用户鼠标放在一个超链接上,它会根据页面的策略是否提前向该链接发起请求、后台渲染,亦或者在浏览器处于空闲状态时候对页面的超链接进行分析并按照策略提前发起请求等。总之,这是稍微预判用户行为,并在用户做出行动前就采取请求的 API 功能。
一开始我原本想手写 Speculation Rules 来进行我博客的适配,但是写了一些规则总对于他的文档说明有点摸不着头脑的感觉,例如如果在 Speculation Rules 中使用 urls
,例如使用以下配置:
|
|
按照这个配置, Chrome 会使用当前路径加上 urls 列表进行匹配,比如如果当前页面路径为 /about/
,那么 Chrome 会根据对应配置的策略对 /about/ads
进行 Prefetch / Prerender 获取,这就有点反直觉,毕竟我是加了根目录的斜杠。
后来发现早就有了更为成熟的框架 quicklink 来实现、拓展 Prefetches / Prerender ,而且使用起来也比较简单,提供了对应的 API ,当然我们也可以直接让 quicklink 自己决定页面的策略:
|
|
当然如果你对 Speculation Rules 感兴趣,也可以参考以下几个文档:
Other Optimizations
还有一些其他的优化,可以使用 Chrome 开发者工具栏的 Lighthouse 进行测试,也可以使用在线版 PageSpeed Insights ,也或者使用 WebpageTest ,尽管他们出的报告好像都差不多。基于这些报告,我们可以从中得到一些优化建议,比如
- 头像的 PNG 可以换成 Webp
- 非主要的 CSS / JS 文件可以加
defer
等异步
当然这些建议都比较机械化,只是简单判断是否存在 A 便提出建议 B ,是否要采用这个建议还需要根据你自己的需求,否则有些时候一味提升这个固化的表面“速度”分数恰好适得其反。
当然这里列举一些我了解到的其他优化方案,比如可以替换的服务:
- Cloudflare
- 对于流量分流来说,有些博客使用了某些国内云厂商的智能 DNS ,从 DNS 解析就做了国内外的流量分流,这也是一个不错的选择。但是鉴于你涉及到国内的 DNS ,自然逃不开备案的那一套,所以我就直接放弃了这个想法
- Github Page
- Vercel (国内已屏蔽): 2021年左右的时候,因为当时我还持有自己的域名,我有考虑过将博客从 Github Page 迁移到其他对国内网络环境比较友好的服务商上,当时就听说 Vercel 对国内网络环境比较友好,结果没想到现在我用国内网络环境测试我之前部署在 Vercel 上的站点已经彻底无法打开了,而且 Vercel 对于超出一定额度的流量收费也是劝退了我。
- 当然你也可以通过其他方式来绕过屏蔽限制,但是本身我之前想用 Vercel 就是因为其对国内网络环境稍微友好一些,一旦失去了这个优势那就没有换的必要了。
- Cloudflare Page: CF 大善人的静态页面托管服务,这个取决于国内用户访问 CF 的网络速度
- 还有一些其他静态页面托管服务,但是总体来说与 Github Page 大差不差,没有 Vercel 当初那种能直接提供网络优势的,所以基本没有切换的动力,以及后期确实不考虑运营域名的情况,还是主要以使用 Github Page 为主
- Vercel (国内已屏蔽): 2021年左右的时候,因为当时我还持有自己的域名,我有考虑过将博客从 Github Page 迁移到其他对国内网络环境比较友好的服务商上,当时就听说 Vercel 对国内网络环境比较友好,结果没想到现在我用国内网络环境测试我之前部署在 Vercel 上的站点已经彻底无法打开了,而且 Vercel 对于超出一定额度的流量收费也是劝退了我。
- 图床服务:
- Backblaze B2: 提供免费的 10GB 试用,而且外出流量免费,综合对比其他国外的存储服务还是很有优势的
- Cloudflare R2: 免费 10GB 存储,外出流量免费
- Onedrive: 个人免费 5GB 存储,外出免费
- SM.MS : 个人免费 5GB 存储,外出免费
- 路过图床: 没有找到免费计划的额度
目前 (2025-01-05) 可以在国内网络环境下,直接使用的服务:
- Google Fonts: Google Fonts 在国内仍可以访问并且速度也不错,可以直接使用,
- 当然你要是不放心,也可以参考 USTC 的方案: *.proxy.ustclug.org 等服务无法访问,以及后续计划
- 使用 CF Workers 实现反代
- 其他备选方案(并不推荐):
- fonts.loli.net: https://fonts.loli.net/css2?family=Lato:wght@300;400;700&display=swap
- fonts.font.im: https://www.googlefonts.cn/ 国内站长提供的 CDN 服务,可靠性未知
- Cloudflare:
- R2: 国内网络环境支持不错
- Page: 直接分配的域名在国内访问的速度跟 Github Page 半斤八两
Summary
除了以上优化以外,自己花的这几天时间也跟进了一波目前 Web (主要是 CSS / Browser ) 的新特性,有一些改进确实很方便,也挺有趣的,但是由于不在我用的那些特性并不算对于博客的优化,只是我用来修改自己对于主题不太满意的地方;Cloudflare 可玩性确实很高,还有很多值得探索利用的功能,以后可能会经常关注其新功能的支持,也算是增加一下对业界的了解,以后也会尽力回归到博客的日常更新中。
最后,祝看到这里的各位新年快乐!