PostgreSQL streaming replication done simple
I've done this a few times now, both professionally and for hobby projects. For the latter, it's a very convenient way of ensuring you have data in more than one location, in case of emergency. (Ok, I admit that I'm probably more concerned about the data integrity in my hobby projects than most)
Anyway, it's the latter case I'm focusing on here, which means there is very little tuning of config options.
I'll be using Ubuntu 24.04 for the servers.
The primary server
Make sure the system is up to date, then install the package postgresql-common
. This installs a script for enabling PostgreSQL's own official Ubuntu repository, giving access to the latest and greatest. Run it with sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
.
Now you can sudo apt update
and sudo apt install postgresql-17
.
By default, PostgreSQL only listens on the loopback interface. The secondary server (and, presumably, you and your applications) needs to be able to connect over the network, so open up your favourite text editor and edit /etc/postgresql/17/main/postgresql.conf
.
Change
#listen_addresses = 'localhost'
to
listen_addresses = '*'
Then, open /etc/postgresql/17/main/pg_hba.conf
Add a line at the bottom (Replace the IP with the IP address of your secondary server)
host replication all 192.168.0.5/32 scram-sha-256
Now, open up a psql console sudo -i -u postgres psql
, and create the replication user:
CREATE ROLE replication WITH REPLICATION LOGIN PASSWORD 'yourpassword123';
The secondary server
Repeat the package installation steps from the primary, but skip the config.
After PostgreSQL is installed. Stop the server: sudo systemctl stop postgresql
.
Then, change to the postgres user: sudo -i -u psql
.
Now, REMOVE the PostgreSQL data directory. rm -rf /var/lib/postgresql/17/main/*
It's time for the magic. (Replace the IP with the IP of your primary server)
pg_basebackup -R -h 192.168.0.4 -U replication -W -D /var/lib/postgresql/17/main/
This will prompt you for the password you created for the replication
user you created earlier. It will then sync the database from the primary, and configure the secondary for streaming replication.
You can now log out the postgres
user, and start PostgreSQL again with sudo systemctl start postgresql
.
If everything goes well, you'll see the following in /var/log/postgresql/postgresql-17-main.log
2025-02-16 11:21:05.226 UTC [4528] LOG: starting PostgreSQL 17.3 (Ubuntu 17.3-1.pgdg24.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0, 64-bit
2025-02-16 11:21:05.226 UTC [4528] LOG: listening on IPv6 address "::1", port 5432
2025-02-16 11:21:05.226 UTC [4528] LOG: listening on IPv4 address "127.0.0.1", port 5432
2025-02-16 11:21:05.228 UTC [4528] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2025-02-16 11:21:05.234 UTC [4531] LOG: database system was interrupted; last known up at 2025-02-16 11:20:54 UTC
2025-02-16 11:21:05.259 UTC [4531] LOG: starting backup recovery with redo LSN 0/3000028, checkpoint LSN 0/3000080, on timeline ID 1
2025-02-16 11:21:05.259 UTC [4531] LOG: entering standby mode
2025-02-16 11:21:05.264 UTC [4531] LOG: redo starts at 0/3000028
2025-02-16 11:21:05.266 UTC [4531] LOG: completed backup recovery with redo LSN 0/3000028 and end LSN 0/3000120
2025-02-16 11:21:05.266 UTC [4531] LOG: consistent recovery state reached at 0/3000120
2025-02-16 11:21:05.266 UTC [4528] LOG: database system is ready to accept read-only connections
2025-02-16 11:21:05.627 UTC [4532] LOG: started streaming WAL from primary at 0/4000000 on timeline 1
Voilá, streaming replication works!