配置指南

分享数据库不花钱-每天自动备份

Created: 02/10/2026

写在前面

如果你使用的数据库已经花钱开启使用了自动备份功能,那么可以忽略我这篇文章;

这篇文章主要解决咱们网站上线后,不花钱进行数据库自动备份的问题;用户数据很重要,很有必要每天备份一份,而且还不占用你本地空间。接下来跟我操作;

原理

这是PostgreSQL 数据库自动化备份方案(主要是面向Supabase、Neon数据库),通过 GitHub Actions 定时执行脚本,将备份文件自动提交到 Git 仓库中。

  • 执行环境:利用 GitHub Actions 的云端环境,无需自备服务器。
  • 备份工具:使用 pg_dump 工具进行数据库导出。
  • 定时触发:通过 GitHub Actions 的 schedule(cron)功能,每天定时运行。
  • 文件存储:备份导出的 .sql 文件按日期存储在 backups/ 目录下,并自动 commit/push 回仓库。

实操

1、github新建一个私有仓库

2、将仓库弄到本地

(1)根目录下新建 config.json

配置项说明:

  • name: 数据库的标识名称,也将作为备份文件夹名。
  • description: 项目描述,方便备注。
  • url: PostgreSQL 的连接字符串(例如:postgresql://user:password@host:port/dbname)。
  • tables: 可选。
    • null 时:执行全量备份。
    • 为数组时(如 ["users", "orders"]):仅备份指定的表。

示例 config.json

{
  "databases": [
    {
      "name": "xxx-app",
      "description": "A网站数据库 - 全量备份",
      "url": "postgresql://postgres:password@db-host:5432/postgres",
      "tables": null
    },
    {
      "name": "xxx-site",
      "description": "B网站数据库 - 指定表备份",
      "url": "postgresql://user:pass@host:5432/db",
      "tables": ["posts", "categories"]
    }
  ]
}

3、新建scripts/backup.sh(先新建scripts,再新建backup.sh)

将下面内容复制粘贴进去

#!/bin/bash
set -e

CONFIG_FILE="config.json"
BACKUP_DIR="backups"
DATE=$(date +%Y%m%d)
YEAR=$(date +%Y)
MONTH=$(date +%m)

# Cleanup logic: on the last day of the month, delete the previous month's backup directory
if [ "$(date -v+1d +%d)" = "01" ]; then
    PREV_YEAR=$(date -v1d -v-1d +%Y)
    PREV_MONTH=$(date -v1d -v-1d +%m)
    echo "Last day of the month. Cleaning up backups for $PREV_YEAR-$PREV_MONTH..."
    for DB_DIR in "$BACKUP_DIR"/*; do
        if [ -d "$DB_DIR/$PREV_YEAR/$PREV_MONTH" ]; then
            echo "Removing: $DB_DIR/$PREV_YEAR/$PREV_MONTH"
            rm -rf "$DB_DIR/$PREV_YEAR/$PREV_MONTH"
        fi
    done
fi

if [ ! -f "$CONFIG_FILE" ]; then
    echo "Error: config.json not found"
    exit 1
fi

DB_COUNT=$(jq '.databases | length' $CONFIG_FILE)
echo "Found $DB_COUNT databases to backup"

for ((i=0; i<$DB_COUNT; i++)); do
    DB_NAME=$(jq -r ".databases[$i].name" $CONFIG_FILE)
    DB_DESC=$(jq -r ".databases[$i].description" $CONFIG_FILE)
    DB_URL=$(jq -r ".databases[$i].url" $CONFIG_FILE)
    TABLES=$(jq -r ".databases[$i].tables" $CONFIG_FILE)
    
    echo "=========================================="
    echo "Backing up: $DB_NAME ($DB_DESC)"
    echo "=========================================="
    
    if [ -z "$DB_URL" ] || [ "$DB_URL" == "null" ]; then
        echo "Warning: No database URL found for $DB_NAME"
        continue
    fi
    
    mkdir -p "$BACKUP_DIR/$DB_NAME/$YEAR/$MONTH"
    BACKUP_FILE="$BACKUP_DIR/$DB_NAME/$YEAR/$MONTH/${DATE}.sql"
    
    if [ "$TABLES" == "null" ]; then
        echo "Mode: Full backup"
        pg_dump "$DB_URL" \
            --clean \
            --if-exists \
            --quote-all-identifiers \
            --no-owner \
            --no-privileges \
            -f "$BACKUP_FILE"
    else
        TABLE_ARGS=""
        TABLE_LIST=$(jq -r ".databases[$i].tables[]" $CONFIG_FILE)
        for TABLE in $TABLE_LIST; do
            TABLE_ARGS="$TABLE_ARGS -t public.$TABLE"
        done
        echo "Mode: Partial backup - tables: $TABLE_LIST"
        pg_dump "$DB_URL" \
            --clean \
            --if-exists \
            --quote-all-identifiers \
            --no-owner \
            --no-privileges \
            $TABLE_ARGS \
            -f "$BACKUP_FILE"
    fi
    
    echo "Backup saved: ${BACKUP_FILE}"
    echo "Done: $DB_NAME"
    echo ""
done

echo "All backups completed!"

4、GitHub Actions 设置

根目录下新建.github/workflows/backup.yml(先新建.github,再新建workflows,再新建backup.yml)

将下面内容复制粘贴进去

name: Daily Database Backup

on:
  schedule:
    - cron: '0 2 * * *'
  workflow_dispatch:

permissions:
  contents: write

jobs:
  backup:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
        
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y jq
          
      - name: Run backup script with PostgreSQL 17
        run: |
          chmod +x scripts/backup.sh
          # 使用Docker运行PostgreSQL 17客户端
          docker run --rm -v $(pwd):/workspace -w /workspace \
            postgres:17 bash -c "apt-get update && apt-get install -y jq && ./scripts/backup.sh"
          
      - name: Commit and push backups
        run: |
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add backups/
          git diff --staged --quiet || git commit -m "backup: $(date +%Y-%m-%d)"
          git push
  • 定时执行:默认设置在每天协调世界时 (UTC) 02:00(北京时间 10:00)运行。【这个时间可以改】
    on:
      schedule:
        - cron: '0 2 * * *'
    
  • 手动触发:支持 workflow_dispatch,你可以在 GitHub 仓库的 Actions 标签页找到 "Daily Database Backup" 手动点击 "Run workflow" 立即执行。
  • Postgres 版本:脚本默认使用 postgres:17 镜像执行备份。

然后将其提交到仓库,然后第二天就开始执行了。

5、执行成功后,备份文件将按照以下结构生成:

backups/
└── {数据库名称}/
    └── {年}/
        └── {月}/
            └── {年月日}.sql

6、安全建议 (重要)

  • 私有仓库:务必将此仓库设为 Private(私有),因为 config.json 中包含数据库的明文密码。