本博客的移动用户镜像站
最新更新:此镜像站已停用。
移动用户(含移动宽带和移动手机流量用户)访问我的博客(https://blog.kukmoon.com,下文称为“本博”),速率慢得像蜗牛,尤其是图片,半天加载不出来。
1 问题的分析与分解
1.1 分析
本博 套了 Cloudflare 的 CDN,图床上传到 GitHub,并且用 Cloudflare Workers 反代加速,联通和电信访问没问题,丝滑流畅。因此,我判断是移动节点访问 Cloudflare 受到了阻碍。我上网搜了一下,果然,网上不乏抱怨移动限速 Cloudflare 的声音。
1.2 解决方案:镜像站
考虑到 本博 的实际情况,我决定采用新建镜像站的解决方案,即:保持主力站不变,专门开个镜像站 https://blog1.kukmoon.com 供移动用户访问。
镜像站,有三个特点:
- 🖼 图床。把原来 GitHub 仓库里的图片同步到墙内的 Gitee,镜像站使用 Gitee 仓库里的图片。
- 🌎 CDN。镜像站不套 Cloudflare 的 CDN,访问者可以直连。
- 🔣 标识。我做不到根据 ISP 自动跳转,只能在主站和镜像站的首页提供访问链接,供用户点击跳转。
1.3 问题的分解
我把移动用户访问本博速率太慢的问题,转换成要建立镜像站的问题。
接下来,我把建立镜像站这个问题,分解成以下三个问题:
- 图床。每次发布最新博文时,把原来 GitHub 仓库里的图片同步到墙内的 Gitee 镜像站;
- 发布。每次发布最新博文时,还要把镜像站每篇博文中图片的 URL 替换成 Gitee 仓库中图片的 URL。
- 标识。我需要修改博客的主题,在博客首页显示主力站和镜像站的访问链接,供用户点击跳转。
接下来,要继续分解,直到每个问题都分解成具体的步骤为止。
1.3.1 图床
在 Gitee 建立一个同名仓库,将 GitHub 仓库中的图片导入其中。
本博 是把源码放在本地,在 GitHub 设置一个博客源码仓库 Kukmoon/kukmoon_blog,每写完一篇新博文,就推送到 GitHub,用 GitHub Actions 自动部署并持续集成[1]。这样,我需要写一个 GitHub Actions workflow,每次推送最新博文时,额外把 GitHub 仓库中的图片同步到 Gitee。
1.3.2 发布
我打算把镜像站部署到虚拟主机上,不套 CDN。
本博 是把源码放在本地,在 GitHub 设置一个博客源码仓库 Kukmoon/kukmoon_blog,每写完一篇新博文,就推送到 GitHub,用 GitHub Actions 自动部署并持续集成[1]。这样,我需要编写一个 GitHub Actions workflow,每次推送最新博文时,把每篇博文中的图片 URL 修改成 Gitee 仓库里的图片的 URL,再部署。
1.3.3 标识
我需要修改博客的主题,在博客首页显示主力站和镜像站的访问链接,供用户点击跳转。它需要在本地修改博客的源文件,与发布无关。
2 方法与步骤
2.1 标识
谷月姐想在 本博 首页的副标题(subtilte)下方增加两条文字说明,如图。
本博 用的是 Fluid 主题。谷月姐有修改这个主题的经验[2] [3]。
通过与主题作者的沟通[4] [5]以及反复试错,谷月姐发现:
- 直接在
_config.fluid.yml
中的index.slogan.text
变量中书写 HTML 代码,就可以渲染出来。但是这样会带来一个 bug:鼠标指向博客副标题时,会把这些 HTML 代码都显示在屏幕提示 (screen tips)中,特别丑。
- 这个屏幕提示本质上是
<span>
标签的title
属性。它可以在themes/fluid/layout/layout.ejs
文件中找到,这个文件决定了每个页面(包括首页、文章页、归档页、分类页、标签页、关于页、友链页)的显示布局。
a. 如果在layout.ejs
文件中修改这个title
属性,打字机动画就不会正常运行,准确地说,打字机动画的那个 JS 脚本是读取这个<span>
标签的title
属性。总之,打字机动画和隐藏屏幕提示不可兼得。
b. 如果在layout.ejs
中,用 CSS 为<span>
标签引入point-events: none
属性,鼠标指向,就不会显示屏幕提示了,但是也无法点击链接了。总之,点击链接和隐藏屏幕提示不可兼得
谷月姐最终用以下方法解决了在首页的副标题下方增加两行文字说明的问题。
- 在
_config.fluid.yml
中增加一个index.slogan.additional_text
变量,在这里面书写 HTML 代码。1
additional_text: <span style="font-size:14px;">主力站(联通电信用户):<a href="https://blog.kukmoon.com" style="color:#C6C6C6;text-decoration:underline;">https://blog.kukmoon.com</a><br />镜像站(移动用户):<a href="https://blog1.kukmoon.com" style="color:#C6C6C6;text-decoration:underline;">https://blog1.kukmoon.com</a></span>
- 在
_config.fluid.yml
中,关掉打字机动画,即把fun_features.typing.enable
变量的值改成false
。 - 修改
themes/fluid/layout/layout.ejs
文件,把图中红框中的代码改成绿框中的代码。
1
2
3
4
5
6
7
8
<span class="h2" id="subtitle" title="<%= subtitle %>">
<% if(!theme.fun_features.typing.enable) { %>
<%- subtitle %>
<% if(is_home()) { %> <!-- is_home() 判断是不是首页 -->
<br /><br /><%- theme.index.slogan.additional_text %> <!-- 在 _config.fluid.yml 文件的 index.slogan 段中,新增了一个参数 additional_text,让它显示补充性文字。必须关掉打字机动画,否则会混乱。 -->
<% } %>
<% } %>
</span>
2.2 图床
2.2.1 导入
Gitee 可以导入 GitHub 的仓库[6]。主要操作步骤:登录 Gitee,点击右上角的 + 号,选择“从 GitHub/GitLab 导入仓库”,按照提示操作。将 本博 所使用的全部图片从 GitHub 的仓库 Kukmoon/img 导入到 Gitee 的仓库 Kukmoon/img。
2.2.2 自动同步
Gitee 只能手工导入 GitHub 的仓库,不能自动从 GitHub 仓库拉取。
我需要在每次更新博客时,把图床里图片从 GitHub 的仓库同步到 Gitee 的仓库。我的博客源码在 GitHub 的仓库 Kukmoon/kukmoon_blog,所以我需要编写一个 GitHub Action workflow,只要我从本地向 Kukmoon/kukmoon_blog 仓库推送,GitHub 就会自动把 GitHub Kukmoon/img 仓库同步到 Gitee 的 Kukmoon/img 仓库。
如果在每次上传图片到图床时,让 GitHub 把图片同步到 Gitee 可以吗?当然可以,实际上我搜到的教程基本都是这方面的,例如[7]。但是这样带来一个问题:我是一边写博文,一边用 PicGo 向 GitHub 图床上传图片的;每篇文章至少有2张图片,如果每上传一张图片都要用 GitHub Actions 自动同步一次,会大量消耗 GitHub Actions 时长,容易被 GitHub 官方处罚。所以我还是选择每更新一次博文就同步一次图片比较稳妥。
这样,我就需要在 GitHub 的 Kukmoon/kukmoon_blog 仓库中编写新的 GitHub Actions 代码,当发生推送事件时,把 GitHub 的 Kukmoon/img 仓库中的全部内容推送到 Gitee 的 Kukmoon/img 仓库。
我参照这篇教程[7]、这篇文档[8]和这篇文档[9],稍微修改了教程[7]中的代码,指定了要同步的仓库为 Kukmoon/img,并且使用 SSH 协议强制更新。
1 |
|
因为代码以变量的形式调用了 GitHub 仓库的 secrets,所以还要配置 secrets 和 SSH 密钥。
在 PowerShell、Windows Terminal、macOS Terminal 或 Linux 终端中执行命令,生成一对公钥和私钥专门用于 GitHub 同步到 Gitee。注意 -C
参数后面的 “Kukmoon” 是说明性文字,可以随意编写。
1 |
|
登录 Gitee,点击右上角头像→设置→ SSH 公钥,添加刚才生成的公钥,起个名字,例如 github2gitee。
登录 Gitee,点击右上角头像→设置→私人令牌→生成新令牌,权限建议全选,复制生成的令牌。
登录 GitHub,打开博客源文件所在的仓库 Kukmoon/kukmoon_blog,点击 Settings → Secrets → Actions,新建 3 个 secrets:
GITEE_USER
:个人的 Gitee user id,谷月姐的是 Kukmoon;GITEE_PRIVATE_KEY
:刚才生成的私钥;GITEE_TOKEN
:刚才在 Gitee 生成的 Token。
登录 GitHub,点击右上角头像→Settings→SSH and GPG Keys→New SSH Key,添加刚才生成的公钥,起个名字,例如github2gitee。因为谷月姐在前面的代码中开启了 SSH 协议同步,所以必须将公钥一并上传到 GitHub。
将以上代码保存到 Kukmoon/kukmoon_blog 仓库中的 .github/workflows/sync2gitee.yml
文件,这次保存就会触发同步。
2.3 发布
本博 是把源码放在本地,在 GitHub 设置一个博客源码仓库 Kukmoon/kukmoon_blog,每写完一篇新博文,就推送到 GitHub,用 GitHub Actions 自动部署并持续集成[1],发布到我的虚拟主机(此处假设虚拟主机的 IP 地址为 999.999.999.999
)和 GitHub Pages。
这样,我需要写一个 GitHub Actions workflow,每次推送最新博文时,把每篇博文的 Markdown 源文件中的图片 URL 修改成 Gitee 仓库里的图片的 URL,再把博客的配置文件 _config.yml
中的部署目标从虚拟主机的 URL 改成镜像站的 URL,再用 hexo d -g
命令发布。
查找替换文件中的字符串可以用 Linux 的 sed
命令,语法如下:sed -i 's/原字符串/新字符串/g' 文件名
。
批量查找替换多个文件的字符串可以用 sed
结合 grep
命令,语法如下:
1 |
|
原字符串中的特殊符号(此处有三个特殊符号:/
、 @
、 #
),前面要加上转义字符 \
处理,以免出错。
本博 主力站的图片 URL 是 https://img.kukmoon.com/图片文件名.jpg
,谷月姐需要把 https://img.kukmoon.com
替换成 Gitee 图床的 URL,即 https://gitee.com/kukmoon/img/raw/master
。所有的 Markdown 源文件都位于 source/_posts
目录。所以,写出批量查找替换图片 URL 的命令如下:
1 |
|
博客的配置文件 _config.yml
的 deploy:
段规定了博客的部署目的地。本博 的配置文件如图所示:
要把第 147 行删除或者注释掉,把第 151 行里的上传 URL 改成镜像站的 上传URL。
用 sed
命令把第 147 行注释掉: sed -i 's/ repo: git\@github.com:Kukmoon\/xxxxxx.git/\#&/g' _config.yml
。(xxxxxx是仓库的名字,新字符串中的 &
符号表示原字符串,例如我要把 abc
替换成 abcd
,就可以写成 sed -i 's/abc/&d/g' filename
)
用 sed
命令修改第 151 行里的上传 URL: sed -i 's/repo: ssh:\/\/kukmoonc\@999.999.999.999\/home\/kukmoonc\/public_html\/blog/ssh:\/\/kukmoonc\@999.999.999.999\/newpath/g' _config.yml
。(ssh://kukmoonc@999.999.999.999/newpath
是镜像站的上传 URL)
可以直接用 sed
命令修改每篇博文的 Markdown 源文件和博客的配置文件 _config.yml
,因为 GitHub Actions Workflow 是在虚拟机中运行的,先用 action/checkout
这个 workflow 将仓库中的文件读取到虚拟机中,再修改虚拟机中的文件,不会直接修改仓库中的文件。
谷月姐把上次写的自动部署博客的 GitHub Action workflow 拿出来[1],稍做修改,写出了一个新的 workflow :
1 |
|
将以上代码保存到 Kukmoon/kukmoon_blog 仓库中的 .github/workflows/deploy_to_mirror_1.yml
文件,这次保存就会触发同步。
2.4 整合
现在谷月姐共有 3 个 GitHub Actions workflow:一个是上次编写的[1],用它把博客部署到 GitHub Pages 和虚拟主机,作为主力站;第二个是在 2.2 节编写的,用它将图片从 GitHub 同步到 Gitee;第三个是在 2.3 节编写的,用它修改 Markdown 源文件中图片的 URL,将博客部署到虚拟主机,作为镜像站。
它们三个都设置为当推送到博客源文件仓库 Kukmoon/kukmoon_blog 时才运行(也就是说,把 on:
设置为 push: branches: - master
)。
每个 GitHub Actions workflow 里面可以有多个 job,而不同的 job 是并发运行的,准确地说,同一个 workflow 有几个 job, GitHub Actions 就开几个虚拟机,每个虚拟机运行一个 job。
因此,谷月姐可以把这三个 workflows 作为三个 jobs,整合到同一个 workflow 中。
代码如下。
1 |
|
把上述代码保存到仓库 Kukmoon/kukmoon_blog
的 .github/workflows/deploy.yml
,覆盖原来的同名文件,然后把上文的两个文件,sync2gitee.yml
和 deploy_to_mirror_1.yml
删除掉。
3 总结
谷月姐加深了对 GitHub Actions 的理解,学会了 Linux 查找替换文件中字符串的方法,发现了 Gitee 充当图床在墙内访问的速度比较快。
如果没有那该死的墙和网站备案制,谷月姐根本不需要搞得这么麻烦。Fuck the GFW!
4 图片版权
头图:“Light trails on the S curve road, Jioufen, Taiwan” by Fishtail@Taipei is licensed under CC BY-NC-ND 2.0 .
5 参考文献
- GitHub Actions 自动部署 Hexo 博客到 cPanel 虚拟主机 https://blog.kukmoon.com/f8bb4ee.html ↩
- 给Hexo博客的 Fluid 主题增加“分享到”模块 https://blog.kukmoon.com/c87ddd18.html ↩
- 给 Hexo 博客的 Fluid 主题增加打赏模块 https://blog.kukmoon.com/7bf76e1d.html ↩
- 如何在博客首页大标题下方加一行文字 #664 https://github.com/fluid-dev/hexo-theme-fluid/issues/664 ↩
- 如何去掉鼠标指向博客副标题时显示的提示 #665 https://github.com/fluid-dev/hexo-theme-fluid/issues/665 ↩
- 如何将 GitHub 项目导入码云?一步搞定! https://blog.gitee.com/2018/06/05/github_to_gitee/ ↩
- 3步自动同步你的 Github 仓库到 Gitee 仓库 https://gyx8899.gitbook.io/blog/share/syncgithubtogitee ↩
- Yikun / hub-mirror-action / README.md https://github.com/Yikun/hub-mirror-action/blob/master/README.md ↩
- actions / checkout / README.md https://github.com/actions/checkout/blob/main/README.md ↩