From Scratch to Restore: Automating PostgreSQL Setup & Backups with Ansible



This content originally appeared on DEV Community and was authored by Athreya aka Maneshwar

Making Ansible Snappy, Quiet, and Friendly: A Dev’s Guide to ansible.cfg

Hi there! I’m Maneshwar. Right now, I’m building LiveAPI, a first-of-its-kind tool that helps you automatically index API endpoints across all your repositories. LiveAPI makes it easier to discover, understand, and interact with APIs in large infrastructures.

Setting up PostgreSQL isn’t hard. Forgetting to set it up the same way across servers? That’s where it gets messy. We wanted to automate it all—install, configure, create roles, set cron, restore dumps, and even back them up with alerts—using a single Ansible playbook and a couple of shell scripts.

Here’s how we automated our entire PostgreSQL lifecycle, from install to restore.

Step 1: Install PostgreSQL and Required Extensions

We start with installing PostgreSQL 16, plpython3u, and pg_cron. We also drop in the official APT repo and GPG key so we’re not stuck with the system default version.

- name: Install required dependencies for PostgreSQL
  ansible.builtin.apt:
    name:
      - curl
      - ca-certificates
      - gnupg
      - lsb-release
    state: present
    update_cache: yes

We then fetch the PostgreSQL signing key and register the repo:

- name: Add PostgreSQL APT repository
  ansible.builtin.apt_repository:
    repo: "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt {{ ansible_lsb.codename }}-pgdg main"
    state: present

Post that, we install the actual packages we care about:

- name: Install PostgreSQL 16 and cron extension
  ansible.builtin.apt:
    name:
      - postgresql-16
      - postgresql-16-cron
      - postgresql-plpython3-16
      - python3-psycopg2  # needed for Ansible postgres modules
    state: present

Step 2: Configure PostgreSQL Access and Superusers

We change the default user’s password, create our custom flyweight superuser, and make sure PostgreSQL accepts external connections:

- name: Alter custom superuser role attributes
  shell: |
    PGPASSWORD="{{ pg_postgres_password }}" psql -U postgres -c "ALTER ROLE {{ pg_flyweight_user }} WITH SUPERUSER CREATEDB CREATEROLE REPLICATION BYPASSRLS;"
  become: true
  become_user: postgres

We also modify postgresql.conf and pg_hba.conf to:

  • Allow external connections (listen_addresses = '*')
  • Enable pg_cron via shared_preload_libraries
  • Allow md5 authentication for all IPs (0.0.0.0/0)

Step 3: pg_cron Config

If you’re using pg_cron, you need to point it to a database. We do that using:

- name: Ensure cron.database_name is set to 'liveapi'
  lineinfile:
    path: /etc/postgresql/16/main/postgresql.conf
    line: "cron.database_name = 'liveapi'"
    state: present
    insertafter: EOF

Step 4: Restore Databases from Backup (Ansible + Shell Combo)

We restore a .tar archive which includes:

  • roles.sql
  • One or more .dump files (one per DB)

Here’s what the restore shell script does:

  1. Downloads and extracts the archive
  2. Restores roles (excluding postgres)
  3. For each DB:
  • Creates it
  • Calls pg_restore
  • Restarts PostgreSQL with updated cron.database_name if needed

📦 restore.sh.j2 looks like this:

curl -sSL "$ARCHIVE_URL" -o "$ARCHIVE_NAME"
tar -xf "$ARCHIVE_NAME" -C "$TMP_DIR"

for dumpfile in "$TMP_DIR"/*.dump; do
  dbname=$(basename "$dumpfile" .dump)
  createdb -h "$PG_HOST" -U "$PG_USER" "$dbname"
  pg_restore -h "$PG_HOST" -U "$PG_USER" -d "$dbname" "$dumpfile"
done

This script is rendered and executed from Ansible:

- name: Run restore.sh as sudo
  ansible.builtin.shell: /home/ubuntu/restore/restore.sh
  become: true

Step 5: Backups to S3 + Discord Alerts

Our backup script does the opposite: dumps everything, compresses it, uploads to S3, and alerts us on Discord with the file size.

PGPASSWORD=$password pg_dumpall -U postgres > full_backup.sql
tar -zcvf "$f" ./dump/full_backup.sql
aws s3 cp "$f" s3://fw-pgbackup

If backup fails or the file size is too small (<20MB), we get a Discord ping.

Why This Setup Works

  • 🧠 One command to setup PostgreSQL from scratch
  • 🚀 Restore production-like data to dev in seconds
  • 🔁 pg_cron ready out of the box
  • 🧼 Role and permission management handled automatically
  • ☁ Cloud backup and alerting done without manual ops

If you’re building platforms with Postgres and want reproducibility with zero surprises, this combo of Ansible + shell + S3 + Discord is hard to beat.

LiveAPI helps you get all your backend APIs documented in a few minutes.

With LiveAPI, you can generate interactive API docs that allow users to search and execute endpoints directly from the browser.

LiveAPI Demo

If you’re tired of updating Swagger manually or syncing Postman collections, give it a shot.


This content originally appeared on DEV Community and was authored by Athreya aka Maneshwar