Self Host PostgreSQL With TLS

Posted by Vivek Shukla on Feb 3, 2025 under PostgreSQL

In this tutorial we will go through how to self-host PostgreSQL Database and setup TLS to securely connect.

Installing PostgreSQL

Postgres APT repository configuration:

sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh

Install PostgreSQL 16

sudo apt install postgresql-16

After installing PostgreSQL, it creates a new user postgres, which is the superuser of the database. We can switch to postgres user in ubuntu to access postgresql command prompt:

sudo -i -u postgres

Now to create new user with passowrd and with privilege to create new db. It will ask you to enter your password, which will not be logged into history hence this is the recommended way to set password.

createuser your_db_user --pwprompt --createdb

Now we can exit from postgres account

exit

We will add new user in our Ubuntu with the same name as the new user we created in postgresql. (Optional) Add -m to create home directory for the user.

sudo useradd -s /bin/bash your_db_user

Accessing psql as the new user we just created. Since we do not have any database associated with our user therefore we are using ‘-d postgres’ to use postgres db for now.

sudo -u your_db_user psql -U your_db_user -d postgres

Create your database.

CREATE DATABASE your_db_name;

This is how you can connect with your db if not already connected.

c your_db_name;

Setting Up SSL

It’s important that we secure our communication with the database while accessing it remotely. We are going to setup SSL certificate using certbot from LetsEncrypt.

Install certbot

sudo snap install core; sudo snap refresh core
sudo apt-get remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Obtain certificate

sudo certbot certonly --standalone -d psql.example.com

Find PostgreSQL data directory

sudo -u postgres psql -U postgres -c 'SHOW data_directory'

Create a renewal hook file

sudo nano /etc/letsencrypt/renewal-hooks/deploy/postgresql.deploy

Paste the following

#!/bin/bash
umask 0177
DOMAIN=psql.example.com
DATA_DIR=/var/lib/postgresql/16/main
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem $DATA_DIR/server.crt
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem $DATA_DIR/server.key
chown postgres:postgres $DATA_DIR/server.crt $DATA_DIR/server.key

Save and exit the file.

Give file executable permission

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/postgresql.deploy

Get the path of PostgreSQL configuration file

sudo -u postgres psql -U postgres -c 'SHOW config_file'

Open the file in edit mode and update the SSL section of the file as below:

sudo nano /etc/postgresql/16/main/postgresql.conf
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_prefer_server_ciphers = on

Locate the Connection Settings section and verify the listen_address is to * for all addresses. Make sure the line is not commented out.

listen_address = '*'

Edit pg_hba.conf file which is in the same dir as config file:

sudo nano /etc/postgresql/16/main/pg_hba.conf

Add the following line to enable connection over ssl for any user and database:

hostssl all all 0.0.0.0/0 md5
hostssl all all ::/0 md5

Renew the SSL certificate

sudo certbot renew --force-renewal

Restart PostgreSQL

sudo service postgresql restart

Connect to your db remotely

psql -d "dbname=your_db_name sslmode=require" -h psql.example.com -U your_db_user
Built with  Svelte Starter Kit