# PostgreSQL overlay -- used ONLY when HISTORY=postgres. # # deploy.sh activates it by writing # COMPOSE_FILE=docker-compose.yml:docker-compose.postgres.yml # into .env, which docker compose reads by itself. So every `docker compose` # command in this stack (up, ps, stop, logs, exec) sees the same set of services # with no extra flags -- unlike compose profiles, where a service can be silently # absent from one command and present in another. # # Networking: ergo and caddy run in the HOST namespace, so they cannot use # compose's service DNS. PostgreSQL therefore stays on a normal bridge network # and publishes only to the host's loopback; Ergo reaches it at 127.0.0.1:5432 # (datastore.postgresql.host in ircd.yaml). Nothing is exposed off-box. # # The major version is PINNED. PostgreSQL will not start on a data directory # written by a different major version, so `update.sh` never touches this image. # Upgrading it is a deliberate dump-and-restore -- see the README ("PostgreSQL"). services: postgres: image: postgres:${POSTGRES_TAG:-17-alpine} container_name: ergo-postgres restart: unless-stopped # Loopback only. A Docker-published port bypasses the host INPUT firewall, # so the bind address is the real restriction here. ports: - "127.0.0.1:${POSTGRES_PORT:-5432}:5432" environment: POSTGRES_USER: "${POSTGRES_USER:-ergo}" POSTGRES_DB: "${POSTGRES_DB:-ergo_history}" # The password is read from a file so it never has to live in .env # (compose interpolates .env, and a '$' in a password would break it). POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password # 17 and below keep the classic layout; set it explicitly so a future # image default cannot move the data directory under us. PGDATA: /var/lib/postgresql/data/pgdata volumes: - postgres-data:/var/lib/postgresql/data - ./secrets/postgres.pass:/run/secrets/postgres-password:ro cap_drop: [ALL] cap_add: - CHOWN # initdb/entrypoint fix ownership of PGDATA - DAC_READ_SEARCH - FOWNER - SETGID # the entrypoint drops from root to the postgres user - SETUID security_opt: [no-new-privileges:true] logging: driver: json-file options: max-size: "10m" max-file: "3" healthcheck: test: ["CMD-SHELL", "pg_isready -U \"${POSTGRES_USER:-ergo}\" -d \"${POSTGRES_DB:-ergo_history}\" -q"] interval: 15s timeout: 5s retries: 5 start_period: 30s # Ergo must not come up before the database is accepting connections: with # persistent history enabled it fails to start if the backend is unreachable. # depends_on is orchestration only, so it works across the host/bridge split. ergo: depends_on: postgres: condition: service_healthy volumes: postgres-data: