PiSQL
Preface
In combination with the Raspberry Pi OS for a server and Using XCA to create private SSL certificates articles, this article describes setting up a Raspberry Pi Model B+ as a PostgreSQL server with external storage.
Caveat
This will only handle low volumes of requests per second, so is not a good choice for acting as the database for things like file synchronization programs (like Nextcloud, when used for file sync).
Preliminaries
Prepare the server and certificates
- Setup a Pi following the Raspberry Pi OS for a server article.
- Create internal SSL CA and server certificate and key by following the Using XCA to create private SSL certificates article.
Prepare storage for the database
- Since we’re using a separate logical volume (partition) for the PostgreSQL data, we need to create the volume, create the filesystem and mount in the location where Debian will store the PostgreSQL data.
sudo lvcreate -n postgres -L 60G vg1
— assuming the server setup described in the mentioned article. You also may want to use a different size than 60G depending on how much data you expect to have. If you’ve been following along and have space available for allocation you should be able to grow the volume and filesystem should the need arise.sudo mkfs.ext4 -E lazy_itable_init=0,lazy_journal_init=0 /dev/vg1/postgres
— formats the volume fully before returning control (without the ‘-E’ options, Linux will use lazy init which will use background cycles and I/O to complete the task, but will return immediately. It is not as safe and the Pi doesn’t really have the resources to operate well with the background processing going on).sudo mkdir -p /var/lib/postgresql
sudoedit /etc/fstab
Add a line such as:
/dev/vg1/postgres /var/lib/postgresql ext4 defaults,relatime,noexec 1 1
sudo mount -a
— should complete with no errorsdf -h
should show/dev/mapper/vg1-postgres
mounted on/var/lib/postgresql
Install PostgreSQL on the Pi
sudo apt install -y postgresql postgresql-client
sudo ss -ltpn
should should show user postgres with localhost listeners on
port 5432 (e.g. 127.0.0.1:5432 and [::1]:5432 should be reported in that
command).
Configure PostgreSQL
Stop PostgreSQL while configuring
sudo systemctl stop postgresql
Configure SCRAM-SHA-256 passwords
sudoedit /etc/postgresql/11/main/conf.d/05-scram-password-encryption.conf
- Add a line such as
password_encryption = scram-sha-256
- Save and exit
Configure SSL
The server private key and server certificate are the ones you created following the XCA guide mentioned above. You will need to substitute with your actual names of course.
- Copy the server private key into
/etc/ssl/private/pisql.use-your-domain.example.com.key
sudo chgrp ssl-cert /etc/ssl/private/pisql.use-your-domain.example.com.key
sudo chmod 0640 /etc/ssl/private/pisql.use-your-domain.example.com.key
- Copy the server certificate into
/etc/ssl/certs/pisql.use-your-domain.example.com.crt
- Tell PostgreSQL to use them when doing SSL:
sudoedit /etc/postgresql/11/main/conf.d/10-ssl-cert-key.conf
and add lines such as:ssl_cert_file = '/etc/ssl/certs/pisql.use-your-domain.example.com.crt' ssl_key_file = '/etc/ssl/private/pisql.use-your-domain.example.com.key'
Save and exit
- Verify the SSL configuration:
sudo systemctl start postgresql
sudo pg_conftool show ssl_cert_file
— Should report the certificate filename you configuredsudo pg_conftool show ssl_key_file
— Should report key filename you configuredsudo systemctl stop postgresql
Configure SSL client verification
- Copy the CA certificate you created to
/etc/postgresql-common/root.crt
and make sure is owned by root:root and has permissions 0644.
Listen on all interfaces
sudoedit /etc/postgresql/11/main/conf.d/50-listen-all-interfaces.conf
and a line such as:listen_addresses = '*'
Save and exit
Verify if you wish (e.g. start postgresql, check listening ports using
ss
and configuration options usingpg_conftool
)Allow traffic in through the firewall
sudo ufw allow in on eth0 proto tcp from any to any port 5432
- Of course, if you know what you are doing, you can be more restrictive.
Configure PostgreSQL to allow incoming connections
It is not enough to listen for connections, PostgreSQL also needs to be configured what connections to accept.
sudoedit /etc/postgresql/11/main/pg_hba.conf
Enter lines such as:
hostssl all all 0.0.0.0/0 scram-sha-256
hostssl all all ::/0 scram-sha-256
This tell PostgreSQL to all allow SSL network connections for any database and any user from any address provided the user is able to authenticate using their ‘scram-sha-256’ encoded password.
Verify PostgreSQL configuration
Start PostgreSQL and verify status
sudo systemctl start postgresql
sudo systemctl status postgresql
— it should report ‘active (exited)’ and
‘status=0/SUCCESS`
The following commands should complete without errors:
sudo su - postgres
createuser --createdb --pwprompt testuser
createdb -U testuser -h \<address-of-your-pi> testdb "\c sslmode=require"
exit
psql -U testuser postgresql://\<address-of-your-pi>:5432/testdb?sslmod=require
\l
\q
sudo su - postgres
dropdb testdb
dropuser testuser
exit
Configure backups
sudo su - postgres
mkdir restic-files
cd restic-files
chmod 700 .
touch password-file
chmod 600 password-file
sensible-editor password-file
In the editor, add a strong password (e.g. 30 alphanumeric and special characters), then save and close (having a file with the password not ideal, but avoiding it is rather complicated, and out of scope for this article).
If using SFTP for backups, create a passwordless SSH keypair using:
ssh-keygen -t rsa -f restic-postgres@piserver -C restic-postgres@piserver -N ''
- Copy the contents of
restic-postges@piserver.pub
to you destination’s `authorized_keys`` file.
(assuming you have configured,
~/.ssh/config
so thatrestic-postgres@backupserver.example.com
uses therestic-postgres@piserver
created above:pg_dumpall -c --if-exists | restic -r sftp:restic-postgres@backupserver.example.com:/path/to/repo --password-file ./password-file backup --stdin --stdin-filename postgresql.sql
Now create a crontab entry to do this every four hours:
crontab -e
Add an entry such as:
23 */4 * * * pg_dumpall -c --if-exists 2>/dev/null | restic -r sftp:restic@backupserver.example.com:/path/to/repo --password-file ./password-file backup --stdin --stdin-filename postgresql.sql --cleanup-cache --quiet 2>&1 | logger -t restic
Save and exit the editor
exit
Server ready
Your server should now be ready for use.