Skip to content

Commit f13d844

Browse files
committed
db-backup: document PG_GLOBALS_URL and PostgreSQL superuser for globals dumps
Made-with: Cursor
1 parent 73c2c4d commit f13d844

2 files changed

Lines changed: 62 additions & 0 deletions

File tree

apps/db-backup/.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ BACKUP_RETAIN_YEARLY=6
2525

2626
# Image version (optional, defaults to latest)
2727
#IMAGE_VERSION=latest
28+
29+
# Optional: PostgreSQL superuser URL for pg_dumpall --globals-only (roles, defaults, tablespaces).
30+
# Must use the postgresql:// scheme (not postgres://). See README.md.
31+
#PG_GLOBALS_URL=postgresql://db_backup_globals:YOUR_PASSWORD@postgresql:5432/postgres

apps/db-backup/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,63 @@ BACKUP_DATABASE_URLS="postgresql://user:pass@postgresql:5432/db1,redis://:pass@r
3333

3434
Supported URL schemes: `postgresql://`, `mysql://`, `sqlite:///`, `redis://`
3535

36+
### PostgreSQL per-database vs cluster globals
37+
38+
`BACKUP_DATABASE_URLS` runs **`pg_dump`** per database. That does **not** include cluster-wide objects: roles, role memberships, database-level defaults, tablespaces, and similar metadata. To capture those, the backup image runs **`pg_dumpall --globals-only`** when configured (see **`PG_GLOBALS_URL`** below).
39+
40+
Without **`PG_GLOBALS_URL`**, the service may still attempt a globals dump using credentials from the **first** `postgresql://…` URL discovered under `PARENT_DIR`. Those URLs are usually **application users**, not superusers, so the globals step is often **skipped** (insufficient privileges). For reliable globals backups, set **`PG_GLOBALS_URL`** to a **superuser** connection.
41+
42+
### Creating a dedicated PostgreSQL superuser for globals backup
43+
44+
Use a **dedicated** superuser role (least surprise when rotating app passwords). From the host, with the PostgreSQL container running:
45+
46+
```bash
47+
cd apps/postgresql
48+
# load admin user from compose env (default superuser in the image)
49+
source .env
50+
ADMIN="${POSTGRES_USER:-postgresql}"
51+
```
52+
53+
Open **`psql`** as that admin:
54+
55+
```bash
56+
docker compose exec postgresql psql -U "$ADMIN" -d postgres
57+
```
58+
59+
In **`psql`**, create a login role used only for backups (pick a strong password, e.g. from `pwgen 32 1`):
60+
61+
```sql
62+
CREATE ROLE db_backup_globals WITH LOGIN SUPERUSER PASSWORD 'replace-with-strong-password';
63+
```
64+
65+
**Security:** treat this password like root DB access. Restrict who can read **`db-backup`** `.env` and your secrets store.
66+
67+
You can instead reuse the cluster’s bootstrap superuser (`POSTGRES_USER` / `POSTGRES_PASSWORD` from `apps/postgresql/.env`) in **`PG_GLOBALS_URL`**, but rotating that password is more disruptive than rotating a dedicated backup role.
68+
69+
### `PG_GLOBALS_URL` (db-backup `.env`)
70+
71+
Set this in **`apps/db-backup/.env`** (not in per-app `.env` files). The [hackstack-db-backup](https://github.com/romkey/hackstack-db-backup) image reads it each backup cycle.
72+
73+
| Property | Notes |
74+
|----------|--------|
75+
| **Format** | `postgresql://USER:PASSWORD@HOST:PORT/DBNAME` |
76+
| **Scheme** | Must be **`postgresql://`**. (`postgres://` is not parsed for this feature.) |
77+
| **Privileges** | User must be a **superuser** (or otherwise allowed to run `pg_dumpall --globals-only`). |
78+
| **DBNAME** | Not used for the globals dump; use `postgres` (or any DB the user can connect to). |
79+
| **Hostname** | From the **`dbbackup`** container, the shared service is usually **`postgresql`** on `postgres-net`. |
80+
81+
Example:
82+
83+
```bash
84+
PG_GLOBALS_URL=postgresql://db_backup_globals:your-password@postgresql:5432/postgres
85+
```
86+
87+
**Output file:** `DEST_DIR/postgresql/backup-globals-postgresql-5432-<timestamp>.sql.bz2` (compressed with the same retention logic as other backups under that folder).
88+
89+
If **`PG_GLOBALS_URL`** is unset, globals backup is only attempted with credentials inferred from discovered app URLs and may be skipped if those users are not superusers.
90+
91+
**Special characters in passwords** must be **URL-encoded** in `PG_GLOBALS_URL` (e.g. `@``%40`, `:``%3A`).
92+
3693
## Configuration
3794

3895
### Environment Variables
@@ -57,6 +114,7 @@ cp .env.example .env
57114
| `BACKUP_RETAIN_MONTHLY` | No | `6` | Monthly backups to keep |
58115
| `BACKUP_RETAIN_YEARLY` | No | `6` | Yearly backups to keep |
59116
| `IMAGE_VERSION` | No | `latest` | Docker image tag |
117+
| `PG_GLOBALS_URL` | No || `postgresql://` URL with a **superuser** used for `pg_dumpall --globals-only` (roles / cluster metadata). See [PostgreSQL globals](#postgresql-per-database-vs-cluster-globals). |
60118

61119
## Usage
62120

0 commit comments

Comments
 (0)