注意:这篇文章上次更新于741天前,文章内容可能已经过时。
This article was last updated741 days ago, the content may be outdated.
起因
前段时间被封了一个圣何塞的甲骨文云账号,上面我开了一个 4C 24G 的 ARM 实例,跑了很多东西,几乎所有以 dijk.eu.org 结尾的域名都在上面跑着。
当然,就包括博客的图片服务器。
这下好了,博客的图片全都挂了。
然后我把博客的图片服务器指定成了家里的服务器。优点是国内访问的速度快,缺点是家里的服务器不稳定。
所以,一个自然的需求就是监控家里的服务器,看看它是否在线。
但是,如果监控服务器的服务器本身都不够稳定,那监控就失去意义了。(没错,我说的就是白嫖的服务器。)
又免费,又相对稳定的服务,我熟悉的就只有 GitHub Actions 了。
效果图
Why
A while ago, my Oracle Cloud account in San Jose was banned. I had a 4C 24G ARM instance there running all sorts of things — almost every domain ending in dijk.eu.org was running on it.
Including, of course, the blog’s image server.
So all the blog images went down.
Then I pointed the blog’s image server to my home server. The advantage is fast access from China; the disadvantage is that the home server isn’t stable.
So a natural need arose: monitor the home server to see if it’s online.
But if the monitoring server itself isn’t stable enough, the monitoring becomes meaningless. (Yes, I’m talking about free-riding servers.)
For something free and relatively stable, the only thing I know well is GitHub Actions.
Effect
代码
想要无限制的使用 GitHub Actions, 你需要一个公开的仓库。
所以我不得不把这套方案公开,尽管它实际上无比丑陋。

https://github.com/WANG-Guangxin/wang-guangxin.github.io
整体结构

这个图其实已经描述的比较清楚了,GitHub Actions 负责执行定时任务,然后 Shell 脚本负责执行 hexo 命令来生成静态页面,Python 脚本负责检查网站是否在线,然后根据结果来生成 Markdown 文件,以提供给 Hexo 来渲染。
下面就一一介绍这三部分。
GitHub Actions
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/.github/workflows/main.yml
1 |
|
简单解释一下,为什么这个定时任务设置的是每 15 分钟执行一次,而不是每 5 分钟执行一次。
这是因为 GitHub Actions 的定时任务执行时间不准确,基本都会有延迟,如果设置的是每 5 分钟执行一次,那么实际上会有很多次执行是在 5 分钟之后的,甚至 10 分钟之后的。
另外,在 Actions 的条款里,对每次 Actions 的执行时长限制是 30 分钟。
为了遵守条款的同时让这个监控更加稳定,我采取的方案是每 15 分钟执行一次 Actions,但每次 Actions 会部署 3 次 Hexo 网站,每次间隔 5 分钟,这样操作相对来说执行频率更高一些。
负责生成 Hexo 网站的脚本是 build.sh,这里接收了 5 个环境变量,用于配置邮件通知。
1 | - name: Build-0 |
Shell 脚本
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/build.sh
1 | hexo clean # 清理 Hexo 缓存 |
解释一下 envsubst 这个命令,它的作用是替换模板文件中的变量。
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/template_index.md
模板 template_index.md 文件中有很多shell变量,这些变量会在 siteenv 文件中被定义。
执行 envsubst < "./template_index.md" > "./source/sites/index.md" 这个命令,就会把 template_index.md 文件中的变量替换成 siteenv 文件中的变量的值,然后生成 index.md 文件。
siteenv 文件的内容由 Python 脚本生成。
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/siteenv
Python 脚本
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/uptime.py
这里是整个 Uptime 监控的核心代码了。
全局变量总共四个,分别是 g_config, g_data_file, g_data_list, g_notice_enable。
1 |
|
g_config 是一个字典,存储了需要监控的网站的信息。这里面的 key 是网站的域名,value 是一个字典,存储了网站的状态、7 天的在线时间、24 小时的在线时间、是否启用 SSL。
它的Value的value是一个字符串,这个字符串是为了生成一个可以被 Linux Shell 执行 source 的文件。
g_config 是需要和 template_index.md 文件中的变量对应的。
g_data_file 是一个文件名,用于把监控的数据持久化到磁盘,这样每一次执行 Python 脚本时从 g_data_file 中读取以往的数据,来计算 7 天的在线时间和 24 小时的在线时间。
g_data_list 是一个列表,用于在内存中存储监控的数据。
g_notice_enable 是一个布尔值,用于控制是否发送邮件通知。
监控的逻辑被我写成了一个纯面向过程的逻辑。
1 | def main(): |
网站状态发生改变的话,会发送邮件通知。

有兴趣的话可以看看完整的代码。
Star 一下也行
The Code
To use GitHub Actions without limits, you need a public repository.
So I had to make this solution public, even though it’s extremely ugly.

https://github.com/WANG-Guangxin/wang-guangxin.github.io
Overall Structure

This diagram is actually quite clear: GitHub Actions is responsible for running scheduled tasks, the Shell script executes hexo commands to generate static pages, and the Python script checks whether websites are online and generates a Markdown file based on the results for Hexo to render.
Below I’ll introduce these three parts one by one.
GitHub Actions
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/.github/workflows/main.yml
1 |
|
Let me briefly explain why this scheduled task runs every 15 minutes instead of every 5 minutes.
That’s because GitHub Actions’ scheduled tasks aren’t precise in timing — there’s basically always a delay. If set to every 5 minutes, many executions would actually happen 5+ minutes late, or even 10+ minutes late.
Also, in Actions’ terms of service, each Actions run is limited to 30 minutes.
To comply with the terms while making the monitoring more stable, my approach is to run Actions every 15 minutes, but each run deploys the Hexo site 3 times, 5 minutes apart, so the effective monitoring frequency is higher.
The script responsible for generating the Hexo site is build.sh, which receives 5 environment variables for configuring email notifications.
1 | - name: Build-0 |
Shell Script
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/build.sh
1 | hexo clean # Clean Hexo cache |
Let me explain the envsubst command: it replaces variables in the template file.
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/template_index.md
The template template_index.md has many shell variables, which are defined in the siteenv file.
Running envsubst < "./template_index.md" > "./source/sites/index.md" replaces the variables in template_index.md with the values from the siteenv file, generating the index.md file.
The content of the siteenv file is generated by the Python script.
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/siteenv
Python Script
https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/uptime.py
This is the core code of the entire Uptime monitoring.
There are four global variables in total: g_config, g_data_file, g_data_list, and g_notice_enable.
1 |
|
g_config is a dictionary storing the info of the websites to monitor. The key is the website’s domain, and the value is a dictionary storing the site’s status, 7-day uptime, 24-hour uptime, and whether SSL is enabled.
The value’s value is a string, designed to generate a file that can be sourced by a Linux shell.
g_config must correspond to the variables in template_index.md.
g_data_file is a filename used to persist the monitoring data to disk, so each time the Python script runs, it reads the past data from g_data_file to calculate the 7-day and 24-hour uptime.
g_data_list is a list used to store the monitoring data in memory.
g_notice_enable is a boolean controlling whether to send email notifications.
The monitoring logic is written in a purely procedural style.
1 | def main(): |
When a website’s status changes, an email notification is sent.

If you’re interested, you can look at the full code.
A star would be nice too


