Files
serverAppConfigs/serverAppConfigs-docs/Dankclaw/Postgres.md
Frank e7f0d93c86 docs(vault): fleet-wide fact re-verification pass (67 pages)
The docs-fact census wave re-read the live hosts and re-keyed every page
it could: runtime/payload identities, ports, sizes, ledger figures, unit
state, and the retirement banners that drifted as the fleet moved. The
wave was interrupted mid-run, so this commit carries only what passed the
integrity gates: every touched page parses (front matter or H1+status
convention intact, balanced fences, no truncated tables, trailing
newline), the docs_completeness and link-integrity seams are green, and
bats is 384/384.

Numbers that this session proved on live hosts are keyed to the measured
value, not the page's earlier claim.
2026-10-18 13:15:43 -07:00

143 lines
6.7 KiB
Markdown

---
type: reference
description: "PostgreSQL is the database backend for Gitea."
tags:
- dankclaw
- postgres
timestamp: 2026-09-03
---
# Postgres
PostgreSQL is the database backend for two separate services on this host:
**Gitea** (`gitea-postgres`) and **Authentik** (`authentik-postgres`). They are two
independent clusters — two containers, two data dirs, two podman networks — and each
holds only its own app's data; neither is a shared instance. Gitea's DB holds the
repository metadata, users, and issue data; Authentik's holds the IdP objects.
**Host:** Dankclaw — **Docs:** https://www.postgresql.org/docs
## Facts
| Item | `gitea-postgres` | `authentik-postgres` |
|------|------------------|----------------------|
| Image | `docker.io/library/postgres:16-alpine` (`dankclaw/gitea/quadlet/gitea-postgres.container:18`) | `docker.io/library/postgres:16-alpine` (`dankclaw/authentik/quadlet/authentik-postgres.container:17`) |
| Port | 5432, container-internal — no `PublishPort`; a TCP probe of `192.168.0.143:5432` is refused (`ss -ltn` + probe 2026-10-18) | same: nothing published, 5432 refused on the LAN IP (2026-10-18) |
| Network | `systemd-gitea`, 10.89.0.0/24 (`dankclaw/gitea/quadlet/gitea.network`, `podman network inspect systemd-gitea` 2026-10-18) | `dankclaw_default`, 10.89.1.0/24 (`authentik-postgres.container:18`; the compose-stack bridge shared with Authentik/Seerr/Grafana) |
| Data volume | `/home/dank/Containers/gitea/postgres:/var/lib/postgresql/data` (`gitea-postgres.container:23`) | `/home/dank/Containers/authentik/postgres:/var/lib/postgresql/data` (`authentik-postgres.container:23`) |
| Healthcheck | **none** — the unit carries no `HealthCmd`, so `podman ps` reports `Up` with no health state (2026-10-18) | `pg_isready -d authentik -U authentik` every 30 s, 5 retries, 20 s start (`authentik-postgres.container:29-33`); container reports `healthy` (2026-10-18) |
| Secret source | `/home/dank/Containers/gitea/env` (mode 0600, `ls -l` 2026-10-18) | `/home/dank/serverAppConfigs/dankclaw/.env` (`authentik-postgres.container:19`) |
`shared/homepage/services.json` reflects both: its `Postgres` card reads "Authentik's
and Gitea's databases (Dankclaw). Not probeable: 5432 is container-internal."
## Configuration
Retired compose-era definition (kept for the history below — the live stack is
Quadlet, and this service ran from `compose.yaml` before the 2026 boot-persistence
cutover). Note the data path in it (`/opt/gitea/data/gitea-postgres`) no longer
exists; nothing deploys this block today.
```yaml
services:
postgres:
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: gitea
POSTGRES_PASSWORD: "${GITEA_DB_PASSWORD}"
POSTGRES_DB: gitea
volumes:
- /opt/gitea/data/gitea-postgres:/var/lib/postgresql/data
```
## Gitea Connection
Gitea reaches its database over the `systemd-gitea` network. The live quadlet unit
`dankclaw/gitea/quadlet/gitea-server.container:24-29` sets exactly these variables
(`Environment=DATABASE_*`), so the compose-era block below is equivalent in keys:
```yaml
environment:
DATABASE_TYPE: postgres
DATABASE_HOST: gitea-postgres
DATABASE_NAME: gitea
DATABASE_USER: gitea
DATABASE_PASSWD: "${GITEA_DB_PASSWORD}"
```
The live `app.ini` on the host overrides env vars: its `[database]` stanza carries
`HOST = gitea-postgres:5432`, `NAME = gitea`, `USER = gitea`
(`/home/dank/Containers/gitea/data/gitea/conf/app.ini:27-33`, 2026-10-18). When you
rename the database container, update that `[database] HOST` line. See [[Gitea]]
Gotchas.
## Layout (current)
Both live units mount their data under `/home/dank/Containers`:
- `gitea-postgres` → `/home/dank/Containers/gitea/postgres:/var/lib/postgresql/data`
- `authentik-postgres` → `/home/dank/Containers/authentik/postgres:/var/lib/postgresql/data`
Both directories exist on the host with mode 0700 and owner uid 100069 (the mapped
`postgres` uid of the rootless namespace) — `ls -ld` 2026-10-18. The old
`/opt/gitea/data/gitea-postgres` compose-era path is gone. Secrets come from
host-local env files (`/home/dank/Containers/gitea/env`, 0600;
`/home/dank/serverAppConfigs/dankclaw/.env`) via `EnvironmentFile=`; the passwords
never enter this repo. See [[Gitea]] and [[Authentik]].
## Boot persistence (Quadlet)
Both units carry `Restart=always` (`gitea-postgres.container:28`,
`authentik-postgres.container:38`) and `[Install] WantedBy=default.target`
(`gitea-postgres.container:31`, `authentik-postgres.container:41-42`), are installed
under `~/.config/containers/systemd/`, and report `generated` / `active` with
`Linger=yes` on the host (2026-10-18), so both come back at boot.
## Healthcheck
Only `authentik-postgres` has one. Its quadlet runs bare argv, not a shell string,
because the generator space-splits `HealthCmd` (the quoted `/bin/sh -c "…"` form
arrived mangled and reported a false-negative `unhealthy` forever — see the comment
in `dankclaw/authentik/quadlet/authentik-postgres.container:24-33`):
```ini
HealthCmd=pg_isready -d authentik -U authentik
HealthInterval=30s
```
`gitea-postgres` has **no** `HealthCmd`; the probe below is the compose-era snippet,
kept as the recipe to add if Gitea's DB ever needs one. Until it is in the unit,
judge `gitea-postgres` by `podman ps` state and Gitea's own health.
```yaml
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea"]
interval: 30s
timeout: 5s
retries: 3
```
## Gotchas
- Two clusters, not one: `gitea-postgres` serves only Gitea and
`authentik-postgres` only Authentik. They are on different bridges
(`systemd-gitea` 10.89.0.0/24 vs `dankclaw_default` 10.89.1.0/24, `podman network
inspect` 2026-10-18), so neither can reach the other's data by name. Any
"one Postgres serves everything" reading of this page is wrong.
- The database password must match between the `postgres` container and Gitea's `DATABASE_PASSWD`; both come from the same env-file variable (`GITEA_DB_PASSWORD`, expanded by systemd from `/home/dank/Containers/gitea/env`).
- Do not change the Gitea `SECRET_KEY` or `INTERNAL_TOKEN` after migration — encrypted data becomes unreadable.
- Back up with `pg_dump`; see [[Gitea]] (knowledge base).
## See Also
- [[Gitea]]
- [[Dankclaw Stack]]
## Citations
- `dankclaw/gitea/quadlet/gitea-postgres.container`, `dankclaw/gitea/quadlet/gitea.network`, `dankclaw/gitea/quadlet/gitea-server.container`
- `dankclaw/authentik/quadlet/authentik-postgres.container`
- `shared/homepage/services.json` (the `Postgres` card)
- Host evidence 2026-10-18: `podman ps`, `podman inspect`, `podman network inspect systemd-gitea dankclaw_default`, `ss -ltn`, TCP probe of `192.168.0.143:5432`, `systemctl --user is-enabled/is-active gitea-postgres authentik-postgres`