How to Configure PostgreSQL Point-in-time Recovery (pitr) with Wal Archiving and Pg_basebackup on Ubuntu Server
How to Configure PostgreSQL Point-in-time Recovery (PITR) with WAL Archiving and pg_basebackup on Ubuntu Server is one of the most valuable database administration skills you can have. Data loss is a real risk for any production system. Whether a developer runs a bad DELETE query or a disk fails unexpectedly, you need a way to roll your database back to an exact moment in time. PostgreSQL’s PITR feature gives you exactly that capability. It combines a full base backup with a continuous stream of Write-Ahead Log (WAL) files. Together, they let you restore your database to any point in its history. In this tutorial, you’ll set up WAL archiving, create a base backup using pg_basebackup, and then walk through a full recovery scenario. By the end, you’ll have a working PITR setup on your Ubuntu server.
Prerequisites for PostgreSQL Point-in-Time Recovery Setup
Before you start, make sure your environment meets these requirements.
Software and access:
- Ubuntu Server 20.04 or 22.04 (fresh or existing install)
- PostgreSQL 14 or later installed and running
- Root or sudo access to the server
- A separate archive directory (local path or remote mount)
Assumed knowledge:
- Basic Linux command-line skills
- Familiarity with PostgreSQL basics (connecting, running queries)
- Understanding of file permissions on Linux
Estimated time: 45–60 minutes
You’ll also want enough disk space for your archive directory. WAL files accumulate quickly on busy databases. A good rule of thumb is to allocate at least twice your database size for the archive. Check the official PostgreSQL documentation on continuous archiving for deeper background before you begin.
How to Configure PostgreSQL PITR with WAL Archiving and pg_basebackup
For a related walkthrough, see: How to Install Proxmox on Ubuntu
Follow these steps carefully. Each one builds on the last.
Step 1: Create the WAL archive directory
First, create a directory where PostgreSQL will store archived WAL segments. The postgres user must own it.
sudo mkdir -p /var/lib/postgresql/wal_archive
sudo chown postgres:postgres /var/lib/postgresql/wal_archive
sudo chmod 700 /var/lib/postgresql/wal_archive
Step 2: Edit the PostgreSQL configuration file
Open the main configuration file. The path depends on your PostgreSQL version.
sudo nano /etc/postgresql/14/main/postgresql.conf
Find and update these settings. If a line is commented out, remove the # symbol.
wal_level = replica
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
archive_timeout = 60
The archive_command copies each WAL file to your archive directory. The %p is the full path to the WAL file. The %f is just the filename. The archive_timeout forces a WAL switch every 60 seconds. This limits how much data you can lose between archives.
Step 3: Restart PostgreSQL to apply changes
sudo systemctl restart postgresql
Verify the service is running cleanly.
sudo systemctl status postgresql
Step 4: Confirm WAL archiving is working
Connect to PostgreSQL and force a WAL switch.
sudo -u postgres psql -c "SELECT pg_switch_wal();"
Then check the archive directory for new files.
ls -lh /var/lib/postgresql/wal_archive/
You should see at least one WAL file. If the directory is empty, double-check your archive_command and file permissions.
Step 5: Take a base backup with pg_basebackup
Now create a full base backup. This is your recovery starting point.
sudo -u postgres pg_basebackup
-D /var/lib/postgresql/base_backup
-Ft
-z
-P
-Xs
-R
Here’s what each flag does:
-D, sets the output directory-Ft, creates a tar format backup-z, compresses the output-P, shows progress-Xs, streams WAL during backup-R, writes a recovery configuration file
Step 6: Record the backup timestamp
Note the exact time your backup completed. You’ll use this as a reference point for recovery.
date --utc +"%Y-%m-%d %H:%M:%S"
Save this output somewhere safe. You’ll need it when setting your recovery target.
Step 7: Simulate data loss and perform recovery
To test your setup, simulate an accidental data loss. First, create a test table and insert some rows.
sudo -u postgres psql -c "CREATE TABLE test_recovery (id serial, note text);"
sudo -u postgres psql -c "INSERT INTO test_recovery (note) VALUES ('before drop');"
Record the current time. Then drop the table.
sudo -u postgres psql -c "SELECT now();"
sudo -u postgres psql -c "DROP TABLE test_recovery;"
Now stop PostgreSQL and replace the data directory with your base backup.
sudo systemctl stop postgresql
sudo mv /var/lib/postgresql/14/main /var/lib/postgresql/14/main.broken
sudo mkdir /var/lib/postgresql/14/main
sudo tar -xzf /var/lib/postgresql/base_backup/base.tar.gz
-C /var/lib/postgresql/14/main
sudo chown -R postgres:postgres /var/lib/postgresql/14/main
sudo chmod 700 /var/lib/postgresql/14/main
Create a recovery signal file and set your recovery target time. Edit postgresql.conf and add these lines.
restore_command = 'cp /var/lib/postgresql/wal_archive/%f %p'
recovery_target_time = '2024-06-15 10:30:00'
recovery_target_action = 'promote'
Replace the timestamp with the time just before you dropped the table. Then create the recovery signal file.
sudo -u postgres touch /var/lib/postgresql/14/main/recovery.signal
Start PostgreSQL and watch the logs.
sudo systemctl start postgresql
sudo tail -f /var/log/postgresql/postgresql-14-main.log
PostgreSQL will replay WAL files up to your target time and then promote itself. Check that your table came back.
sudo -u postgres psql -c "SELECT FROM test_recovery;"
Troubleshooting Common PostgreSQL PITR Errors
Archive directory is empty after restart
Check the archive_command output manually. Run the command yourself, replacing %p and %f with real values. Fix any permission errors on the archive directory.
Recovery stops before the target time
This usually means WAL files are missing from the archive. Make sure your archive_command was running before you took the base backup. Also confirm the archive directory path in restore_command is correct.
PostgreSQL won’t start after restore
Check /var/log/postgresql/postgresql-14-main.log for errors. A common cause is wrong ownership on the data directory. Run sudo chown -R postgres:postgres /var/lib/postgresql/14/main to fix it.
pg_basebackup fails with “could not connect to server”
Make sure your pg_hba.conf allows replication connections from localhost. Add this line if it’s missing.
local replication postgres trust
Then reload PostgreSQL with sudo systemctl reload postgresql.
For more detail on recovery configuration options, see the PostgreSQL recovery configuration reference.
Conclusion
You now know how to configure PostgreSQL Point-in-Time Recovery (PITR) with WAL Archiving and pg_basebackup on Ubuntu Server from start to finish. You set up WAL archiving, created a base backup, simulated data loss, and recovered to a specific point in time. This setup protects you against accidental deletions, bad migrations, and other data disasters. As a next step, consider automating your base backups with a cron job and shipping WAL archives to remote storage like S3 for offsite protection. You might also explore tools like pgBackRest or Barman, which wrap these concepts in a more manageable interface for larger environments.
