备份服务器数据到阿里云盘

背景

为了防止重要数据丢失,必须进行备份,备份最保险的措施就是异地备份。即使本地组成最安全的磁盘阵列,依然可能被一锅端。文章将介绍如何通过 OpenList + 阿里云盘异地备份重要数据。

环境

  • 操作系统:debian12

安装 openlist

最简单最安全的方式是使用 docker 安装 openlist。docker-compose.yaml 文件内容如下:

services:
  openlist:
    image: 'openlistteam/openlist:latest'
    container_name: openlist
    user: '1001:1001' # Please replace `0:0` with the actual user ID and group ID you want to use to run OpenList.
    volumes:
      - './data:/opt/openlist/data'
    ports:
      - '5244:5244'
    environment:
      - UMASK=022
      - TZ=Asia/Shanghai
      - OPENLIST_ADMIN_PASSWORD=password
    restart: unless-stopped

执行如下命令启动 OpenList:

# 启动之前先修改 data 目录的权限
chown -R 1001:1001 ./data
docker compose up -d

在 OpenList 中挂载阿里云盘

根据官方文档进行操作即可。假设

设置 OpenList 的 WabDav 权限

根据官方文档 操作即可。

上传文件到 OpenList

假设服务器的地址是: docker.local.com:5244,阿里云盘映射到 OpenList 的名称是:aliyun-drive。有两种方式上传文件:

  1. curl
  2. rclone

curl 上传文件

使用 curl 上传:

curl -T size_60MB.txt -u <username>:<password> http://docker.local.com:5244/dav/aliyun-drive/

使用 curl 命令测试的时候,URL 最后面的 / 不能够少,表示上传文件到 aliyun-drive 文件夹。如果不加最后的 / ,表示上传文件到 openlist 的根目录,并将 size_60MB.txt 重命名为 aliyun-drive

rclone 上传文件

安装 rclone 命令:

apt install -y rclone

安装成功之后,可以通过 rclone config 交互式命令配置 rclone,也可以在 ~/.config/rclone/rclone.conf 文件中直接写入配置

# openlist 是名称,随意命名
[openlist]
type = webdav
url = http://docker.local.com:5244/dav
vendor = other
user = admin
pass = 2SkGONIcZ4HcPItSBDN8O26ThYY4AV_C

配置文件中的密码是加密后的密码,可以通过如下命令对密码进行加密:

rclone obscure 'mypassword'

将加密后的密码放入到 ~/.config/rclone/rclone.conf 文件的 pass

使用 rclone 上传文件:

rclone copy size_60MB.txt openlist:aliyun-drive --progress

对文件进行加密

加密方式有两种: 对称加密和非对称加密。

  • 对称加密速度快,适合加密大文件
  • 非对称加密更安全,但是不适合加密大文件

备份文件的大小通常都比较大,应当使用对称加密。如果每次备份文件使用的对称加密的密钥都相同,某个文件被破解,其他使用相同密钥加密的文件也被破解了,因此每次加密文件使用的对称加密的密钥应当不同。

每次加密的密钥都不相同,如何管理这些密钥呢?答案是:使用非对称加密的公钥对对称加密的密钥进行加密,并将加密后的密钥与备份文件放在一个压缩包中,这就是对称加密和非对称加密的混合加密方式。

使用混和加密时,一定一定要保管好非对称加密的私钥,私钥丢了,那就一点办法都没有了,以目前计算机的算力是无法破解的。私钥可以保存到自己的计算机或者是 U 盘上。

混和加密的步骤如下:

1. 生成 RSA 密钥对

生成私钥

openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
  • genpkey: 表示生成私钥
  • -algorithm RSA: 表示使用 RSA 非对称加密算法
  • -out private.pem: 输出的私钥保存到 private.pem 文件中
  • -pkeyopt rsa_keygen_bits:2048: 表示生成的 RSA 密钥的大小为 2048 位。密钥长度越长,安全性越高,但生成和加解密运算时消耗的资源也越多。2048 位是目前推荐的最低安全密钥长度。

导出公钥

openssl rsa -in private.pem -pubout -out public.pem
  • rsa: 执行 rsa 非对长加密算法的相关操作
  • -pubout: 执行输出公钥的操作
  • -out public.pem: 输出的公钥保存到 public.pem 文件中
  • -in private.pem: 从 private.pem 文件中提取公钥

2. 生成随机 AES 密钥

openssl rand -out aes.key 32
  • rand: 表示生成随机字节
  • -out aes.key: 表示将生成的随机字节写入到 aes.key 文件中
  • 32 表示 32 个字节,即 256 位,$2^{256}$,这是 AES 加密支持的最大长度

3. 使用 AES 密钥加密文件

openssl enc -aes-256-cbc -pbkdf2 \
  -in plain.txt \
  -out data.enc \
  -pass file:./aes.key
  • enc: 表示执行加密操作
  • -aes-256-cbc: 指定加密算法:AES,使用 256 位密钥长度,工作模式为 CBC(Cipher Block Chaining,密码块链模式)
  • -pbkdf2: 指定使用 PBKDF2(Password-Based Key Derivation Function 2)作为密钥派生函数。这使得基于密码的加密更安全,增加了抗暴力破解能力。默认情况下,openssl enc 以前不使用 PBKDF2,而是用较弱的 EVP_BytesToKey,现代实践推荐加上此选项。
  • -out data.enc: 表示密文写入到 data.enc 文件中
  • -in plain.txt: 表示待加密的文件
  • -pass file:./aes.key: 表示从 aes.key 文件中读取密码。pass 选项有三种传递密码的方式:
    • 直接传递密码:pass:<password>
    • 文件读取密码:file:/path/to/file
    • 读取环境变量:evn:<Variable>

4. 使用公钥加密 AES 密钥

openssl pkeyutl -encrypt -pubin -inkey public.pem -in aes.key -out aes.key.encrypted
  • pkeyutl: 表示执行非对称加解密相关操作
  • -encrypt:加密操作
  • -pubin:表示使用公钥加密
  • -inkey public.pem:公钥文件
  • -in aes.key:需要机密的数据。
  • -out aes.key.encrypted:将加密后的数据写入 aes.key.encrypted 文件中。

5.将加密后的文件和加密后的密钥一起打包

mkdir backup-2026-01-08
mv data.enc aes.key.encrypted backup-2026-01-08
tar -czvf backup-2026-01-08.tar.gz backup-2026-01-08

对文件进行解密

1. 解压文件

tar -xvf backup-2026-01-08.tar.gz

2. 使用私钥解密 AES 密钥

cd backup-2026-01-08
openssl pkeyutl -decrypt \
  -inkey private.pem \
  -in aes.key.encrypted \
  -out aes.key
  • pkeyutl: 非对称加解密相关工具
  • -decrypt: 执行解密操作
  • -inkey private.pem: 密钥文件路径
  • -in aes.key.encrypted: 加密文件路径
  • -out aes.key: 解密后的数据写入到 aes.key 文件中

3. 使用 AES 密钥解密文件

openssl enc -d -aes-256-cbc -pbkdf2 \
  -in data.enc \
  -out plain.txt \
  -pass file:./aes.key
  • enc -d: 执行解密操作
  • -aes-256-cbc: 指定加密算法:AES,使用 256 位密钥长度,工作模式为 CBC(Cipher Block Chaining,密码块链模式)
  • -pbkdf2: 指定使用 PBKDF2(Password-Based Key Derivation Function 2)作为密钥派生函数。这使得基于密码的加密更安全,增加了抗暴力破解能力。默认情况下,openssl enc 以前不使用 PBKDF2,而是用较弱的 EVP_BytesToKey,现代实践推荐加上此选项。
  • -in data.enc: 加密文件
  • -out plain.txt: 解密后的内容输出到 plain.txt 文件中
  • -pass file:./aes.key: 从 aes.key 文件中读取密钥。pass 选项有三种传递密码的方式:
    • 直接传递密码:pass:<password>
    • 文件读取密码:file:/path/to/file
    • 读取环境变量:evn:<Variable>

4. 检查文件是否成功解密

cat plain.txt

备份文件

工具都准备好后,就可以备份重要文件了,备份步骤:

  1. 打包重要文件
  2. 对重要文件进行加密
  3. 上传加密后的文件到阿里云盘
  4. 删除阿里云盘中过期的备份文件

假设我需要备份服务器上的 ~/docker/minio 文件夹

# -C 参数表示先进入 ~/docker 文件夹,再进行打包
# 这样解压 minio.tar.gz 文件时,解药出来的就是 minio 而不是 docker/minio
tar -czvf minio.tar.gz -C ~/docker minio

# 生成 AES 密钥
openssl rand -out aes.key 32

# 使用 AES 密钥对 minio.tar.gz 文件加密
openssl enc -aes-256-cbc -pbkdf2 \
  -in minio.tar.gz \
  -out minio.tar.gz.enc \
  -pass file:./aes.key
 
# 从私钥中导出公钥
openssl rsa -in private.pem -pubout -out public.pem

# 使用公钥对 AES 密钥加密
openssl pkeyutl -encrypt -pubin -inkey public.pem -in aes.key -out aes.key.enc

# 将备份文件以及密钥放入到一个压缩包中
mkdir backup-2026-01-08
mv minio.tar.gz.enc aes.key.enc backup-2026-01-08
tar -czvf backup-2026-01-08.tar.gz backup-2026-01-08

# 将备份文件通过 openlist 上传到阿里云盘
rclone copy backup-2026-01-08.tar.gz openlist:aliyun-drive --progress

# 删除阿里云盘中七天以前的备份
rclone delete "openlist:aliyun-drive/" --min-age 7d --include "backup-*.tar.gz" -v

# 清理本地不必要的文件
rm -rf aes.key backup-2026-01-08 backup-2026-01-08.tar.gz minio.tar.gz public.pem

恢复备份文件

# 解压备份文件
tar -xvf backup-2026-01-08.tar.gz

# 使用私钥解密加密的 AES 密钥
openssl pkeyutl -decrypt \
  -inkey private.pem \
  -in backup-2026-01-08/aes.key.enc \
  -out aes.key

# 使用 AES 密钥解密备份文件
openssl enc -d -aes-256-cbc -pbkdf2 \
  -in backup-2026-01-08/minio.tar.gz.enc \
  -out minio.tar.gz \
  -pass file:./aes.key

# 解压备份文件
tar -xvf minio.tar.gz
使用 Hugo 构建
主题 StackJimmy 设计