Production database, no backups scheduled. One bad migration or a dropped table by accident, and there's nothing to restore from.
PostgreSQL already ships with pg_dump, so a proper automated backup can be set up on Linux without installing extra backup software.
This guide sets up a daily backup, adds a timestamp to each filename, and deletes anything older than 7 days.
Prerequisites
Make sure the PostgreSQL client tools are installed:
pg_dump --version
On Ubuntu or Debian, install them if needed:
sudo apt update
sudo apt install postgresql-client
Example setup used in this guide:
Database: mydatabase
User: postgres
Backup directory: /var/backups/postgresql
Retention: 7 days
Swap these for your own values.
1. Create the Backup Directory
sudo mkdir -p /var/backups/postgresql
sudo chown $USER:$USER /var/backups/postgresql
sudo chmod 700 /var/backups/postgresql
2. Test a Manual Backup First
Before automating anything, confirm pg_dump actually works:
pg_dump -h 127.0.0.1 -U postgres -F c mydatabase > /var/backups/postgresql/test.dump
Check the result:
ls -lh /var/backups/postgresql/
You should see test.dump.
The -F c flag uses PostgreSQL's custom archive format, which can be restored later with pg_restore.
3. Create the Backup Script
sudo nano /usr/local/bin/postgres-backup.sh
Paste:
#!/bin/bash
BACKUP_DIR="/var/backups/postgresql"
DB_NAME="mydatabase"
DB_USER="postgres"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
mkdir -p "$BACKUP_DIR"
pg_dump \
-h 127.0.0.1 \
-U "$DB_USER" \
-F c \
"$DB_NAME" \
> "$BACKUP_DIR/${DB_NAME}_${TIMESTAMP}.dump"
find "$BACKUP_DIR" \
-type f \
-name "*.dump" \
-mtime +7 \
-delete
Make it executable:
sudo chmod +x /usr/local/bin/postgres-backup.sh
Run it manually:
/usr/local/bin/postgres-backup.sh
Verify:
ls -lh /var/backups/postgresql/
You should see something like mydatabase_2026-09-04_02-00-00.dump.
4. Skip the Password Prompt
The backup needs to run without asking for a password, otherwise cron can't complete it on its own.
nano ~/.pgpass
Add:
localhost:5432:mydatabase:postgres:YOUR_PASSWORD
Then lock down the file:
chmod 600 ~/.pgpass
Run the script again. It should finish without prompting for anything.
Never hardcode the database password inside the backup script itself.
One gotcha: without -h, PostgreSQL connects through a Unix socket, and the default local auth method on Ubuntu/Debian is usually peer, not password. That means .pgpass gets ignored and you'll hit a "Peer authentication failed" error. Adding -h 127.0.0.1 (as in the script above) forces a TCP connection instead, so .pgpass actually gets used.
5. Schedule It With Cron
crontab -e
To run every day at 2:00 AM:
0 2 * * * /usr/local/bin/postgres-backup.sh >> /var/backups/postgresql/backup.log 2>&1
Confirm it's saved:
crontab -l
That's it, PostgreSQL now backs itself up every day without anyone touching it.
6. Check Your Backups Are Actually There
ls -lh /var/backups/postgresql/
You can also peek inside an archive without restoring it:
pg_restore -l /var/backups/postgresql/mydatabase_2026-09-04_02-00-00.dump | head
This one just reads the archive file directly, so it doesn't need -h or a database connection at all. If PostgreSQL can read it, you'll see the table of contents.
7. Actually Test a Restore
A backup doesn't count as reliable until you've restored it at least once.
createdb -h 127.0.0.1 -U postgres restore_test
pg_restore \
-h 127.0.0.1 \
-U postgres \
-d restore_test \
/var/backups/postgresql/mydatabase_2026-09-04_02-00-00.dump
Check the data is actually there, then clean up:
dropdb -h 127.0.0.1 -U postgres restore_test
Wrap Up
At this point the backup system runs daily, timestamps every file, keeps the password out of the script, and clears anything older than 7 days on its own.
For most small Linux servers, that's a solid first layer of protection.
One thing to keep in mind though: a backup sitting only on the same server is still one disk failure away from being gone too. Copy it somewhere else if the data actually matters.
ALKNETWORK