--- ansible_host: 10.0.19.30 ansible_python_interpreter: /usr/bin/python3 ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new' firewall_trusted_subnets: - subnet: 100.64.0.0/10 comment: Tailscale - subnet: 10.0.8.0/21 comment: Home cluster network firewall_allow_rules: - port: 5432 proto: tcp comment: PostgreSQL - port: 6432 proto: tcp comment: PgBouncer # Override role defaults - this server uses default Debian paths, not RAID postgresql_version: "17" postgresql_storage_setup_enabled: false postgresql_data_directory: /var/lib/postgresql/17/main postgresql_wal_directory: /var/lib/postgresql/17/main/pg_wal postgresql_config_directory: /etc/postgresql/17/main postgresql_backup_enabled: false # TimescaleDB timescaledb_enabled: true timescaledb_max_background_workers: 16 timescaledb_apt_repo: "deb https://packagecloud.io/timescale/timescaledb/debian/ trixie main" # PostgreSQL config (matches live server tuning) postgresql_config: # Connection listen_addresses: "'*'" # Matches the live server (was raised from 100). With PgBouncer fronting the # backend, real backend connections stay well under this; the headroom covers # apps still connecting directly during/after cutover. max_connections: 300 port: 5432 # Memory (tuned for 8GB ARM server) shared_buffers: 2014MB work_mem: 5157kB maintenance_work_mem: 1031576kB effective_cache_size: 6044MB # Disk random_page_cost: 1.1 effective_io_concurrency: 256 # Workers max_worker_processes: 23 max_parallel_workers: 4 max_parallel_workers_per_gather: 2 # WAL wal_buffers: 16MB max_wal_size: 1GB min_wal_size: 512MB checkpoint_completion_target: 0.9 # Autovacuum autovacuum_max_workers: 10 autovacuum_naptime: 10 # Query tuning default_statistics_target: 100 jit: off # Compression and locking default_toast_compression: lz4 max_locks_per_transaction: 128 # Logging log_line_prefix: "'%m [%p] %q%u@%d '" log_timezone: "'UTC'" cluster_name: "'17/main'" # Locale datestyle: "'iso, dmy'" timezone: "'Europe/London'" lc_messages: "'en_GB.UTF-8'" lc_monetary: "'en_GB.UTF-8'" lc_numeric: "'en_GB.UTF-8'" lc_time: "'en_GB.UTF-8'" default_text_search_config: "'pg_catalog.english'" # Extensions shared_preload_libraries: "'pg_stat_statements,timescaledb'" # TimescaleDB timescaledb.max_background_workers: 16 # SSL ssl: on ssl_cert_file: "'server.crt'" ssl_key_file: "'server.key'" # pg_hba.conf entries (matches live server) postgresql_hba_entries: - type: local database: all user: postgres auth_method: peer - type: local database: all user: all auth_method: peer - type: host database: all user: all address: 127.0.0.1/32 auth_method: scram-sha-256 - type: host database: all user: all address: "::1/128" auth_method: scram-sha-256 - type: local database: replication user: all auth_method: peer - type: host database: replication user: all address: 127.0.0.1/32 auth_method: scram-sha-256 - type: host database: replication user: all address: "::1/128" auth_method: scram-sha-256 - type: hostssl database: all user: all address: 10.0.8.0/21 auth_method: scram-sha-256 # Databases and users (matches live server) postgresql_databases: - name: aprsme_prod owner: aprsme - name: gridmap owner: gridmap - name: towerops owner: towerops - name: prop owner: prop postgresql_users: - name: aprsme password: "{{ vault_postgresql_aprsme_password | default(omit) }}" - name: gridmap password: "{{ vault_postgresql_gridmap_password | default(omit) }}" - name: towerops password: "{{ vault_postgresql_towerops_password | default(omit) }}" - name: prop password: "{{ vault_postgresql_prop_password | default(omit) }}" postgresql_extensions: aprsme_prod: - citext - pg_stat_statements - pg_trgm - postgis # --- PgBouncer --- # Per-database backend connection pools. Sized from observed live usage in # session mode (which pins ~1 server conn per active client): towerops runs 2 # replicas, aprsme peaks ~52, prop ~70. Sum (~210) + reserves stays under # max_connections (300) with room for TimescaleDB workers and gridmap (direct). # All session mode (safe for Ecto prepared statements and Oban LISTEN/NOTIFY); # switch an app to pool_mode: transaction only after verifying it tolerates it. pgbouncer_max_db_connections: 100 pgbouncer_databases: - name: towerops pool_size: 30 - name: aprsme_prod pool_size: 60 - name: prop pool_size: 80 - name: gridmap pool_size: 20