compose.yml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. # briven data-plane stack — Phase 6 of BACKEND_FORK_BRIEF.md.
  2. #
  3. # Per-project Postgres + REST + Auth + Realtime + Schema-introspection,
  4. # fronted by Caddy. Studio (apps/studio) is deployed separately as a
  5. # Next.js app at studio.briven.tech and talks to this stack via the
  6. # Caddy proxy.
  7. #
  8. # Services dropped from upstream supabase docker-compose:
  9. # - studio (lives in apps/studio, deployed as separate Next app)
  10. # - kong (replaced with caddy — see plan §1)
  11. # - storage / imgproxy (deferred to Phase 9 per brief §5)
  12. # - functions (deferred — briven has separate Deno isolate plan)
  13. # - analytics (logflare) — briven uses Loki+Grafana instead
  14. # - vector (hard-rule violation of docs/DOCKER.md rule 6 —
  15. # bind-mounts /var/run/docker.sock; never re-add)
  16. # - supavisor (deferred to Phase 9 — pool sizing only matters at scale)
  17. #
  18. # Hard rules enforced (docs/DOCKER.md):
  19. # - every service uses logging: *briven-logging (cap 10MB x 3 files)
  20. # - no service mounts /var/run/docker.sock
  21. # - no auto-poll of the Docker API
  22. # - restart: unless-stopped, not always
  23. x-logging: &briven-logging
  24. driver: json-file
  25. options:
  26. max-size: '10m'
  27. max-file: '3'
  28. services:
  29. # ── Reverse proxy ────────────────────────────────────────────────────
  30. # Strips identifying upstream headers (Server, X-Powered-By) before
  31. # any response leaves the trust zone. Adds Server: briven. Auto-TLS
  32. # via Let's Encrypt if BRIVEN_PUBLIC_HOST is set to a routable domain.
  33. caddy:
  34. image: caddy:2.10-alpine
  35. container_name: briven-caddy
  36. restart: unless-stopped
  37. logging: *briven-logging
  38. networks:
  39. - briven-network
  40. ports:
  41. - '${BRIVEN_PROXY_HTTP_PORT:-8000}:80'
  42. - '${BRIVEN_PROXY_HTTPS_PORT:-8443}:443'
  43. environment:
  44. BRIVEN_PUBLIC_HOST: ${BRIVEN_PUBLIC_HOST:-api.briven.tech}
  45. volumes:
  46. - ./volumes/proxy/caddy/Caddyfile:/etc/caddy/Caddyfile:ro,z
  47. - caddy_data:/data
  48. - caddy_config:/config
  49. depends_on:
  50. auth:
  51. condition: service_healthy
  52. rest:
  53. condition: service_healthy
  54. healthcheck:
  55. test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost/']
  56. interval: 10s
  57. timeout: 5s
  58. retries: 5
  59. # ── Postgres ─────────────────────────────────────────────────────────
  60. # The data plane. Schemas per project are created on demand by the
  61. # control-plane provisioning flow (Phase 7).
  62. db:
  63. image: supabase/postgres:15.8.1.085
  64. container_name: briven-db
  65. restart: unless-stopped
  66. logging: *briven-logging
  67. networks:
  68. - briven-network
  69. ports:
  70. - '${BRIVEN_DB_HOST_PORT:-5432}:5432'
  71. environment:
  72. POSTGRES_HOST: /var/run/postgresql
  73. POSTGRES_PORT: 5432
  74. POSTGRES_DB: ${BRIVEN_POSTGRES_DB:-postgres}
  75. POSTGRES_PASSWORD: ${BRIVEN_POSTGRES_PASSWORD:?BRIVEN_POSTGRES_PASSWORD is required}
  76. PGPORT: 5432
  77. PGPASSWORD: ${BRIVEN_POSTGRES_PASSWORD:?BRIVEN_POSTGRES_PASSWORD is required}
  78. PGDATABASE: ${BRIVEN_POSTGRES_DB:-postgres}
  79. JWT_SECRET: ${BRIVEN_JWT_SECRET:?BRIVEN_JWT_SECRET is required}
  80. JWT_EXP: ${BRIVEN_JWT_EXP:-3600}
  81. volumes:
  82. - briven-db-data:/var/lib/postgresql/data
  83. - briven-db-config:/etc/postgresql-custom
  84. - ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
  85. - ./volumes/db/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:Z
  86. - ./volumes/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:Z
  87. - ./volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z
  88. - ./volumes/db/_briven.sql:/docker-entrypoint-initdb.d/migrations/97-_briven.sql:Z
  89. - ./volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z
  90. healthcheck:
  91. test: ['CMD', 'pg_isready', '-U', 'postgres', '-h', 'localhost']
  92. interval: 5s
  93. timeout: 5s
  94. retries: 10
  95. # ── Auth (gotrue) ────────────────────────────────────────────────────
  96. # GOTRUE_* env names are baked into the upstream Go binary; we wrap
  97. # them with BRIVEN_AUTH_* indirection at the compose layer. Caddy
  98. # strips response headers (Server, X-Powered-By, Via) — see
  99. # volumes/proxy/caddy/Caddyfile. Response BODY scrubbing of upstream
  100. # identifiers (gotrue error messages, postgrest hints) is not yet
  101. # implemented — vanilla caddy:2-alpine lacks the replace-response
  102. # module. Tracked in HANDOFF.md §"Carry-over gaps".
  103. auth:
  104. image: supabase/gotrue:v2.186.0
  105. container_name: briven-auth
  106. restart: unless-stopped
  107. logging: *briven-logging
  108. networks:
  109. - briven-network
  110. depends_on:
  111. db:
  112. condition: service_healthy
  113. environment:
  114. GOTRUE_API_HOST: 0.0.0.0
  115. GOTRUE_API_PORT: 9999
  116. API_EXTERNAL_URL: ${BRIVEN_API_EXTERNAL_URL:?BRIVEN_API_EXTERNAL_URL is required}
  117. GOTRUE_DB_DRIVER: postgres
  118. GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${BRIVEN_POSTGRES_PASSWORD}@db:5432/${BRIVEN_POSTGRES_DB:-postgres}
  119. GOTRUE_SITE_URL: ${BRIVEN_AUTH_SITE_URL:?BRIVEN_AUTH_SITE_URL is required}
  120. GOTRUE_URI_ALLOW_LIST: ${BRIVEN_AUTH_URI_ALLOW_LIST:-}
  121. GOTRUE_DISABLE_SIGNUP: ${BRIVEN_AUTH_DISABLE_SIGNUP:-false}
  122. GOTRUE_JWT_ADMIN_ROLES: service_role
  123. GOTRUE_JWT_AUD: authenticated
  124. GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
  125. GOTRUE_JWT_EXP: ${BRIVEN_JWT_EXP:-3600}
  126. GOTRUE_JWT_SECRET: ${BRIVEN_JWT_SECRET}
  127. GOTRUE_EXTERNAL_EMAIL_ENABLED: ${BRIVEN_AUTH_EMAIL_ENABLED:-true}
  128. GOTRUE_MAILER_AUTOCONFIRM: ${BRIVEN_AUTH_MAILER_AUTOCONFIRM:-false}
  129. GOTRUE_SMTP_HOST: ${BRIVEN_AUTH_SMTP_HOST:-}
  130. GOTRUE_SMTP_PORT: ${BRIVEN_AUTH_SMTP_PORT:-587}
  131. GOTRUE_SMTP_USER: ${BRIVEN_AUTH_SMTP_USER:-}
  132. GOTRUE_SMTP_PASS: ${BRIVEN_AUTH_SMTP_PASS:-}
  133. GOTRUE_SMTP_ADMIN_EMAIL: ${BRIVEN_AUTH_SMTP_ADMIN_EMAIL:-}
  134. GOTRUE_SMTP_SENDER_NAME: ${BRIVEN_AUTH_SMTP_SENDER_NAME:-briven}
  135. healthcheck:
  136. test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:9999/health']
  137. interval: 5s
  138. timeout: 5s
  139. retries: 10
  140. # ── PostgREST ────────────────────────────────────────────────────────
  141. # Auto-generates a REST API from the DB schema. PGRST_* names are
  142. # native; wrapped via BRIVEN_REST_* at the compose layer.
  143. rest:
  144. image: postgrest/postgrest:v14.8
  145. container_name: briven-rest
  146. restart: unless-stopped
  147. logging: *briven-logging
  148. networks:
  149. - briven-network
  150. depends_on:
  151. db:
  152. condition: service_healthy
  153. environment:
  154. PGRST_DB_URI: postgres://authenticator:${BRIVEN_POSTGRES_PASSWORD}@db:5432/${BRIVEN_POSTGRES_DB:-postgres}
  155. PGRST_DB_SCHEMAS: ${BRIVEN_REST_DB_SCHEMAS:-public,storage,graphql_public}
  156. PGRST_DB_ANON_ROLE: anon
  157. PGRST_JWT_SECRET: ${BRIVEN_JWT_SECRET}
  158. PGRST_DB_USE_LEGACY_GUCS: 'false'
  159. PGRST_APP_SETTINGS_JWT_SECRET: ${BRIVEN_JWT_SECRET}
  160. PGRST_APP_SETTINGS_JWT_EXP: ${BRIVEN_JWT_EXP:-3600}
  161. command:
  162. - 'postgrest'
  163. healthcheck:
  164. test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/']
  165. interval: 5s
  166. timeout: 5s
  167. retries: 10
  168. # ── Realtime (Phoenix) ───────────────────────────────────────────────
  169. # WebSocket subscriptions on Postgres logical replication. Native env
  170. # names (API_JWT_SECRET, DB_HOST, etc.) wrapped via BRIVEN_REALTIME_*.
  171. realtime:
  172. image: supabase/realtime:v2.76.5
  173. container_name: briven-realtime
  174. restart: unless-stopped
  175. logging: *briven-logging
  176. networks:
  177. - briven-network
  178. depends_on:
  179. db:
  180. condition: service_healthy
  181. environment:
  182. PORT: 4000
  183. DB_HOST: db
  184. DB_PORT: 5432
  185. DB_USER: supabase_admin
  186. DB_PASSWORD: ${BRIVEN_POSTGRES_PASSWORD}
  187. DB_NAME: ${BRIVEN_POSTGRES_DB:-postgres}
  188. DB_AFTER_CONNECT_QUERY: 'SET search_path TO _realtime'
  189. DB_ENC_KEY: ${BRIVEN_REALTIME_ENC_KEY:?BRIVEN_REALTIME_ENC_KEY is required}
  190. API_JWT_SECRET: ${BRIVEN_JWT_SECRET}
  191. SECRET_KEY_BASE: ${BRIVEN_REALTIME_SECRET_KEY_BASE:?BRIVEN_REALTIME_SECRET_KEY_BASE is required}
  192. ERL_AFLAGS: -proto_dist inet_tcp
  193. DNS_NODES: "''"
  194. RLIMIT_NOFILE: '10000'
  195. APP_NAME: realtime
  196. SEED_SELF_HOST: 'true'
  197. RUN_JANITOR: 'true'
  198. healthcheck:
  199. test:
  200. - CMD-SHELL
  201. - 'curl -sSfL --head -o /dev/null -H "Authorization: Bearer ${BRIVEN_JWT_SECRET}" http://localhost:4000/api/tenants/realtime-dev/health'
  202. interval: 5s
  203. timeout: 5s
  204. retries: 3
  205. # ── postgres-meta ────────────────────────────────────────────────────
  206. # Schema introspection backend that Studio reads from. PG_META_* native;
  207. # wrapped via BRIVEN_META_*.
  208. meta:
  209. image: supabase/postgres-meta:v0.96.3
  210. container_name: briven-meta
  211. restart: unless-stopped
  212. logging: *briven-logging
  213. networks:
  214. - briven-network
  215. depends_on:
  216. db:
  217. condition: service_healthy
  218. environment:
  219. PG_META_PORT: 8080
  220. PG_META_DB_HOST: db
  221. PG_META_DB_PORT: 5432
  222. PG_META_DB_NAME: ${BRIVEN_POSTGRES_DB:-postgres}
  223. PG_META_DB_USER: supabase_admin
  224. PG_META_DB_PASSWORD: ${BRIVEN_POSTGRES_PASSWORD}
  225. healthcheck:
  226. test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:8080/health']
  227. interval: 10s
  228. timeout: 5s
  229. retries: 5
  230. # ── pgBackRest ───────────────────────────────────────────────────────
  231. # Phase 9 of BACKEND_FORK_BRIEF.md. Continuous WAL archive + incremental
  232. # backups to Cloudflare R2 every 15 minutes; full backup nightly. Reads
  233. # PGDATA via a shared bind-mount with the db service (NOT via the
  234. # daemon API). Restore procedure documented in infra/datapane/RESTORE.md.
  235. pgbackrest:
  236. image: pgbackrest/pgbackrest:2.55.1
  237. container_name: briven-pgbackrest
  238. restart: unless-stopped
  239. logging: *briven-logging
  240. networks:
  241. - briven-network
  242. depends_on:
  243. db:
  244. condition: service_healthy
  245. environment:
  246. PGBACKREST_REPO1_TYPE: s3
  247. PGBACKREST_REPO1_S3_BUCKET: ${BRIVEN_BACKUP_R2_BUCKET:?BRIVEN_BACKUP_R2_BUCKET is required}
  248. PGBACKREST_REPO1_S3_ENDPOINT: ${BRIVEN_BACKUP_R2_ENDPOINT:?BRIVEN_BACKUP_R2_ENDPOINT is required}
  249. PGBACKREST_REPO1_S3_REGION: auto
  250. PGBACKREST_REPO1_S3_KEY: ${BRIVEN_BACKUP_R2_ACCESS_KEY:?BRIVEN_BACKUP_R2_ACCESS_KEY is required}
  251. PGBACKREST_REPO1_S3_KEY_SECRET: ${BRIVEN_BACKUP_R2_SECRET_KEY:?BRIVEN_BACKUP_R2_SECRET_KEY is required}
  252. PGBACKREST_REPO1_RETENTION_FULL: '4'
  253. PGBACKREST_REPO1_RETENTION_DIFF: '7'
  254. PGBACKREST_REPO1_CIPHER_TYPE: aes-256-cbc
  255. PGBACKREST_REPO1_CIPHER_PASS: ${BRIVEN_BACKUP_ENCRYPTION_KEY:?BRIVEN_BACKUP_ENCRYPTION_KEY is required}
  256. PGBACKREST_PROCESS_MAX: '2'
  257. PGBACKREST_COMPRESS_TYPE: zst
  258. PGBACKREST_LOG_LEVEL_FILE: info
  259. PGBACKREST_LOG_LEVEL_CONSOLE: warn
  260. volumes:
  261. - briven-db-data:/var/lib/postgresql/data:ro
  262. - briven-backup-cache:/var/lib/pgbackrest
  263. - ./pgbackrest/pgbackrest.conf:/etc/pgbackrest/pgbackrest.conf:ro,z
  264. - ./pgbackrest/crontab:/etc/crontabs/root:ro,z
  265. - ./pgbackrest/entrypoint.sh:/entrypoint.sh:ro,z
  266. entrypoint: ['/bin/sh']
  267. command: ['/entrypoint.sh']
  268. healthcheck:
  269. test: ['CMD', 'pgbackrest', '--stanza=briven', 'check']
  270. interval: 1m
  271. timeout: 30s
  272. retries: 3
  273. networks:
  274. briven-network:
  275. name: briven-network
  276. volumes:
  277. briven-db-data:
  278. name: briven-db-data
  279. briven-db-config:
  280. name: briven-db-config
  281. briven-backup-cache:
  282. name: briven-backup-cache
  283. caddy_data:
  284. name: briven-caddy-data
  285. caddy_config:
  286. name: briven-caddy-config