一个面向 Linux 和 Cron 的单文件 PostgreSQL 逻辑备份工具。它逐库调用 pg_dump,可导出集群全局对象,并在校验完成后原子发布备份。
custom 和 plain 两种 PostgreSQL 原生格式。zip、files、both 三种产物模式。本项目只做逻辑备份,不提供物理备份、WAL 归档、PITR、流复制、增量备份、对象存储上传或备份加密。
需要 Bash 4.2+、PostgreSQL 客户端、flock,以及 sha256sum 或 shasum。zip、curl、Apprise 和 timeout 只在对应功能启用时需要。
Debian 或 Ubuntu:
sudo apt-get update
sudo apt-get install postgresql-client util-linux coreutils zip
脚本可以先独立检查依赖。它不会安装软件,也不会连接数据库:
bash pgsql_backup.sh --dependency-report
安装脚本:
sudo install -d -m 755 /opt/postgresql-backup &&
sudo curl -fL https://raw.githubusercontent.com/funnyzak/pgsql-onekey-backup/main/pgsql_backup.sh \
-o /opt/postgresql-backup/pgsql_backup.sh &&
sudo chmod 755 /opt/postgresql-backup/pgsql_backup.sh
下载地址使用 main 分支,每次安装都会获取最新版脚本。执行前可先打开下载地址检查脚本内容。
Homebrew 的 libpq 默认可能不在 PATH 中。按 brew info libpq 的提示加入其 bin 目录。
客户端最好与服务端使用相同主版本,至少不能比服务端旧。脚本会在连接预检时拒绝较旧的 pg_dump。
目标根目录必须提前创建,归运行脚本的用户所有,且组用户和其他用户不能写入:
install -d -m 700 /var/backups/postgresql
离线检查配置和本机依赖:
bash pgsql_backup.sh \
--target-dir /var/backups/postgresql \
--host 127.0.0.1 \
--port 5432 \
--user backup \
--passfile /etc/postgresql-backup/pgpass \
--database app \
--check
执行单库备份:
bash pgsql_backup.sh \
--target-dir /var/backups/postgresql \
--host 127.0.0.1 \
--port 5432 \
--user backup \
--passfile /etc/postgresql-backup/pgpass \
--database app
多次传入 --database 可按指定顺序备份多个数据库。不传数据库或使用 --all-databases 时,脚本通过维护库查询所有 datallowconn=true 且 datistemplate=false 的数据库。
生产环境推荐 passfile。文件必须是当前用户所有的普通文件,不能是符号链接,权限不能宽于 0600;各级父目录也不能允许组用户或其他用户写入。
127.0.0.1:5432:*:backup:replace-with-your-password
chmod 600 /etc/postgresql-backup/pgpass
bash pgsql_backup.sh \
--target-dir /var/backups/postgresql \
--passfile /etc/postgresql-backup/pgpass \
--database app
passfile 的字段顺序是 hostname:port:database:username:password。字段中的 : 写成 \:,反斜杠写成 \\。尽量使用精确的主机、端口和用户,避免通配符匹配错误凭据。
service file 可保存连接参数。显式传入的 host、port、user 会覆盖 service 中的同名值。
[backup]
host=127.0.0.1
port=5432
user=backup
dbname=postgres
bash pgsql_backup.sh \
--target-dir /var/backups/postgresql \
--service backup \
--service-file /etc/postgresql-backup/pg_service.conf \
--passfile /etc/postgresql-backup/pgpass \
--database app
显式 service file 按敏感文件检查。只指定 --service 时,也可以使用系统或用户默认的 service 配置。
export PGSQL_BACKUP_PASSWORD='replace-with-your-password'
bash pgsql_backup.sh \
--target-dir /var/backups/postgresql \
--database app
直接密码不能与 passfile 或 service 组合。脚本只对子数据库客户端进程设置 PGPASSWORD,不会把密码写入日志、manifest、通知或 Hook 环境。命令行 --password 会进入 Shell 历史和进程参数,生产环境不推荐。
未显式配置认证时,libpq 仍可读取运行用户的默认 .pgpass、service 或使用服务端免密认证。Cron 必须使用同一系统用户。
默认维护库是 postgres。不存在时显式指定:
--maintenance-database template1
--globals-mode 支持:
auto:全库模式导出 globals.sql,显式数据库模式跳过。include:始终导出全局对象。skip:始终跳过。全局对象默认使用 pg_dumpall --globals-only --no-role-passwords。--include-role-passwords 会把角色密码哈希写入 globals.sql,只应在明确评估风险后使用。
单个 pg_dump 使用一致快照;多个数据库按顺序导出,不保证跨库同一时点一致。严格一致的业务应由外部流程管理停写和恢复、安排维护窗口,或改用物理备份。不要把前置 Hook 和发布后 Hook 当成必定成对执行的停写机制。
--format 决定数据库文件格式:
custom:默认,扩展名 .dump,可用 pg_restore 选择性或并行恢复。plain:扩展名 .sql,可直接交给 psql。--compression 0..9 只控制 custom 内部压缩。plain 模式显式设置压缩级别会失败。
--output-mode 决定包装方式:
zip:只保留 backup.zip、manifest、身份文件和校验文件。files:保留逐库文件和可选 globals.sql,不生成 Zip。both:两者都保留。custom 外层 Zip 使用 store 模式,避免重复压缩。
/var/backups/postgresql/
├── .staging/
└── runs/
└── pgback_20260807T120000Z_12345/
├── .pgsql-onekey-backup-run
├── backup.zip
├── manifest.txt
└── SHA256SUMS
manifest 记录客户端和服务端版本、认证来源、最终数据库与文件映射、逐库时间和大小,但不记录密码、Token 或敏感文件内容。
恢复前先复制产物到权限受控的临时目录。不要直接在备份目录中修改文件。
sha256sum -c SHA256SUMS
zip -T backup.zip
unzip backup.zip -d restore-files
阅读 manifest.txt 和 globals.sql。异机恢复时,globals.sql 中的表空间绝对路径可能不存在,需要先修改或预建目录。
需要集群对象时先恢复 globals:
psql --dbname=postgres --file=restore-files/globals.sql
恢复 custom:
pg_restore --create --dbname=postgres restore-files/001_app.dump
恢复 plain:
psql --dbname=postgres --file=restore-files/001_app.sql
每个备份固定加入 --create,因此恢复命令连接维护库。恢复后检查扩展、所有者、权限、表空间、行数和应用连接。备份命令成功不等于恢复可用,发布前必须演练一次完整恢复。
三类 Hook 都必须是当前用户所有的绝对路径普通可执行文件,不能是符号链接,组用户和其他用户不能写入。
--before-hook:连接和数据库范围确定后、第一份导出前执行。--after-database-hook:每个数据库产物校验后执行。--after-hook:发布和过期清理完成后执行。所有 Hook 接收 BACKUP_RUN_ID、BACKUP_TARGET_DIR、BACKUP_STAGE_DIR、BACKUP_PUBLISHED_DIR。每库 Hook 还接收数据库名、文件、序号、总数、格式和 output mode。Hook 使用干净环境启动,不接收 libpq 凭据或通知密钥。
前置或每库 Hook 失败时不发布。发布后 Hook 失败时保留已发布产物,但脚本返回失败。
--after-hook 只在备份发布成功后执行。导出或校验中途失败时不会执行它,因此前置 Hook 不适合单独承担“停写”、后置 Hook 承担“恢复写入”。需要停写时,应由外部编排保证失败后也能恢复,或使用带自动过期的维护状态。
默认发送成功和失败通知,--notify-start 还会发送开始通知。支持以下渠道:
--apprise-config,可配 --apprise-tags。--apprise-api-url,stateless /notify 还需 --apprise-urls。--bark-server、--bark-device-key。--ntfy-server、--ntfy-topic,私有主题可加 Token。通知默认脱敏,不显示连接、用户、数据库、目标路径和错误详情。受信任渠道可使用 --no-notify-redact。HTTP 通知只接受 HTTPS;只有 localhost、127.0.0.1 和 [::1] 可以使用 HTTP。单个通知渠道失败不会改变备份结果。
每天 03:00 使用 passfile 备份全部数据库:
0 3 * * * /usr/bin/bash '/opt/postgresql-backup/pgsql_backup.sh' --target-dir '/var/backups/postgresql' --host '127.0.0.1' --port '5432' --user 'postgres' --passfile '/etc/postgresql-backup/pgpass' --notify-redact --all-databases >> '/var/log/postgresql-backup.log' 2>&1
每条 Cron 任务携带完整参数,多个任务不会共享环境配置。Linux 上通常使用 /usr/bin/bash。Crontab 必须是一条物理行;命令中的 % 要写成 \%。密码、Token 和 Webhook 会以明文保存在 Crontab 中,生产环境优先使用权限为 600 的 passfile、service file 或通知配置文件,并使用独立的低权限账号运行任务。
--expire-hours 默认 4320 小时,0 表示不清理。脚本只检查 runs/pgback_* 的一级真实目录,并同时核对身份文件和 manifest 中的格式版本及 Run ID。无法识别的目录只警告,不删除。
同一目标目录使用非阻塞 flock。已有任务运行时,新任务立即失败。
每个选项都有 PGSQL_BACKUP_* 环境变量形式,CLI 优先。PGSQL_BACKUP_DATABASES 和 PGSQL_BACKUP_DUMP_OPTIONS 每行一项;只要 CLI 出现同类列表选项,就整体替换环境变量列表。
脚本只接受 --option value,不接受 --option=value。完整参数可查看:
bash pgsql_backup.sh --help
umask 077。dbname='…' 字面值,并通过独立参数传递;不会拼入 SQL、连接 URI 或 Shell 命令。名称包含 = 或 URI 前缀时也按真实库名处理。mv 到正式目录。