256 lines
8.9 KiB
YAML
256 lines
8.9 KiB
YAML
name: mulliganmates
|
|
|
|
x-supabase-env: &supabase-env
|
|
POSTGRES_HOST: ${POSTGRES_HOST:-db}
|
|
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
|
|
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
JWT_SECRET: ${JWT_SECRET}
|
|
ANON_KEY: ${ANON_KEY}
|
|
SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
|
|
|
|
services:
|
|
|
|
# ── Application ────────────────────────────────────────────
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
restart: unless-stopped
|
|
environment:
|
|
NEXT_PUBLIC_SUPABASE_URL: ${SUPABASE_PUBLIC_URL}
|
|
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${ANON_KEY}
|
|
SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
|
|
ADMIN_EMAIL: ${ADMIN_EMAIL}
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.mulliganmates.rule=Host(`${APP_DOMAIN}`)"
|
|
- "traefik.http.routers.mulliganmates.entrypoints=websecure"
|
|
- "traefik.http.routers.mulliganmates.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.mulliganmates.loadbalancer.server.port=3000"
|
|
networks:
|
|
- traefik
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
auth:
|
|
condition: service_started
|
|
|
|
# ── Supabase: Database ─────────────────────────────────────
|
|
db:
|
|
image: supabase/postgres:15.8.1.085
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
environment:
|
|
<<: *supabase-env
|
|
POSTGRES_HOST: /var/run/postgresql
|
|
volumes:
|
|
- db_data:/var/lib/postgresql/data
|
|
- ./supabase/migrations:/docker-entrypoint-initdb.d:ro
|
|
networks:
|
|
- internal
|
|
|
|
# ── Supabase: Kong (API Gateway) ───────────────────────────
|
|
kong:
|
|
image: kong/kong:3.9.1
|
|
restart: unless-stopped
|
|
environment:
|
|
KONG_DATABASE: "off"
|
|
KONG_DECLARATIVE_CONFIG: /etc/kong/kong.yml
|
|
KONG_DNS_ORDER: LAST,A,CNAME
|
|
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth
|
|
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
|
|
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
|
|
SUPABASE_ANON_KEY: ${ANON_KEY}
|
|
SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
|
|
volumes:
|
|
- ./volumes/api/kong.yml:/etc/kong/kong.yml:ro
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.supabase-api.rule=Host(`${SUPABASE_DOMAIN}`)"
|
|
- "traefik.http.routers.supabase-api.entrypoints=websecure"
|
|
- "traefik.http.routers.supabase-api.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.supabase-api.loadbalancer.server.port=8000"
|
|
networks:
|
|
- traefik
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
# ── Supabase: Auth (GoTrue) ────────────────────────────────
|
|
auth:
|
|
image: supabase/gotrue:v2.186.0
|
|
restart: unless-stopped
|
|
environment:
|
|
<<: *supabase-env
|
|
GOTRUE_API_HOST: "0.0.0.0"
|
|
GOTRUE_API_PORT: 9999
|
|
API_EXTERNAL_URL: ${SUPABASE_PUBLIC_URL}
|
|
GOTRUE_DB_DRIVER: postgres
|
|
GOTRUE_DB_DATABASE_URL: "postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}"
|
|
GOTRUE_SITE_URL: ${SITE_URL}
|
|
GOTRUE_URI_ALLOW_LIST: ${ADDITIONAL_REDIRECT_URLS:-}
|
|
GOTRUE_DISABLE_SIGNUP: "true"
|
|
GOTRUE_JWT_SECRET: ${JWT_SECRET}
|
|
GOTRUE_JWT_EXP: ${JWT_EXPIRY:-3600}
|
|
GOTRUE_MAILER_AUTOCONFIRM: "false"
|
|
GOTRUE_SMTP_HOST: ${SMTP_HOST}
|
|
GOTRUE_SMTP_PORT: ${SMTP_PORT:-1025}
|
|
GOTRUE_SMTP_USER: ${SMTP_USER:-}
|
|
GOTRUE_SMTP_PASS: ${SMTP_PASS:-}
|
|
GOTRUE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME:-MulliganMates}
|
|
GOTRUE_MAILER_URLPATHS_INVITE: "/auth/v1/verify"
|
|
GOTRUE_MAILER_URLPATHS_CONFIRMATION: "/auth/v1/verify"
|
|
GOTRUE_MAILER_URLPATHS_RECOVERY: "/auth/v1/verify"
|
|
GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE: "/auth/v1/verify"
|
|
networks:
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
# ── Supabase: REST (PostgREST) ─────────────────────────────
|
|
rest:
|
|
image: postgrest/postgrest:v14.6
|
|
restart: unless-stopped
|
|
environment:
|
|
PGRST_DB_URI: "postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}"
|
|
PGRST_DB_SCHEMAS: "public,storage,graphql_public"
|
|
PGRST_DB_ANON_ROLE: anon
|
|
PGRST_JWT_SECRET: ${JWT_SECRET}
|
|
PGRST_DB_USE_LEGACY_GUCS: "false"
|
|
PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
|
|
PGRST_APP_SETTINGS_JWT_EXP: ${JWT_EXPIRY:-3600}
|
|
networks:
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
# ── Supabase: Realtime ─────────────────────────────────────
|
|
realtime:
|
|
image: supabase/realtime:v2.76.5
|
|
restart: unless-stopped
|
|
environment:
|
|
PORT: 4000
|
|
DB_HOST: ${POSTGRES_HOST:-db}
|
|
DB_PORT: ${POSTGRES_PORT:-5432}
|
|
DB_USER: supabase_admin
|
|
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
|
DB_NAME: ${POSTGRES_DB:-postgres}
|
|
DB_AFTER_CONNECT_QUERY: "SET search_path TO _realtime"
|
|
DB_ENC_KEY: ${SECRET_KEY_BASE}
|
|
API_JWT_SECRET: ${JWT_SECRET}
|
|
FLY_ALLOC_ID: fly123
|
|
FLY_APP_NAME: realtime
|
|
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
|
|
ERL_AFLAGS: -proto_dist inet_tcp
|
|
DNS_NODES: "''"
|
|
RLIMIT_NOFILE: "10000"
|
|
networks:
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
# ── Supabase: Storage ──────────────────────────────────────
|
|
storage:
|
|
image: supabase/storage-api:v1.44.2
|
|
restart: unless-stopped
|
|
environment:
|
|
<<: *supabase-env
|
|
ANON_KEY: ${ANON_KEY}
|
|
SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
|
POSTGREST_URL: http://rest:3000
|
|
PGRST_JWT_SECRET: ${JWT_SECRET}
|
|
DATABASE_URL: "postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}"
|
|
FILE_SIZE_LIMIT: 52428800
|
|
STORAGE_BACKEND: file
|
|
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
|
|
TENANT_ID: stub
|
|
REGION: stub
|
|
GLOBAL_S3_BUCKET: stub
|
|
volumes:
|
|
- storage_data:/var/lib/storage
|
|
networks:
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
rest:
|
|
condition: service_started
|
|
|
|
# ── Supabase: Meta ─────────────────────────────────────────
|
|
meta:
|
|
image: supabase/postgres-meta:v0.95.2
|
|
restart: unless-stopped
|
|
environment:
|
|
PG_META_PORT: 8080
|
|
PG_META_DB_HOST: ${POSTGRES_HOST:-db}
|
|
PG_META_DB_PORT: ${POSTGRES_PORT:-5432}
|
|
PG_META_DB_NAME: ${POSTGRES_DB:-postgres}
|
|
PG_META_DB_USER: supabase_admin
|
|
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
|
networks:
|
|
- internal
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
# ── Supabase: Studio (dev only) ────────────────────────────
|
|
studio:
|
|
image: supabase/studio:2026.03.16-sha-5528817
|
|
restart: unless-stopped
|
|
profiles: ["dev"]
|
|
environment:
|
|
STUDIO_PG_META_URL: http://meta:8080
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
DEFAULT_ORGANIZATION_NAME: MulliganMates
|
|
DEFAULT_PROJECT_NAME: MulliganMates
|
|
SUPABASE_URL: http://kong:8000
|
|
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
|
|
SUPABASE_ANON_KEY: ${ANON_KEY}
|
|
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
|
LOGFLARE_API_KEY: ${LOGFLARE_PUBLIC_ACCESS_TOKEN:-}
|
|
NEXT_PUBLIC_ENABLE_LOGS: "false"
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.supabase-studio.rule=Host(`${STUDIO_DOMAIN}`)"
|
|
- "traefik.http.routers.supabase-studio.entrypoints=websecure"
|
|
- "traefik.http.routers.supabase-studio.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.supabase-studio.loadbalancer.server.port=3000"
|
|
networks:
|
|
- traefik
|
|
- internal
|
|
|
|
# ── Email: Mailpit (dev only) ──────────────────────────────
|
|
mailpit:
|
|
image: axllent/mailpit:latest
|
|
restart: unless-stopped
|
|
profiles: ["dev"]
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.mailpit.rule=Host(`${MAILPIT_DOMAIN}`)"
|
|
- "traefik.http.routers.mailpit.entrypoints=websecure"
|
|
- "traefik.http.routers.mailpit.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.mailpit.loadbalancer.server.port=8025"
|
|
networks:
|
|
- traefik
|
|
- internal
|
|
|
|
volumes:
|
|
db_data:
|
|
storage_data:
|
|
|
|
networks:
|
|
traefik:
|
|
external: true
|
|
internal:
|
|
driver: bridge
|