Backup PostgreSQL trên VPS bằng pg_dump và cron: 18 bước có kiểm tra restore
Hướng dẫn backup PostgreSQL tự động trên VPS bằng pg_dump, cron, checksum, retention, lưu ngoài máy chủ và kiểm tra restore định kỳ.
Bài viết bởi Phạm Minh Thiện
Front-end Developer, trực tiếp thực hành Next.js, NestJS, Docker, Nginx và VPS Ubuntu.
Bài viết đã được kiểm tra lại ngày 2/8/2026.
Mục lục bài viết

Backup PostgreSQL trên VPS không chỉ là chạy pg_dump rồi thấy một file .dump xuất hiện. Một bản backup chỉ thật sự có giá trị khi được tạo đúng lịch, không chứa file lỗi giả thành công, có chính sách lưu giữ, được sao chép ra khỏi VPS và đã từng restore thử.
Bài viết này hướng dẫn quy trình phù hợp với ứng dụng nhỏ và vừa tự quản lý trên Ubuntu: kiểm tra phiên bản PostgreSQL, tạo tài khoản backup, dùng .pgpass, tạo archive dạng custom, chống hai job chạy đồng thời, tạo checksum, dọn bản cũ, chạy bằng cron và restore vào database kiểm thử.
Tóm tắt nhanh: Dùng
pg_dump -Fcđể tạo logical backup, chỉ đổi tên file tạm sau khi lệnh thành công, kiểm tra archive bằngpg_restore --list, lưu checksum, giữ nhiều phiên bản, sao chép ít nhất một bản ra khỏi VPS và kiểm tra restore định kỳ.

Demo terminal: tạo và kiểm tra một bản backup
Ví dụ dưới đây tạo archive dạng custom, liệt kê nội dung archive và sinh checksum:

mkdir -p ~/postgres-backup-demo
pg_dump \
-h 127.0.0.1 \
-p 5432 \
-U backup_user \
-d appdb \
-Fc \
-f ~/postgres-backup-demo/appdb.dump
pg_restore --list ~/postgres-backup-demo/appdb.dump > /dev/null
sha256sum ~/postgres-backup-demo/appdb.dump
Lưu ý: Không đưa mật khẩu database trực tiếp vào câu lệnh, shell history, repository hoặc ảnh chụp terminal. Hãy dùng
.pgpass, secret manager hoặc cơ chế cấp secret phù hợp với môi trường triển khai.
Phạm vi của bài viết
Quy trình này phù hợp khi:
PostgreSQL chạy trên VPS hoặc trong Docker
Database có kích thước nhỏ đến vừa
Chấp nhận backup theo mốc thời gian
Không yêu cầu Point-in-Time Recovery ở từng phút
Có thể dành tài nguyên để restore thử định kỳ
pg_dump là logical backup của từng database. Với hệ thống có RPO rất thấp, database lớn hoặc cần khôi phục tới một thời điểm chính xác, cần đánh giá thêm physical backup, WAL archiving, streaming replication hoặc dịch vụ database được quản lý.
Mục tiêu sau khi hoàn thành
Có tài khoản hoặc cơ chế kết nối dành cho backup
Mật khẩu không nằm trong script
Backup được tạo bằng file tạm
Job thất bại không để lại file giả thành công
Có checksum và log
Có chính sách retention
Có bản sao ngoài VPS
Có quy trình restore test
Biết RPO và RTO thực tế
Kiến trúc đề xuất
PostgreSQL
│
├── pg_dump -Fc
│
▼
File tạm trên VPS
│
├── pg_restore --list
├── sha256sum
└── đổi tên thành file hoàn chỉnh
│
▼
Thư mục backup cục bộ
│
├── retention
└── sao chép sang máy/kho lưu trữ khác
│
▼
Restore test định kỳ
Bước 1: Ghi lại thông tin database
Không bắt đầu bằng việc viết cron. Trước tiên, hãy xác định:
Database name:
Host:
Port:
PostgreSQL version:
Kích thước database:
Ứng dụng nào đang dùng:
Thời gian ít tải:
RPO mong muốn:
RTO mong muốn:
Nơi lưu bản sao ngoài VPS:
Kiểm tra phiên bản client:
pg_dump --version
pg_restore --version
psql --version
Kiểm tra server:
psql \
-h 127.0.0.1 \
-p 5432 \
-U postgres \
-d postgres \
-c "SHOW server_version;"
Kiểm tra kích thước:
psql \
-h 127.0.0.1 \
-U postgres \
-d appdb \
-c "SELECT pg_size_pretty(pg_database_size(current_database()));"
Bước 2: Xác định RPO và RTO
RPO là gì?
RPO là lượng dữ liệu tối đa có thể chấp nhận mất.
Ví dụ:
Backup mỗi 24 giờ → có thể mất gần 24 giờ dữ liệu
Backup mỗi 6 giờ → có thể mất gần 6 giờ dữ liệu
Backup mỗi 1 giờ → có thể mất gần 1 giờ dữ liệu
Đây là giới hạn theo lịch backup, chưa tính trường hợp job thất bại hoặc bản backup không restore được.
RTO là gì?
RTO là thời gian mục tiêu để dịch vụ hoạt động trở lại.
RTO phụ thuộc vào:
- Thời gian tải bản backup.
- Thời gian tạo server mới.
- Thời gian cài PostgreSQL.
- Thời gian restore.
- Thời gian cập nhật secret và DNS.
- Thời gian kiểm tra ứng dụng.
Không thể biết RTO thật nếu chưa từng diễn tập restore.
Bước 3: Chọn định dạng backup
Plain SQL
pg_dump -d appdb > appdb.sql
Ưu điểm:
- Có thể đọc bằng text editor.
- Restore bằng
psql. - Dễ chỉnh sửa thủ công trong trường hợp đặc biệt.
Nhược điểm:
- Khó chọn từng object khi restore.
- Không dùng
pg_restore. - Thường kém linh hoạt hơn archive.
Custom archive
pg_dump -Fc -d appdb -f appdb.dump
Ưu điểm:
- Dùng được với
pg_restore. - Có nén mặc định.
- Có thể xem danh sách object.
- Có thể restore chọn lọc.
- Hỗ trợ parallel restore.
Với quy trình trong bài này, dùng custom archive.
Bước 4: Kiểm tra tương thích phiên bản
Kiểm tra:
pg_dump --version
Nguyên tắc quan trọng:
pg_dumpcó thể dump server PostgreSQL cũ hơn nó trong phạm vi được hỗ trợ.pg_dumpkhông dump được server có major version mới hơn chính nó.- Restore sang PostgreSQL mới hơn thường là hướng được hỗ trợ tốt hơn.
- Restore ngược về major version cũ hơn không được đảm bảo.
Ví dụ, nếu server là PostgreSQL 18 nhưng máy chạy script chỉ có pg_dump 16, lệnh sẽ từ chối thực hiện.
Trên Ubuntu, hãy cài client đúng major version cần dùng từ nguồn package phù hợp với hệ thống của bạn.
Bước 5: Tạo tài khoản backup
Không nhất thiết phải dùng tài khoản superuser cho một logical backup thông thường.
Đăng nhập bằng tài khoản quản trị:
sudo -u postgres psql
Tạo role:
CREATE ROLE backup_user
WITH LOGIN
PASSWORD 'THAY_BANG_MAT_KHAU_MANH';
Cho phép kết nối:
GRANT CONNECT ON DATABASE appdb TO backup_user;
Chuyển vào database:
\c appdb
Cấp quyền cho schema public:
GRANT USAGE ON SCHEMA public TO backup_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_user;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO backup_user;
Áp dụng cho object tạo sau này:
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO backup_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON SEQUENCES TO backup_user;
Nếu ứng dụng dùng nhiều schema, hãy cấp quyền cho từng schema cần backup.
Lưu ý: Quyền cần thiết phụ thuộc cấu trúc database, extension, Row-Level Security và ownership. Hãy chạy thử
pg_dumpbằng chính tài khoản backup và xử lý từng lỗi quyền thay vì cấp superuser ngay từ đầu.
Bước 6: Tạo user Linux dành cho backup
Tạo system user không có shell đăng nhập:
sudo useradd \
--system \
--create-home \
--home-dir /var/lib/postgresql-backup \
--shell /usr/sbin/nologin \
backupsvc
Kiểm tra:
id backupsvc
sudo -u backupsvc sh -c 'echo "$HOME"'
Mục đích:
- Tách file và credential backup khỏi user deploy.
- Hạn chế quyền.
- Dễ theo dõi cron và log.
- Dễ thu hồi quyền khi cần.
Bước 7: Cấu hình .pgpass
Tạo file:
sudo -u backupsvc nano /var/lib/postgresql-backup/.pgpass
Nội dung:
127.0.0.1:5432:appdb:backup_user:THAY_BANG_MAT_KHAU_MANH
Đặt permission:
sudo chown backupsvc:backupsvc \
/var/lib/postgresql-backup/.pgpass
sudo chmod 600 \
/var/lib/postgresql-backup/.pgpass
PostgreSQL yêu cầu file password trên Unix không cho group hoặc user khác truy cập. Nếu permission quá rộng, file có thể bị bỏ qua.
Test:
sudo -u backupsvc \
psql \
-h 127.0.0.1 \
-p 5432 \
-U backup_user \
-d appdb \
-c "SELECT current_database(), current_user;"
Không đặt:
PGPASSWORD=mat_khau pg_dump ...
trực tiếp trong cron nếu có lựa chọn an toàn hơn.
Bước 8: Tạo thư mục backup và log
sudo mkdir -p \
/var/backups/postgresql/appdb \
/var/log/postgresql-backup
Gán owner:
sudo chown -R backupsvc:backupsvc \
/var/backups/postgresql \
/var/log/postgresql-backup
Đặt permission:
sudo chmod 700 /var/backups/postgresql
sudo chmod 700 /var/backups/postgresql/appdb
sudo chmod 750 /var/log/postgresql-backup
Kiểm tra dung lượng:
df -h /var/backups/postgresql
df -i /var/backups/postgresql
Không để backup chiếm hết ổ đĩa của database.
Bước 9: Chạy backup thủ công
Chạy dưới đúng Linux user:
sudo -u backupsvc \
pg_dump \
-h 127.0.0.1 \
-p 5432 \
-U backup_user \
-d appdb \
-Fc \
--verbose \
-f /var/backups/postgresql/appdb/appdb-manual.dump
Kiểm tra exit code ngay sau lệnh:
echo $?
Kết quả thành công:
0
Kiểm tra file:
sudo -u backupsvc \
ls -lh /var/backups/postgresql/appdb/appdb-manual.dump
Không đánh giá thành công chỉ dựa vào việc file tồn tại. Một process thất bại vẫn có thể để lại file chưa hoàn chỉnh.
Bước 10: Kiểm tra archive và checksum
Liệt kê nội dung archive:
sudo -u backupsvc \
pg_restore \
--list \
/var/backups/postgresql/appdb/appdb-manual.dump \
> /dev/null
Sinh checksum:
sudo -u backupsvc \
sha256sum \
/var/backups/postgresql/appdb/appdb-manual.dump \
> /var/backups/postgresql/appdb/appdb-manual.dump.sha256
Xác minh:
cd /var/backups/postgresql/appdb
sudo -u backupsvc \
sha256sum --check appdb-manual.dump.sha256
Checksum giúp phát hiện file thay đổi hoặc hỏng trong quá trình sao chép. Nó không thay thế restore test.
Bước 11: Backup role và object toàn cluster
pg_dump chỉ backup một database. Nó không tự chứa đầy đủ role và tablespace ở cấp cluster.
Backup global object:
sudo -u postgres \
pg_dumpall \
--globals-only \
> /var/backups/postgresql/appdb/globals.sql
Hạn chế permission:
sudo chown backupsvc:backupsvc \
/var/backups/postgresql/appdb/globals.sql
sudo chmod 600 \
/var/backups/postgresql/appdb/globals.sql
File global có thể chứa thông tin nhạy cảm như role definition và password hash. Hãy bảo vệ nó như một secret.
Nếu backup script chạy bằng backupsvc, cần thiết kế quyền phù hợp hoặc tách job global object thành một job quản trị riêng. Không cấp quyền hệ thống quá rộng chỉ để tiện chạy một lệnh.
Bước 12: Viết script backup an toàn
Tạo file:
sudo nano /usr/local/sbin/backup-postgresql-appdb.sh
Nội dung:
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
DB_HOST="127.0.0.1"
DB_PORT="5432"
DB_NAME="appdb"
DB_USER="backup_user"
BACKUP_DIR="/var/backups/postgresql/appdb"
LOG_DIR="/var/log/postgresql-backup"
RETENTION_DAYS="14"
TIMESTAMP="$(date '+%Y-%m-%d_%H-%M-%S')"
TEMP_FILE="${BACKUP_DIR}/.${DB_NAME}_${TIMESTAMP}.dump.tmp"
FINAL_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.dump"
CHECKSUM_FILE="${FINAL_FILE}.sha256"
LOG_FILE="${LOG_DIR}/backup.log"
mkdir -p "${BACKUP_DIR}" "${LOG_DIR}"
exec 9>"/var/lock/postgresql-appdb-backup.lock"
if ! flock -n 9; then
printf '%s %s\n' \
"$(date --iso-8601=seconds)" \
"ERROR: another backup job is running" \
>> "${LOG_FILE}"
exit 1
fi
cleanup() {
rm -f "${TEMP_FILE}"
}
trap cleanup EXIT
printf '%s %s\n' \
"$(date --iso-8601=seconds)" \
"INFO: backup started" \
>> "${LOG_FILE}"
pg_dump \
-h "${DB_HOST}" \
-p "${DB_PORT}" \
-U "${DB_USER}" \
-d "${DB_NAME}" \
-Fc \
--verbose \
-f "${TEMP_FILE}" \
2>> "${LOG_FILE}"
pg_restore --list "${TEMP_FILE}" > /dev/null
mv "${TEMP_FILE}" "${FINAL_FILE}"
(
cd "${BACKUP_DIR}"
sha256sum "$(basename "${FINAL_FILE}")" \
> "$(basename "${CHECKSUM_FILE}")"
)
find "${BACKUP_DIR}" \
-type f \
\( -name "${DB_NAME}_*.dump" -o -name "${DB_NAME}_*.dump.sha256" \) \
-mtime "+${RETENTION_DAYS}" \
-delete
printf '%s %s %s\n' \
"$(date --iso-8601=seconds)" \
"INFO: backup completed" \
"${FINAL_FILE}" \
>> "${LOG_FILE"
Dòng cuối phải đóng biến đúng cú pháp. Hãy dùng phiên bản hoàn chỉnh sau:
printf '%s %s %s\n' \
"$(date --iso-8601=seconds)" \
"INFO: backup completed" \
"${FINAL_FILE}" \
>> "${LOG_FILE}"
Vì sao script dùng file tạm?
.dump.tmp → backup đang chạy
.dump → backup đã hoàn tất kiểm tra cơ bản
Nếu pg_dump thất bại, trap xóa file tạm. Job khác không nhầm file dở dang là bản backup hoàn chỉnh.
Vì sao dùng flock?
flock ngăn hai lần backup chạy cùng lúc, ví dụ job trước chưa xong nhưng cron đã kích hoạt job tiếp theo.
Cấp quyền thực thi:
sudo chmod 750 \
/usr/local/sbin/backup-postgresql-appdb.sh
sudo chown root:backupsvc \
/usr/local/sbin/backup-postgresql-appdb.sh
Bước 13: Kiểm tra script trước khi lên lịch
Kiểm tra cú pháp:
sudo bash -n \
/usr/local/sbin/backup-postgresql-appdb.sh
Chạy bằng đúng user:
sudo -u backupsvc \
/usr/local/sbin/backup-postgresql-appdb.sh
Xem log:
sudo tail -n 100 \
/var/log/postgresql-backup/backup.log
Xem file:
sudo ls -lh \
/var/backups/postgresql/appdb
Xác minh checksum mới nhất:
cd /var/backups/postgresql/appdb
LATEST_CHECKSUM="$(
find . -maxdepth 1 -type f -name '*.sha256' \
-printf '%T@ %p\n' |
sort -nr |
head -n 1 |
cut -d' ' -f2-
)"
sudo -u backupsvc \
sha256sum --check "${LATEST_CHECKSUM}"
Không cấu hình cron trước khi lệnh thủ công chạy thành công.
Bước 14: Lên lịch bằng cron
Tạo file:
sudo nano /etc/cron.d/postgresql-appdb-backup
Nội dung:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15 2 * * * backupsvc /usr/local/sbin/backup-postgresql-appdb.sh >> /var/log/postgresql-backup/cron.log 2>&1
Job chạy lúc 02:15 mỗi ngày theo timezone của server.
Kiểm tra timezone:
timedatectl
date
Kiểm tra cron:
sudo systemctl status cron
sudo journalctl -u cron --since today
Kiểm tra file:
sudo chmod 644 \
/etc/cron.d/postgresql-appdb-backup
sudo chown root:root \
/etc/cron.d/postgresql-appdb-backup
Cron có môi trường tối giản. Vì vậy script nên dùng path rõ ràng và không phụ thuộc vào biến shell của user đăng nhập.
Bước 15: Cấu hình retention
Ví dụ trong script giữ file 14 ngày:
RETENTION_DAYS="14"
Chính sách retention gợi ý:
7 bản hàng ngày
4 bản hàng tuần
6 bản hàng tháng
Không có một con số đúng cho mọi dự án. Chính sách phụ thuộc:
- Dung lượng database.
- Tần suất thay đổi.
- Yêu cầu pháp lý.
- Chi phí storage.
- Khả năng phát hiện lỗi trễ.
- RPO và RTO.
Trước khi dùng find ... -delete, chạy thử không có -delete:
find /var/backups/postgresql/appdb \
-type f \
-mtime +14 \
-print
Chỉ bật xóa sau khi danh sách đúng.
Bước 16: Sao chép backup ra khỏi VPS
Backup chỉ nằm trên cùng VPS không bảo vệ được khi:
- VPS bị xóa.
- Ổ đĩa hỏng.
- Tài khoản cloud bị chiếm.
- Ransomware mã hóa dữ liệu.
- Script sai xóa cả database và backup.
- Nhà cung cấp gặp sự cố.
Có thể sao chép sang máy backup riêng bằng rsync:
rsync -az \
--partial \
/var/backups/postgresql/appdb/ \
backup@backup-server:/srv/backups/appdb/
Hoặc dùng object storage có:
Versioning
Retention policy
Encryption
Lifecycle rule
Access log
Credential riêng cho backup
Không dùng cùng credential có quyền xóa toàn bộ production nếu không cần thiết.
Mô hình tối thiểu:
1 bản trên VPS để restore nhanh
1 bản ngoài VPS để chống mất máy chủ
Nhiều phiên bản theo thời gian
Bước 17: Restore thử vào database riêng
Không restore đè production để kiểm tra.
Tạo database thử từ template0:
sudo -u postgres \
createdb \
-T template0 \
appdb_restore_test
Chọn file backup:
LATEST_DUMP="$(
find /var/backups/postgresql/appdb \
-maxdepth 1 \
-type f \
-name 'appdb_*.dump' \
-printf '%T@ %p\n' |
sort -nr |
head -n 1 |
cut -d' ' -f2-
)"
echo "${LATEST_DUMP}"
Restore:
sudo -u postgres \
pg_restore \
--dbname=appdb_restore_test \
--no-owner \
--no-privileges \
--exit-on-error \
"${LATEST_DUMP}"
Cập nhật statistics:
sudo -u postgres \
psql \
-d appdb_restore_test \
-c "ANALYZE;"
Kiểm tra:
sudo -u postgres \
psql \
-d appdb_restore_test \
-c "\dt"
Ví dụ kiểm tra số dòng:
sudo -u postgres \
psql \
-d appdb_restore_test \
-c "SELECT COUNT(*) FROM users;"
Sau khi xác nhận:
sudo -u postgres \
dropdb appdb_restore_test
Restore test nên kiểm tra ít nhất:
Archive đọc được
Schema được tạo
Dữ liệu quan trọng có mặt
Migration version đúng
Ứng dụng có thể kết nối
Một số truy vấn nghiệp vụ chạy đúng
Thời gian restore được ghi lại
Bước 18: Diễn tập phục hồi đầy đủ
Một restore drill tốt không chỉ chạy pg_restore trên cùng VPS.
Hãy thử kịch bản:
1. Tạo một VPS hoặc máy test sạch
2. Cài đúng major version PostgreSQL
3. Khôi phục role cần thiết
4. Tải backup từ kho ngoài VPS
5. Xác minh checksum
6. Tạo database từ template0
7. Chạy pg_restore
8. Chạy ANALYZE
9. Cập nhật secret của ứng dụng test
10. Chạy smoke test
11. Ghi thời gian từng bước
12. Cập nhật runbook
Kết quả cần ghi:
Ngày test:
File backup:
Dung lượng:
Thời gian tải:
Thời gian restore:
Tổng RTO:
Lỗi gặp phải:
Cách xử lý:
Người xác nhận:
Trường hợp PostgreSQL chạy trong Docker Compose
Xác định service:
docker compose ps
Backup từ container:
mkdir -p /var/backups/postgresql/appdb
docker compose exec -T postgres \
pg_dump \
-U postgres \
-d appdb \
-Fc \
> /var/backups/postgresql/appdb/appdb-docker.dump
Dấu > được shell trên host xử lý, nên file nằm trên host.
Kiểm tra:
docker compose exec -T postgres \
pg_restore --list \
< /var/backups/postgresql/appdb/appdb-docker.dump \
> /dev/null
Restore vào database test trong container:
docker compose exec -T postgres \
createdb \
-U postgres \
-T template0 \
appdb_restore_test
docker compose exec -T postgres \
pg_restore \
-U postgres \
-d appdb_restore_test \
--no-owner \
--no-privileges \
--exit-on-error \
< /var/backups/postgresql/appdb/appdb-docker.dump
Không chỉ copy thư mục data của container khi PostgreSQL đang chạy rồi xem đó là backup hợp lệ. Physical backup cần quy trình đảm bảo tính nhất quán riêng.
Monitoring backup tối thiểu
Theo dõi:
Lần backup thành công gần nhất
Exit code
Dung lượng file
Thời gian chạy
Dung lượng ổ đĩa
Số bản đang giữ
Kết quả sao chép offsite
Kết quả restore test gần nhất
Xem log:
sudo tail -f \
/var/log/postgresql-backup/backup.log
Tìm lỗi:
sudo grep -iE \
'error|fatal|failed' \
/var/log/postgresql-backup/*.log
Kiểm tra file mới nhất:
find /var/backups/postgresql/appdb \
-maxdepth 1 \
-type f \
-name '*.dump' \
-printf '%TY-%Tm-%Td %TH:%TM %s %p\n' |
sort -r |
head
Một job không tạo backup trong khoảng thời gian dự kiến phải phát cảnh báo.
Những việc không nên làm
Chỉ kiểm tra file có tồn tại
File có thể rỗng, chưa hoàn chỉnh hoặc chứa archive lỗi.
Ghi password vào script
Script thường được backup, đọc bởi nhiều user hoặc vô tình commit.
Chỉ giữ một bản mới nhất
Nếu lỗi dữ liệu đã xảy ra vài ngày trước, bản mới nhất có thể đã chứa lỗi.
Chỉ lưu trên cùng VPS
Mất VPS đồng nghĩa mất cả database lẫn backup.
Không restore thử
pg_restore --list chỉ là kiểm tra cơ bản, không chứng minh ứng dụng chạy được sau restore.
Cho backup user quyền superuser mặc định
Hãy bắt đầu với quyền tối thiểu và chỉ tăng khi có lý do rõ ràng.
Chạy retention trước khi backup hoàn tất
Nếu job lỗi sau khi xóa bản cũ, số bản an toàn có thể giảm ngoài dự kiến.
Checklist production
[ ] Đã ghi RPO và RTO
[ ] Client pg_dump tương thích server
[ ] Có tài khoản backup riêng hoặc cơ chế quyền rõ ràng
[ ] Password không nằm trong script
[ ] .pgpass có permission 600
[ ] Thư mục backup không public
[ ] Backup dùng file tạm
[ ] Script dùng set -Eeuo pipefail
[ ] Có flock chống chạy trùng
[ ] Kiểm tra exit code
[ ] pg_restore --list chạy thành công
[ ] Có checksum
[ ] Có retention
[ ] Có log
[ ] Cron chạy bằng user riêng
[ ] Có bản sao ngoài VPS
[ ] Global object được xem xét
[ ] Restore test chạy thành công
[ ] Có runbook phục hồi
[ ] Có cảnh báo khi backup trễ hoặc thất bại
Câu hỏi thường gặp
pg_dump có làm khóa database không?
pg_dump tạo export nhất quán trong khi database vẫn có thể được sử dụng. Nó không chặn thao tác đọc hoặc ghi thông thường, nhưng vẫn cần các lock phù hợp để bảo vệ object trong lúc dump. DDL hoặc yêu cầu exclusive lock có thể ảnh hưởng tới quá trình backup.
Nên backup bao lâu một lần?
Dựa vào RPO. Nếu chấp nhận mất tối đa một giờ dữ liệu, lịch backup một lần mỗi ngày là không đủ.
Dùng .sql hay .dump?
Dùng plain SQL khi cần file dễ đọc và restore bằng psql. Dùng custom archive khi cần nén, xem danh sách object, restore chọn lọc hoặc parallel restore.
pg_dump có backup role không?
Không đầy đủ. Role và tablespace là global object. Hãy xem xét pg_dumpall --globals-only.
Có thể restore backup sang PostgreSQL cũ hơn không?
Không nên giả định sẽ thành công. Khả năng restore về major version cũ hơn không được đảm bảo.
Checksum thành công có nghĩa backup dùng được không?
Không. Checksum chỉ cho biết file chưa thay đổi so với lúc tạo checksum. Vẫn phải restore thử.
pg_dump có đủ cho mọi hệ thống production không?
Không. Với database lớn, RPO thấp hoặc cần Point-in-Time Recovery, hãy đánh giá physical backup và WAL archiving hoặc dùng dịch vụ PostgreSQL được quản lý.
Bài viết liên quan
- Mới mua VPS Ubuntu cần làm gì?
- Docker Compose production
- Monitoring, log và healthcheck production
- SSH Key đăng nhập VPS
Kết luận
Một quy trình backup PostgreSQL production cần trả lời được ba câu hỏi:
Backup có chạy đúng lịch không?
File có được lưu an toàn ngoài VPS không?
Đã restore thành công gần đây chưa?
pg_dump, cron và checksum tạo nền tảng tốt cho ứng dụng nhỏ và vừa. Tuy nhiên, mục tiêu cuối cùng không phải là có nhiều file backup, mà là khôi phục được dịch vụ trong RPO và RTO đã cam kết.
Nguồn tham khảo
Đọc tiếp
Bài viết liên quan
Docker Compose production: Node.js, PostgreSQL và backup
Cấu hình Docker Compose production cho Node.js và PostgreSQL với healthcheck, volume, network riêng, secret, log rotation, backup và rollback.
Đọc bài →Deploy Docker lên VPS bằng GitHub Actions: CI/CD tự động 2026
Hướng dẫn build Docker image trên GitHub Actions, đẩy lên GHCR và tự động deploy lên VPS Ubuntu, tránh lỗi Killed 137 trên server RAM thấp.
Đọc bài →GitHub Actions CI/CD: Tự động deploy Node.js lên VPS
Tạo GitHub Actions CI/CD để build, test và tự động deploy Node.js lên VPS qua SSH an toàn, có secrets, healthcheck, concurrency và rollback.
Đọc bài →