接上一篇,将能迁移的服务都迁移到PostgreSQL后,再配置上自动备份脚本,基本上就可以高枕无忧了,本来想备份到阿里云OSS的,想了想本站几乎是ALL IN Cloudflare,那就直接备份到CloudFlare R2吧,正好也快一点。下面就记录下备份的方法。

创建CloudFlare R2桶

在面板首页->存储和数据库 -> R2对象存储中,创建一个桶,我起的名字就是backup

创建桶

创建完成后发,返回桶列表,点击右下角的Account Deatails下面的Manage,按钮,创建一个Token。

创建Token

1、权限必须是管理员读和写,选对象读和写执行rclone命令会报权限错误。

2、因为1,所以最好将客户端IP限制一下,反正VPS都是静态的IP地址,不然要是被泄露了那就完犊子了~

创建好后,给你三个信息,分别是访问密钥 ID(access_key_id)机密访问密钥(secret_access_key)为 S3 客户端使用管辖权地特定的终结点(endpoint)。暂时记录下来,下一步要用。

安装Rclone

要备份到CloudFlare R2,那就需要Rclone,执行下面的命令安装即可。

1
apt install rclone

安装完成后,执行rclone config就可以配置了,不过控制台看着乱糟糟的,我直接选创建配置文件的方式了。

1
touch ~/.config/rclone/rclone.conf

然后在里面填写如下信息:

1
2
3
4
5
6
7
8
[r2-remote]
type = s3
provider = Cloudflare
access_key_id = <你的访问密钥>
secret_access_key = <你的机密访问密钥>
# 注意,不要带桶名称
endpoint = https://<Account_ID>.r2.cloudflarestorage.com
no_check_bucket = true

配置完成后,执行如下命令进行测试:

1
2
3
4
5
6
7
8
9
# 执行
rclone listremotes
# 输出
r2-remote:

# 执行
rclone lsd r2-remote: -vv
# 输出
# 你自己的桶,其中需要包含刚才创建的

配置脚本

PostgreSQL

/data/script/中创建pgsql-to-r2.sh文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

# --- 配置区 ---
CONTAINER_NAME="postgresql"
DB_USER="postgres"
BACKUP_DIR="/data/backups/pgsql"
DATE=$(date +%Y%m%d_%H%M%S)
FILE_NAME="pg_all_backup_$DATE.sql.gz"
R2_BUCKET="r2-remote:backup" # rclone 配置名:桶名(backup就是刚才创建的桶)
RETENTION_DAYS=7

# --- 执行备份 ---
mkdir -p $BACKUP_DIR

echo "开始导出 ..."
docker exec -t $CONTAINER_NAME pg_dumpall -c -U $DB_USER | gzip > $BACKUP_DIR/$FILE_NAME

# --- 上传到 R2 ---
echo "正在上传 $FILE_NAME 到 Cloudflare R2..."
rclone copy $BACKUP_DIR/$FILE_NAME $R2_BUCKET/pgsql_daily/

# --- 清理旧数据 ---
echo "清理 $RETENTION_DAYS 天前的本地备份..."
find $BACKUP_DIR -mtime +$RETENTION_DAYS -exec rm {} \;

# --- 可选:清理 R2 上的旧备份 (需要 R2 支持 lifecycle 或用 rclone delete) ---
# rclone delete $R2_BUCKET --min-age ${RETENTION_DAYS}d --dry-run

echo "备份任务完成!"

测试

1
bash pgsql-to-r2.sh

MySQL

/data/script/中创建mysql-to-r2.sh文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash

# --- 1. 配置区 ---
CONTAINER_NAME="db" # 你的 MySQL 容器名
DB_USER="root"
DB_PASSWORD="password"
BACKUP_DIR="/data/backups/mysql"
DATE=$(date +%Y%m%d_%H%M)
R2_REMOTE="r2-remote:backup"
RETENTION_DAYS=7

# 需要备份的数据库列表
DATABASES=("db1" "db2")

# --- 2. 准备工作 ---
mkdir -p $BACKUP_DIR
echo "[$DATE] 开始执行 MySQL 分库备份..."

# --- 3. 循环备份 ---
for DB in "${DATABASES[@]}"; do
FILE_NAME="${DB}_${DATE}.sql.gz"
echo "正在备份 MySQL 数据库: $DB..."

# 使用 mysqldump 并直接 gzip 压缩
# --single-transaction: 保证备份期间不锁表(针对 InnoDB)
# --routines: 备份存储过程和函数
docker exec $CONTAINER_NAME mysqldump -u$DB_USER -p$DB_PASSWORD \
--single-transaction --routines --databases $DB | gzip > $BACKUP_DIR/$FILE_NAME

if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo "上传 $FILE_NAME 到 R2..."
rclone copy $BACKUP_DIR/$FILE_NAME $R2_REMOTE/mysql_daily/
else
echo "错误: $DB 备份失败!"
fi
done

# --- 4. 清理 ---
find $BACKUP_DIR -mtime +$RETENTION_DAYS -exec rm {} \;
echo "MySQL 备份任务完成。"

执行测试

1
bash mysql-to-r2.sh

配置定时计划

1
cronteb -e

填写如下内容:

1
2
3
4
5
# 凌晨 02:00 备份 PostgreSQL
0 2 * * * /bin/bash /data/script/pgsql-to-r2.sh >> /var/log/pg_backup.log 2>&1

# 凌晨 03:00 备份 MySQL
0 3 * * * /bin/bash /data/script/mysql-to-r2.sh >> /var/log/mysql_backup.log 2>&1

配置对象生命周期规则

数据库文件比较小,乐意放几天放几天。我的习惯,30天肯定至少要访问一次的,所以就30天了。

image-20260318215913289