ansible-playbooks/roles/postgres
2025-11-11 11:11:47 +01:00
..
defaults fix: review postgres on multiple iface 2025-11-11 11:11:47 +01:00
handlers feat: add postgres support 2025-11-10 18:24:43 +01:00
tasks fix: review postgres on multiple iface 2025-11-11 11:11:47 +01:00
templates fix: review postgres on multiple iface 2025-11-11 11:11:47 +01:00
vars feat: pg with extensions and open to podmans containers 2025-11-11 00:02:15 +01:00
README.md fix: review postgres on multiple iface 2025-11-11 11:11:47 +01:00

PostgreSQL Role

This Ansible role installs and configures PostgreSQL for local use only. It provides a shared PostgreSQL instance that multiple services can use with isolated databases and users.

Features

  • Installs PostgreSQL
  • Local-only access (localhost)
  • Configurable performance settings
  • Each service manages its own database/user (see below)

Requirements

  • Systemd-based Linux distribution
  • Root/sudo access
  • Python psycopg2 package (for database operations from service roles)

Role Variables

See defaults/main.yml for all available variables and their default values.

Key Configuration Requirements

Required Password

The postgres_admin_password variable must be set in your inventory (min 12 characters). The role will fail if not set.

Container Access

For containers to access PostgreSQL, set postgres_bind to include the Podman gateway:

postgres_bind: "127.0.0.1,{{ podman_subnet_gateway }}"

Dependencies

None.

Example Playbook

---
- hosts: servers
  become: true
  roles:
    - role: postgres
    - role: immich  # Will create its own database
    - role: nextcloud  # Will create its own database

Database Isolation Strategy

This role follows a decentralized database management pattern:

1. PostgreSQL Role Responsibility

  • Install and configure PostgreSQL
  • Manage global performance settings
  • Ensure the service is running

2. Service Role Responsibility

Each service role (immich, nextcloud, etc.) manages its own:

  • Database creation
  • User creation
  • Password management
  • Schema migrations

3. Security & Isolation

Database Isolation:

  • Each service gets its own database
  • Example: immich, nextcloud, gitea

User Isolation:

  • Each service gets its own PostgreSQL user
  • Users can only access their own database
  • Example: immichimmich database only

Authentication:

  • Each user has a unique password
  • Passwords stored in service role variables (use Ansible Vault for production)

Connection Methods

From Containers

If your service runs in a container (Docker/Podman), you need to configure PostgreSQL to listen on the Podman bridge gateway:

Step 1: Configure PostgreSQL in inventory

# inventory/host_vars/yourserver.yml
postgres_bind: "127.0.0.1,{{ podman_subnet_gateway }}"
postgres_firewall_allowed_sources:
  - 127.0.0.0/8
  - "{{ podman_subnet }}"

Step 2: Use host.containers.internal in containers

# docker-compose.yml
services:
  myservice:
    extra_hosts:
      - "host.containers.internal:host-gateway"
    environment:
      DB_HOSTNAME: host.containers.internal
      DB_PORT: 5432

What this does:

  • PostgreSQL listens on 127.0.0.1 (localhost) and 10.88.0.1 (Podman gateway)
  • UFW firewall allows connections from localhost and Podman subnet
  • pg_hba.conf automatically configured to allow Podman subnet
  • host.containers.internal resolves to the gateway IP inside containers

From System Services

Services running directly on the host can connect to localhost:5432 without any special configuration.

Security Best Practices

1. Use Ansible Vault for Passwords

# Create encrypted variables
ansible-vault encrypt_string 'my_secure_password' --name 'immich_db_password'

Add to your inventory or vars:

immich_db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          ...encrypted...

2. Unique Passwords per Service

Never reuse passwords between services:

immich_db_password: unique_password_1
nextcloud_db_password: unique_password_2
gitea_db_password: unique_password_3

3. Minimal Privileges

The pattern above ensures users have:

  • Access to their database only
  • No superuser privileges
  • Cannot create databases
  • Cannot create roles
  • Cannot access other databases

4. Controlled Access

PostgreSQL default configuration:

  • Listens on localhost only by default
  • To allow container access, set postgres_bind to include Podman gateway
  • UFW firewall rules automatically configured for allowed sources
  • pg_hba.conf automatically configured for Podman subnet when enabled
  • No remote network access by default

Troubleshooting

Check PostgreSQL status

systemctl status postgresql

Connect to PostgreSQL

sudo -u postgres psql

List databases

\l

List users and permissions

\du

Test connection from service

# From localhost
psql -h localhost -U immich -d immich

# From Podman gateway (if configured)
psql -h 10.88.0.1 -U immich -d immich

# Check listen addresses
sudo -u postgres psql -c "SHOW listen_addresses;"

# Check firewall rules
sudo ufw status | grep 5432

# Check pg_hba.conf
sudo grep -v "^#" /var/lib/postgres/data/pg_hba.conf | grep -v "^$"

View logs

journalctl -u postgresql -f

Performance Tuning

Adjust variables based on your hardware:

For systems with 4GB RAM:

postgres_shared_buffers: 1GB
postgres_effective_cache_size: 3GB

For systems with 16GB RAM:

postgres_shared_buffers: 4GB
postgres_effective_cache_size: 12GB

Rule of thumb:

  • shared_buffers: 25% of total RAM
  • effective_cache_size: 50-75% of total RAM

Backup Recommendations

Consider implementing:

  1. pg_dump for logical backups
  2. WAL archiving for point-in-time recovery
  3. Automated backup scripts via cron

Example backup script for a service:

pg_dump -h localhost -U immich immich > /backup/immich_$(date +%Y%m%d).sql

License

MIT

Author Information

Created for managing shared PostgreSQL instances in NAS/homelab environments.