解放双手!使用 Shell 脚本将 VPS 数据每日自动备份到 Telegram

Author Avatar
青枫 6月20日
  • 在其它设备中阅读本文章

作为一名站长或开发者,服务器数据的安全性是我们永远不能忽视的生命线。无论是硬件故障、软件 Bug 还是恶意攻击,都可能导致我们数小时甚至数月的心血付之一炬。

传统的备份方案可能涉及另一台服务器或昂贵的商业对象存储,但今天,我将向大家分享一个极具性价比且高效的终极解决方案:将 VPS 的关键数据每日自动打包、加密,并上传到 Telegram 的无限云存储中!

💡 为什么选择 Telegram?

  • 免费云存储 :Telegram 的“保存的消息”和私密频道,就是一个无限容量的个人云盘。
  • 即时通知 :备份成功后,文件会立刻推送到您的客户端,让您随时掌控备份状态。
  • 异地容灾 :将备份存放在与 VPS 完全隔离的第三方服务上,是最佳的容灾实践。
  • 安全可靠 :配合强大的 GPG 加密,即使 Telegram 服务器数据泄露,我们的备份内容也安然无恙。

✨ 方案亮点

我们即将打造的这套自动化备份系统,是一个生产级别的解决方案,具备以下特点:

  • 全自动化 :一次配置,每日通过 Cron 自动执行,无需人工干预。
  • 🔐 强加密 :使用 GPG 对备份文件进行对称加密,没有密码谁也无法查看。
  • 📦 完整打包 :支持同时备份多个网站目录、配置文件和 MySQL/PostgreSQL 数据库。
  • 🪓 大文件支持 :自动分割超过 2GB(Telegram 非会员限制)的大文件,确保上传成功。
  • 🧹 自动清理 :备份上传后自动删除本地临时文件,不占用服务器宝贵空间。
  • 💡 环境兼容:完美解决在 Cron 或宝塔面板等非交互式环境中 HOME 变量缺失导致程序出错的问题。
  • 📜 日志记录 :可将执行日志输出到文件,方便排查问题。

⚙️ 准备工作

在正式开始之前,我们需要确保服务器上已安装好必要的工具,并获取到关键的 Telegram 频道 ID。整个准备过程分为以下两个步骤。

1. 安装所需工具

  • ① TDL (Telegram 客户端)
    一个强大的 Telegram 命令行客户端,是上传文件的核心。请参照其 官方文档 完成安装和登录授权。
  • ② GnuPG (加密工具)
    用于对备份文件进行加密,保障数据安全。

    # Debian/Ubuntu 系统
    sudo apt update && sudo apt install -y gpg
    
    # CentOS/RHEL 系统
    sudo yum install -y gnupg2
  • ③ 数据库客户端
    用于导出数据库。通常已预装,如果没有,请根据您的数据库类型安装。

    # MySQL/MariaDB
    sudo apt install -y mysql-client
    
    # PostgreSQL
    sudo apt install -y postgresql-client

2. 获取 Telegram 频道 ID

这是脚本用来定位备份文件存放地的关键标识。我们提供两种方法来获取它。

方法一:从网页版 URL 获取 (最推荐)

  1. 创建频道 :在您的任意 Telegram 客户端创建一个 私密频道 ,并确保您已加入。
  2. 登录网页版:在电脑浏览器中,访问并登录 Telegram 网页版:https://web.telegram.org/a/
  3. 定位 ID:登录后,点击您创建的私密频道。此时,浏览器的地址栏会显示类似下方的 URL:

    https://web.telegram.org/a/#-1002759598666

  4. 提取纯数字 ID
    • URL 中井号#后面的 -1002759598666 是频道的完整 ID。
    • 关键一步 :我们需要 去掉前面的 -100 前缀 ,只保留后面的纯数字部分。
    • 例如,从 -1002759598666 中,我们提取出 2759598666

方法二:从桌面客户端获取

  1. 开启实验性功能 :进入 设置 高级 实验功能 ,勾选 在资料中显示对话 ID
  2. 查看并提取 ID:打开您的私密频道,进入其 资料页,会看到如 Channel ID: 2759598666 的信息。

👉 最终确认:脚本里到底填什么?

无论您使用哪种方法,请务必记住:在脚本的 TG_CHAT_ID 配置项中,仅填写那串纯数字 ,不带任何前缀或符号。

正确示例TG_CHAT_ID="2759598666"


📜 核心脚本

这是我们整个方案的核心。首先,创建脚本文件并赋予执行权限。

# 创建脚本存放目录
sudo mkdir -p /opt/scripts

# 创建脚本文件并赋予执行权限
sudo touch /opt/scripts/backup_to_telegram.sh
sudo chmod +x /opt/scripts/backup_to_telegram.sh

然后,将下面的完整脚本内容粘贴到 /opt/scripts/backup_to_telegram.sh 文件中。

#!/bin/bash

# =================================================================
# VPS Backup to Telegram Script (with File Splitting & CRON Fix)
# Author: Your Name/Blog URL
# Version: 2.1
# Description: A robust script to backup, encrypt, split large files,
#              and upload to Telegram via tdl.
# =================================================================

# !!! 关键修复:为非交互式环境(如Cron/宝塔面板)指定HOME目录 !!!
# tdl 需要 $HOME 目录来寻找其配置文件和会话数据
export HOME=/root

# --- 配置区域 START (请根据您的实际情况修改) ---

# 1. 需要备份的目录 (多个目录用空格隔开)
# 例如: BACKUP_SRC_DIRS="/var/www/my_site /etc/nginx"
BACKUP_SRC_DIRS="/var/www/html /etc/nginx/sites-available"

# 2. 数据库配置 (如果不需要备份数据库,请将 DB_USER 留空)
DB_USER="your_db_user"
DB_PASS="your_db_password"
DB_NAME="your_db_name"
DB_TYPE="mysql" # 可选 "mysql" 或 "postgres"

# 3. Telegram 配置
# 在这里填入您上一步获取到的纯数字ID
TG_CHAT_ID="YOUR_CHAT_ID" 
# Telegram 单文件上传大小限制 (非会员约 1.9GB)
UPLOAD_LIMIT_BYTES=2040109465

# 4. 加密配置
# !!! 重要 !!! 请设置一个强密码用于加密备份文件
# 这个密码是您未来解密备份的唯一凭证,请务必妥善保管在安全的地方!
GPG_PASSPHRASE="A_VERY_STRONG_AND_SECRET_PASSWORD"

# 5. 临时文件和备份命名
TMP_DIR="/tmp/backup_$$" # $$ 表示当前脚本的进程ID,保证并发执行时目录唯一
BACKUP_FILENAME_PREFIX="vps_backup"

# --- 配置区域 END ---


# --- 脚本主体 (一般无需修改) ---
set -e
set -o pipefail

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}

cleanup() {
    if [ -d "$TMP_DIR" ]; then
        log "正在清理临时文件..."
        # 额外清理可能产生的分卷文件和临时包
        rm -rf "$TMP_DIR" /tmp/${BACKUP_FILENAME_PREFIX}_*.tar.gz*
        log "清理完成。"
    fi
}
trap cleanup EXIT

log "备份任务开始 (V2.1 - 支持大文件分割)..."

log "创建临时工作目录: $TMP_DIR"
mkdir -p "$TMP_DIR"

log "正在备份指定的目录..."
for src_dir in $BACKUP_SRC_DIRS; do
    if [ -d "$src_dir" ]; then
        cp -r "$src_dir" "$TMP_DIR/"
        log "  - 已备份: $src_dir"
    else
        log "  - 警告: 目录不存在,已跳过: $src_dir"
    fi
done

if [ -n "$DB_USER" ]; then
    log "正在备份数据库: $DB_NAME..."
    DB_BACKUP_FILE="$TMP_DIR/${DB_NAME}.sql"
    case "$DB_TYPE" in
        mysql) mysqldump -u"$DB_USER" -p"$DB_PASS" --single-transaction --routines --triggers "$DB_NAME" > "$DB_BACKUP_FILE";;
        postgres) PGPASSWORD="$DB_PASS" pg_dump -U "$DB_USER" -d "$DB_NAME" -f "$DB_BACKUP_FILE";;
        *) log "错误: 不支持的数据库类型 '$DB_TYPE'。"; exit 1;;
    esac
    log "数据库备份完成。"
fi

TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
ARCHIVE_NAME="${BACKUP_FILENAME_PREFIX}_${TIMESTAMP}.tar.gz"
ARCHIVE_PATH="/tmp/${ARCHIVE_NAME}"
log "正在打包压缩成: $ARCHIVE_PATH"
tar -zcvf "$ARCHIVE_PATH" -C "$TMP_DIR" . > /dev/null

ENCRYPTED_ARCHIVE_PATH="${ARCHIVE_PATH}.gpg"
log "正在加密备份文件: $ENCRYPTED_ARCHIVE_PATH"
gpg --symmetric --batch --yes --passphrase "$GPG_PASSPHRASE" -o "$ENCRYPTED_ARCHIVE_PATH" "$ARCHIVE_PATH"

log "检查文件大小并准备上传..."
FILE_SIZE=$(stat -c%s "$ENCRYPTED_ARCHIVE_PATH")

if [ "$FILE_SIZE" -gt "$UPLOAD_LIMIT_BYTES" ]; then
    SPLIT_SIZE="1900M" 
    log "文件大小 ($((FILE_SIZE / 1024 / 1024)) MB) 超过限制,将分割成 ${SPLIT_SIZE} 的分卷。"
    
    # 使用split进行分割,并生成有意义的分卷名
    split -b "$SPLIT_SIZE" -d -a 2 --additional-suffix=.part "$ENCRYPTED_ARCHIVE_PATH" "${ARCHIVE_PATH}.gpg."
    
    log "文件分割完成,开始逐个上传分卷..."
    PART_COUNT=$(find /tmp -name "${ARCHIVE_NAME}.gpg.*.part" | wc -l)
    CURRENT_PART=1

    for part_file in $(find /tmp -name "${ARCHIVE_NAME}.gpg.*.part"); do
        log "正在上传分卷 $CURRENT_PART/$PART_COUNT: $(basename "$part_file")"
        tdl up -p "$part_file" -c "$TG_CHAT_ID"
        log "分卷 $CURRENT_PART/$PART_COUNT 上传成功。"
        rm -f "$part_file"
        CURRENT_PART=$((CURRENT_PART + 1))
    done
else
    log "文件大小 ($((FILE_SIZE / 1024 / 1024)) MB) 未超过限制,直接上传。"
    tdl up -p "$ENCRYPTED_ARCHIVE_PATH" -c "$TG_CHAT_ID"
fi

log "所有文件上传成功!"

rm -f "$ARCHIVE_PATH" "$ENCRYPTED_ARCHIVE_PATH"
log "本地的原始压缩包和加密包已删除。"

log "备份任务圆满完成!"
exit 0

🚀 部署与自动化

脚本配置完成后,我们只需三步即可实现全自动运行。

  1. 修改配置
    使用文本编辑器(如vimnano)打开 /opt/scripts/backup_to_telegram.sh,仔细修改顶部的“配置区域”,填入您自己的目录、数据库信息、Telegram 频道 ID 和 一个强壮的加密密码
  2. 手动测试
    在终端执行一次脚本,确保一切正常。
    /opt/scripts/backup_to_telegram.sh

    观察日志输出,并检查您的 Telegram 频道是否收到了备份文件。

  3. 设置定时任务 (Cron Job)
    执行 crontab -e 并添加以下一行,以设置每天凌晨 4 点执行备份:
    0 4 * * * /opt/scripts/backup_to_telegram.sh >> /var/log/backup_telegram.log 2>&1

    命令解释 >> /var/log/backup_telegram.log 2>&1 会将脚本的所有输出(包括正常信息和错误信息)都追加到日志文件中,这对于日后排查问题至关重要。

    如果您使用 宝塔面板,可以在“计划任务”中添加一个 Shell 脚本任务,执行周期设置为每天,脚本内容填入 /opt/scripts/backup_to_telegram.sh 即可。


🔧 如何恢复备份

备份的最终目的是恢复。以下是在不同操作系统上恢复数据的指南。

在 Linux / macOS 上恢复

  1. 下载文件:从 Telegram 下载所有备份文件(单个.gpg文件或多个.partXX文件)到同一目录。
  2. 合并文件 (如果被分割):

    # 使用通配符自动按顺序合并所有part文件
    cat vps_backup_*.part* > backup_merged.gpg
  3. 解密文件

    # 提示输入密码时,输入您在脚本中设置的GPG_PASSPHRASE
    gpg -o backup.tar.gz -d backup_merged.gpg
  4. 解压文件
    tar -zxvf backup.tar.gz

在 Windows 上恢复

  1. 安装工具 :下载并安装 Gpg4win7-Zip
  2. 合并文件 (如果被分割):在文件所在目录打开命令提示符(CMD),执行:
    copy /b vps_backup_*.part* backup_merged.gpg
  3. 解密文件 :右键点击 .gpg 文件,选择 GpgEXKleopatra 相关的 "Decrypt" 选项,输入您的加密密码。
  4. 解压文件 :右键点击解密后得到的 .tar.gz 文件,选择 7-Zip -> 提取到...

恭喜您!现在,您已经拥有了一套强大、可靠且免费的自动化 VPS 备份方案。安心地去创造吧,数据安全已由这套系统稳稳守护!