Typecho 是传统的基于 php 的博客系统,该系统主要由两部分组成,一部分是站点文件,另外一部分是数据库
要实现 Typecho 的双机灾备与故障转移,我们需要确保站点文件和数据库的同步与高可用切换能力
架构目标#
- 两台服务器:主机(A)+ 备机(B)
- 主机故障时,备机能够自动/手动接管服务
要求具备以下能力:
- Typecho 站点文件的一致性
- 数据库数据的同步
- 域名或负载均衡的快速切换
站点文件的同步策略#
使用 inotifywait 搭配 rsync,首先在主机(A)上执行:
apt update
apt install inotify-tools -ybash之后编写一个同步脚本:
#!/bin/bash
WATCH_DIR="/var/www/typecho"
REMOTE="<备机(B)>:/var/www/typecho"
inotifywait -mrq -e modify,create,delete,move "$WATCH_DIR" | while read path action file; do
echo "Detected change: $action $file"
rsync -az --delete "$WATCH_DIR"/ $REMOTE
donesh其中的 <备机(B)> 要替换成对于的 IP,并且在主机(A)上配置好密钥验证或者证书验证,确保其能正常通过 rsync 进行连接
之后文件会存入到备机(B)的对应 /var/www/typecho 目录中
数据库同步策略#
可以参考我写的这篇文章:
[post cid=“115” /]
需要注意的是,表同步过去了之后,在备站(B)上的数据库上,也要为 Typecho 配置对应的权限
什么意思呢,你可以打开 Typecho 的配置文件,一般来说在路径 /var/www/typecho 下,文件名叫做 config.inc.php
里面有关于数据库连接的一些配置

比如我这里的 Typecho 博客,就是以 typecho 这个用户去连接数据库的,我们在备站(B)的数据库中也要配置一个 typecho 用户,并且密码也要和配置文件里面一样,同时赋予其读 typecho* 表的权限
首先以 root 身份连接到数据库:
sudo mysql -u rootbash创建 typecho 用户,这里假设你上面查到的 Typecho 表为 typecho,密码设置为上面配置文件的密码:
CREATE USER 'typecho'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON typecho.* TO 'typecho'@'localhost';
FLUSH PRIVILEGES;sql之后重新使用 typecho 用户登录,看看能否看到表:

配置 Web 服务#
不出意外的话,现在你现在在备站(B)配置好 Web 服务,然后在云服务商将 DNS 改到备站(B)的 IP,就可以正常访问了
这个站点除了不能评论和写新文章,和主站(A)完全一样
蛤?你问我为什么只能读不能写?因为数据库是主从设计,备站(B)的数据库只能从主站(A)单向同步,本身不能推送数据到主站(A)的数据库
还有一个就是证书的问题,一般情况下,站点域名都是解析到主站的 IP 上,备用站没办法正常获取到证书(HTTP-01),只能通过 DNS-01 的方法获取证书
我比较喜欢用 Caddy,这里需要自己编译一个新的 Caddy,可以看我写的这篇文章:
[post cid=“117” /]
因为我的域名是托管在阿里云的,可以使用他们的 DNS 进行证书验证签发,你需要在 RAM 中去创建 AccessKey,得到一对:AccessKey ID 和 AccessKey Secret,并且为其最少配置对 DNS 的完全管理权
最好不要把 AccessKey ID 和 AccessKey Secret 这种比较敏感的东西直接写到 Caddyfile 中,比较推荐的方法是把变量写进 systemd 的 EnvironmentFile
在 /etc/caddy/ 目录下新建一个专门存放环境变量的文件,比如 /etc/caddy/aliyun. Env:
nano /etc/caddy/aliyun.envbash写入:
ALIYUN_ACCESS_KEY_ID=你的AccessKeyID
ALIYUN_ACCESS_KEY_SECRET=你的AccessKeySecretplaintext保存后设置权限:
sudo chmod 600 /etc/caddy/aliyun.env
sudo chown root:root /etc/caddy/aliyun.envbash修改 Caddy 的 systemd 单元文件 /etc/systemd/system/caddy.service(或 /lib/systemd/system/caddy.service,取决你之前放在哪儿)。在 [Service] 段里,加上一行:
EnvironmentFile=/etc/caddy/aliyun.envplaintext最终的(核心片段)大致长这样:
[Service]
User=caddy
Group=caddy
EnvironmentFile=/etc/caddy/aliyun.env
ExecStart=/usr/local/bin/caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile
Restart=on-failureplaintext重载,并且重启一下:
sudo systemctl daemon-reload
sudo systemctl restart caddy
sudo journalctl -u caddy -fbash这时 Caddy 启动日志不再弹出 “AccessKeyID is empty” 的错误,应能看到 solving challenges、certificate obtained successfully 等正常输出
在两台服务器上都可以进行一样的配置
切流量#
切的前提是健康检查失败,Typecho 这个博客系统本身不带有健康检查,得自己重新写一个 php 页面,可以从这个 gist 里面取: Typecho健康检查 ↗
之后放到网站根目录(/var/www/typecho)中,即可:

之后就可以开始设计切流量的脚本了,阿里云给的 Python SDK 还是比较丰富和好用的,为此,我写了一个很好用的脚本,并且可以使用 Docker 进行部署:GitHub - liueic/typecho_dnstypecho ↗



检验效果#
可以在主站直接停掉 MariaDB,这样话 Health Check 就通不过,就可以伪造出站点垮了的效果
systemctl stop mariadbbash测试完了不要忘记重新启动数据库:
systemctl start mariadbbash