最近服务器上运行了太多东西,不小心崩了一次,好在重启后恢复正常,没有出现数据丢失。这给我提了个醒,万一哪天数据真丢了那恐怕是叫天天不应,叫地地不灵,所以产生了定期备份Halo数据的想法。但是Halo官方的增强备份插件是收费的,而且也不一定支持我想用的云盘,遂考虑自己实现这个功能。

自动创建备份文件

1.21日更新:

考虑到其实每次更新往往只会更改少量内容,之前的方式每次都是备份一个新的压缩包,会导致备份很多重复内容,改进方案如下:

代码修改:

import base64
import time
import requests
import json
from datetime import datetime
from datetime import timedelta
# 网站地址
website = "http://localhost:8090"
# halo2备份文件夹路径
backup_halo_path = "/opt/1panel/apps/halo/halo/data/backups"
backup_api = website + "/apis/migration.halo.run/v1alpha1/backups"
check_api = website + "/apis/migration.halo.run/v1alpha1/backups?sort=metadata.creationTimestamp%2Cdesc"
user = "admin"
password = ""
# 获取现在的时间 2023-09-24T13:14:18.650Z
now_time = datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
seven_days_later = (datetime.now() + timedelta(minutes=2)).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
print(now_time)
# 构建认证头部
auth_header = "Basic " + base64.b64encode((user + ":" + password).encode()).decode()
payload = json.dumps({
    "apiVersion": "migration.halo.run/v1alpha1",
    "kind": "Backup",
    "metadata": {
        "generateName": "backup-",
        "name": ""
    },
    "spec": {
        "expiresAt": seven_days_later,
    }
})
headers = {
    'User-Agent': '',
    'Content-Type': 'application/json',
    'Authorization': "Basic " + base64.b64encode((user + ":" + password).encode()).decode(),
}
response = requests.request("POST", backup_api, headers=headers, data=payload)
print(response.text)
if response.status_code == 201:
    print("备份请求成功!")
    new_backup_name = ""
    while True:
        check_response = requests.request("GET", check_api, headers=headers)
        if check_response.status_code == 200:
            backup_data = json.loads(check_response.text)
            items = backup_data.get("items", [])
            if items[0]["status"]["phase"] == "SUCCEEDED":
                print("备份完成!")
                new_backup_name = items[0]["status"]["filename"]
                break
            if items[0]["status"]["phase"] == "RUNNING":
                print("正在备份!")
                time.sleep(10)

        else:
            print(f"查询备份请求失败!错误代码:{check_response.status_code}")

else:
    print(f"备份请求失败!错误代码:{response.status_code}")

主要改进思路是将缩短压缩包存在时间,改为创建压缩包后解压,备份解压后的内容,相应的shell脚本改进如下:

cd /home
python3 backup.py
cd /opt/1panel/apps/halo/halo/data/backups    #与backup_halo_path一致
unzip -o 2*  #如果附件中有文件是中文名请使用 unzip -O utf8 -o 2* 

以下是原文:

秉持着不要重复造轮子的思想(其实就是懒),在网上找到了Jevon大佬的利用aligo实现Halo自动备份数据到阿里云盘对大佬的代码略作修改后,便可实现我们想要的功能。修改后的代码如下:

import base64
import time
import requests
import json
from datetime import datetime
from datetime import timedelta
# 网站地址
website = "http://localhost:8090"
# halo2备份文件夹路径
backup_halo_path = "/opt/1panel/apps/halo/halo/data/backups"
backup_api = website + "/apis/migration.halo.run/v1alpha1/backups"
check_api = website + "/apis/migration.halo.run/v1alpha1/backups?sort=metadata.creationTimestamp%2Cdesc"
user = "admin"
password = ""
# 获取现在的时间 2023-09-24T13:14:18.650Z
now_time = datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
seven_days_later = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
print(now_time)
# 构建认证头部
auth_header = "Basic " + base64.b64encode((user + ":" + password).encode()).decode()
payload = json.dumps({
    "apiVersion": "migration.halo.run/v1alpha1",
    "kind": "Backup",
    "metadata": {
        "generateName": "backup-",
        "name": ""
    },
    "spec": {
        "expiresAt": seven_days_later,
    }
})
headers = {
    'User-Agent': '',
    'Content-Type': 'application/json',
    'Authorization': "Basic " + base64.b64encode((user + ":" + password).encode()).decode(),
}
response = requests.request("POST", backup_api, headers=headers, data=payload)
print(response.text)
if response.status_code == 201:
    print("备份请求成功!")
    new_backup_name = ""
    while True:
        check_response = requests.request("GET", check_api, headers=headers)
        if check_response.status_code == 200:
            backup_data = json.loads(check_response.text)
            items = backup_data.get("items", [])
            if items[0]["status"]["phase"] == "SUCCEEDED":
                print("备份完成!")
                new_backup_name = items[0]["status"]["filename"]
                break
            if items[0]["status"]["phase"] == "RUNNING":
                print("正在备份!")
                time.sleep(10)

        else:
            print(f"查询备份请求失败!错误代码:{check_response.status_code}")

else:
    print(f"备份请求失败!错误代码:{response.status_code}")

由于我们想要实现多重备份,光是阿里云是不够的,因此删除了源代码中阿里云备份的相关内容,同时将备份文件的存留时间改为了7天。同时还要修改

  • website 网站地址

  • backup_halo_path Halo备份的目录

  • user Halo的账号

  • password Halo的密码

理论上,在这段代码执行成功后会在指定的目录下生成zip文件,如下所示

确认这段代码能正常生成备份文件后,就可以设置shell脚本运行了,比如

cd /home 
python3 backup.py

alist的安装与使用

推荐使用docker,具体请看官方教程

安装完alist之后,就可以添加所有alist支持的网盘,这边我选择了123盘,为啥?因为它送2个T,具体设置请查看设置教程,这里我将挂载路径设置为/123

如果按照上面的方式设置,那么在alist主页应该会是这样:

点进123文件夹,里面就是你存储在123盘里的文件了。

为了方便整理,我们在123里面再创建一个backup文件夹作为备份的目录,像这样

到这,alist的设置告一段落。

2024.1.21补充:如果你的服务器在海外,最好使用海外的网盘作为备份盘。如果单看容量的话推荐Terabox,需要速度的话还是Mega啥的,国内的话首推坚果云,对海外连接很友好,每个月1g的上传流量基本够用;然后是123盘,速度勉强能看;不推荐用天翼云还有中国移动网盘啥的,非常慢,不过只是备份halo的话勉强够用。

2024.6.2补充:目前123盘的webdav改成了收费功能,不再推荐,目前来看还是坚果云最稳。

duplicati的安装与使用

首先选择一个文件夹,创建docker-compose.yml文件,具体设置如下:

version: "3"
services:
  duplicati:
    image: rob1king1/lscr.io.linuxserver.duplicati
    container_name: duplicati
    environment:
      - PUID=0
      - PGID=0
      - TZ=Asia/Shanghai
    volumes:
      - /root/Dupli/config:/config
      - /root/Dupli/backups:/backups
      - /:/source
    ports:
      - 8200:8200
    restart: unless-stopped

- /:/source 这一项很重要,是连接主机文件和duplicati的窗口,建议设置为根目录,这样可以备份主机上所有的文件。

执行 docker-compose up -d

构建成功后,就可以通过8200端口进行访问。

第一次登录duplicati会询问你是否需要设置密码,这点看个人需求,下面开始讲备份设置。

点击新增备份,设置备份名称还有加密方式:

然后设置备份的保存位置,这里存储类型选WebDAV,然后填你的服务器ip,如果按照官方设置alist的活动端口应该是5244,然后是路径,如果是像我刚刚那么设置,那么就是/dav/123/backup ,如果你做了其他修改,这里就是/dav+你设置的挂载路径+网盘中想要存储备份的位置 总之前面的/dav 必不可少。下面的用户名和密码就是alist的用户名和密码,设置完成后点击测试连接,顺利通过就是设置成功。

下面就是选择你要备份的数据了,在计算机中找到source,里面就是你之前设定的备份范围,如果是根目录应该可以在这里面找到主机上的所有文件。

最后的计划和选项根据个人需求来就好,在此略过。

最终效果如下

如果想实现多重云备份,在alist中增添新的存储后重复上面的流程即可。

ps:这套方案其实可以备份服务器上的任何数据。