📢 新文章推送 · 每周更新优质内容 · 订阅更新 →
向下滚动
开发编程

Lumin Admin 备份还原系统:全站数据安全保障

AI 智能总结

Lumin Admin 备份还原系统:全站数据安全保障

📌 概述

备份还原系统是博客数据安全的核心保障,支持一键全站备份、从备份恢复、自动定时备份、云存储备份等功能。所有备份文件以 tar.gz 格式存储,包含站点内容和配置的完整快照。

本功能基于 Node.js child_process.execSync 调用系统 tar 命令实现打包,备份文件存储在 admin/_backups/ 目录。

一、功能概览

功能说明
一键全站备份将 content、static、hugo.toml、config 打包为 tar.gz
备份恢复从备份文件还原全站数据
备份下载下载备份文件到本地
备份删除删除不需要的备份
自动备份支持每天/每周/每月自动备份
保留策略可设置保留份数(1-50)
云存储备份可选择已配置的图床作为备份存储

二、后端实现

2.1 备份目录与配置

1const BACKUP_DIR = join(ROOT, 'admin', '_backups')
2const BACKUP_CONFIG = join(ROOT, 'admin', 'backupConfig.json')

备份配置结构:

1{
2  "autoBackup": false,
3  "interval": "daily",
4  "retention": 10,
5  "cloudProvider": ""
6}

2.2 创建备份

 1app.post('/api/backup/create', (req, res) => {
 2  const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)
 3  const filename = `backup-${ts}.tar.gz`
 4  const filepath = join(BACKUP_DIR, filename)
 5
 6  const dirsToBackup = ['content', 'static', 'hugo.toml', 'config']
 7    .filter(d => existsSync(join(ROOT, d)))
 8
 9  execSync(`tar -czf "${filepath}" -C "${ROOT}" ${dirsToBackup.join(' ')}`, {
10    cwd: ROOT,
11    shell: true
12  })
13
14  const stat = statSync(filepath)
15  ok(res, { filename, size: stat.size, created: new Date().toISOString() })
16})

备份文件命名格式:backup-2026-05-22T12-30-00.tar.gz

2.3 备份范围

目录/文件说明是否必须存在
content/所有文章内容
static/静态资源
hugo.toml站点配置
config/额外配置目录否(如存在则包含)

2.4 恢复备份

1app.post('/api/backup/restore/:filename', (req, res) => {
2  const fp = join(BACKUP_DIR, req.params.filename)
3  if (!fp.startsWith(BACKUP_DIR)) return fail(res, 403, 'Access denied')
4  if (!existsSync(fp)) return fail(res, 404, 'Backup not found')
5
6  execSync(`tar -xzf "${fp}" -C "${ROOT}"`, { cwd: ROOT, shell: true })
7  ok(res, { status: 'ok' })
8})

2.5 备份列表

 1app.get('/api/backup/list', (req, res) => {
 2  const files = readdirSync(BACKUP_DIR)
 3    .filter(f => f.endsWith('.tar.gz'))
 4    .map(name => {
 5      const fp = join(BACKUP_DIR, name)
 6      const s = statSync(fp)
 7      return { filename: name, size: s.size, created: s.mtime.toISOString() }
 8    })
 9    .sort((a, b) => b.created.localeCompare(a.created))
10  ok(res, { files })
11})

2.6 安全措施

 1// 路径安全检查:确保文件路径在备份目录内
 2app.delete('/api/backup/:filename', (req, res) => {
 3  const fp = join(BACKUP_DIR, req.params.filename)
 4  if (!fp.startsWith(BACKUP_DIR)) return fail(res, 403, 'Access denied')
 5  // ...
 6})
 7
 8// 下载接口:使用 res.download() 确保安全
 9app.get('/api/backup/download/:filename', (req, res) => {
10  const fp = join(BACKUP_DIR, req.params.filename)
11  if (!fp.startsWith(BACKUP_DIR)) return res.status(403).json({ error: 'Access denied' })
12  res.download(fp, req.params.filename)
13})

2.7 API 接口

接口方法说明
/api/backup/configGET获取备份配置
/api/backup/configPUT更新备份配置
/api/backup/createPOST创建全站备份
/api/backup/listGET获取备份列表
/api/backup/:filenameDELETE删除备份
/api/backup/restore/:filenamePOST从备份恢复
/api/backup/download/:filenameGET下载备份文件

三、前端实现

3.1 页面布局

 1┌──────────────────────────────┐  ┌──────────────────┐
 2│  📦 备份文件                  │  │  ⚙️ 备份设置      │
 3│                              │  │                  │
 4│  [立即备份]                   │  │  自动备份 [开关]  │
 5│                              │  │  备份频率 [选择]  │
 6│  文件名    大小  时间   操作   │  │  保留份数 [数字]  │
 7│  backup-1  390M  12:00 ...   │  │  云存储   [选择]  │
 8│  backup-2  385M  11:00 ...   │  ├──────────────────┤
 9│                              │  │  📊 备份统计      │
10│                              │  │  备份总数: 2      │
11│                              │  │  占用空间: 775MB  │
12│                              │  │  最近备份: 12:00  │
13└──────────────────────────────┘  └──────────────────┘

3.2 恢复确认

恢复操作需要二次确认,防止误操作:

1async function restoreBackup(row) {
2  await ElMessageBox.confirm(
3    `确定从备份 ${row.filename} 恢复?当前数据将被覆盖!`,
4    '确认恢复',
5    { type: 'warning', confirmButtonText: '确认恢复', cancelButtonText: '取消' }
6  )
7  await restoreBackupApi(row.filename)
8  ElMessage.success('恢复成功,建议重启服务')
9}

3.3 云存储备份

备份设置中的「云存储备份」选项,动态获取已配置的图床列表:

1async function loadCloudProviders() {
2  const res = await getImageHostingProviders()
3  cloudProviders.value = Object.values(res.data.providers || {})
4    .filter(p => p.configured && p.enabled)
5}

3.4 备份统计

1const totalSize = computed(() =>
2  backups.value.reduce((sum, b) => sum + (b.size || 0), 0)
3)

四、后续规划

  • 增量备份:仅备份变更文件,减小备份体积
  • 定时自动备份:基于调度器实现,按配置频率自动执行
  • 云存储上传:备份完成后自动上传到配置的图床
  • 备份加密:对备份文件进行加密保护
  • 备份对比:对比两个备份之间的差异

五、文件变更清单

文件变更
admin/backend/server.js新增 7 个备份 API
admin/frontend/src/views/Backup/Index.vue新建备份还原页面
admin/frontend/src/api/index.js新增 7 个备份 API 函数
admin/frontend/src/router/index.js/backup 路由从 Placeholder 改为真实页面
admin/frontend/src/layouts/MainLayout.vue菜单从「备份」改为「备份还原」
admin/_backups/备份文件存储目录
admin/backupConfig.json备份配置文件
版权声明

本文作者 Lumin

本文链接 https://www.zhengquan.xyz/code/lumin-admin-backup/

许可协议 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

请作者喝杯咖啡 ☕

  • 微信打赏
    微信支付
  • 支付宝打赏
    支付宝
点击按钮查看打赏二维码
🎁 推荐工具
试试这些实用在线工具,提升工作效率
前往工具集 →

留言评论

期待你的想法

评论加载中