pgstef's blog

SELECT * FROM pgstef

Home About me Talks PITR tools View on GitHub

SFTP support has been added in the 2.46 release on 22 May 2022.

In this demo setup, the SFTP host will be called sftp-srv and the PostgreSQL node pg-srv. Both nodes will be running on Rocky Linux 8.

If you’re familiar with Vagrant, here’s a simple Vagrantfile to initiate 3 virtual machines using those names:

# Vagrantfile
Vagrant.configure(2) do |config|
    config.vm.box = 'rockylinux/8'
    config.vm.provider 'libvirt' do |lv|
        lv.cpus = 1
        lv.memory = 1024
    end
    config.vm.synced_folder ".", "/vagrant", disabled: true

    nodes  = 'sftp-srv', 'pg-srv'
    nodes.each do |node|
        config.vm.define node do |conf|
            conf.vm.hostname = node
        end
    end
end

When using Vagrant boxes, it might be needed to enable the SSH password authentication to proceed with SSH key exchange:

$ sudo -i
root# sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config    
root# systemctl restart sshd.service
root# passwd

Installation

On the database node, first configure the PGDG repositories and install PostgreSQL:

$ sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
$ sudo dnf -qy module disable postgresql
$ sudo dnf install -y postgresql15-server postgresql15-contrib

Create a basic PostgreSQL instance:

$ sudo PGSETUP_INITDB_OPTIONS="--data-checksums" /usr/pgsql-15/bin/postgresql-15-setup initdb
$ sudo systemctl enable postgresql-15
$ sudo systemctl start postgresql-15

Install pgBackRest and check its version:

$ sudo dnf install -y epel-release
$ sudo dnf install -y pgbackrest
$ pgbackrest version
pgBackRest 2.46

Create a dedicated user and location on the SFTP server

The pgbackrest user is created to own the backups and archives repository on the SFTP server:

$ sudo groupadd pgbackrest
$ sudo adduser -g pgbackrest -n pgbackrest
$ sudo mkdir -m 750 -p /backup_space
$ sudo chown pgbackrest: /backup_space
$ sudo -u pgbackrest mkdir -m 750 -p /home/pgbackrest/.ssh

Setup SSH communication between the PostgreSQL node and SFTP server

The idea is to generate a dedicated SSH key pair for the SFTP connection and use a secured passphrase with it.

First of all, generate the SSH key pair on the PostgreSQL node:

$ sudo -u postgres ssh-keygen -f /var/lib/pgsql/.ssh/id_rsa_sftp -t rsa -b 4096 -N "BeSureToGenerateAndUseASecurePassphrase"

Then, copy the generated public keys to the SFTP server to authorize it:

# From sftp-srv
$ ssh root@pg-srv cat /var/lib/pgsql/.ssh/id_rsa_sftp.pub| \
    sudo -u pgbackrest tee -a /home/pgbackrest/.ssh/authorized_keys

The connection from the PostgreSQL node should now prompt for the passphrase:

$ sudo -u postgres ssh pgbackrest@sftp-srv -i /var/lib/pgsql/.ssh/id_rsa_sftp

Configuration

We’ll now prepare the configuration for our stanza called demo.

Update the pg-srv pgBackRest configuration file:

# /etc/pgbackrest.conf
[global]
repo1-bundle=y
repo1-type=sftp
repo1-path=/backup_space
repo1-sftp-host=sftp-srv
repo1-sftp-host-key-hash-type=sha1
repo1-sftp-host-user=pgbackrest
repo1-sftp-private-key-file=/var/lib/pgsql/.ssh/id_rsa_sftp
repo1-sftp-private-key-passphrase=BeSureToGenerateAndUseASecurePassphrase

repo1-retention-full=2
start-fast=y
log-level-console=info
log-level-file=debug
delta=y
process-max=2

[demo]
pg1-path=/var/lib/pgsql/15/data

Configure archiving in the postgresql.conf file:

listen_addresses = '*'
archive_mode = on
archive_command = 'pgbackrest --stanza=demo archive-push %p'

The PostgreSQL instance must be restarted after making these changes.

$ sudo systemctl restart postgresql-15.service

When using SFTP, pgBackRest commands are run like with other repository types (NFS, S3,…). Let’s then now create the stanza and check the configuration on the pg-srv:

$ sudo -iu postgres pgbackrest --stanza=demo stanza-create
...
P00   INFO: stanza-create command end: completed successfully

$ sudo -iu postgres pgbackrest --stanza=demo check
...
P00   INFO: check command end: completed successfully

We can now take our first backup from pg-srv:

$ sudo -iu postgres pgbackrest --stanza=demo --type=full backup
P00   INFO: backup command begin 2.46: ...
P00   INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000003, lsn = 0/3000028
P00   INFO: check archive for prior segment 000000010000000000000002
P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000003, lsn = 0/3000138
P00   INFO: check archive for segment(s) 000000010000000000000003:000000010000000000000003
P00   INFO: new backup label = 20230525-140532F
P00   INFO: full backup size = 22MB, file total = 966
P00   INFO: backup command end: completed successfully

Finally, look at the repository content using the info command:

$ sudo -iu postgres pgbackrest --stanza=demo info
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (15): 000000010000000000000001/000000010000000000000003

        full backup: 20230525-140532F
            timestamp start/stop: 2023-05-25 14:05:32 / 2023-05-25 14:05:44
            wal start/stop: 000000010000000000000003 / 000000010000000000000003
            database size: 22MB, database backup size: 22MB
            repo1: backup set size: 2.9MB, backup size: 2.9MB

Conclusion

The SFTP repository type is pretty easy to setup but as mentioned in the official documentation, the SFTP file transfer is relatively slow. Increasing process-max to parallelize file transfer and using file bundling will help but it would probably be better to use the other supported repository types if you can.

Edit: pgBackRest 2.47 brought a significant performance improvement of the SFTP storage driver. So it becomes a good option if you really need to use it.