Files
mc_cars_gmbh_infraestructure/docker-compose.yml
T

332 lines
12 KiB
YAML

name: mc-cars
############################################################
# MC Cars - fully Dockerized self-hosted Supabase + web
#
# Host deployment root:
# - ALL bind mounts resolve under /mnt/user/appdata/mc-cars.
# - Runtime state lives under /mnt/user/appdata/mc-cars/data.
# - Config lives under /mnt/user/appdata/mc-cars/{supabase,frontend}.
# - Deploy this stack from that host folder so Docker sees the same
# absolute paths on every restart.
############################################################
networks:
mccars:
driver: bridge
services:
# -------------------------------------------------------------------------
# Postgres with logical replication enabled (needed by supabase/realtime).
# First-boot SQL creates the Supabase service roles.
# -------------------------------------------------------------------------
db:
image: postgres:15-alpine
container_name: mccars-db
restart: unless-stopped
command:
- postgres
- -c
- wal_level=logical
- -c
- max_wal_senders=10
- -c
- max_replication_slots=10
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
interval: 5s
timeout: 5s
retries: 30
environment:
POSTGRES_USER: postgres
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- /mnt/user/appdata/mc-cars/data/db:/var/lib/postgresql/data
- /mnt/user/appdata/mc-cars/supabase/migrations/00-run-init.sh:/docker-entrypoint-initdb.d/00-run-init.sh:ro
- /mnt/user/appdata/mc-cars/supabase/migrations/01-init.sql:/sql/01-init.sql:ro
ports:
- "55532:5432"
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
# -------------------------------------------------------------------------
# GoTrue (Supabase Auth)
# -------------------------------------------------------------------------
auth:
image: supabase/gotrue:v2.158.1
container_name: mccars-auth
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
GOTRUE_API_HOST: 0.0.0.0
GOTRUE_API_PORT: 9999
API_EXTERNAL_URL: ${API_EXTERNAL_URL}
GOTRUE_DB_DRIVER: postgres
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?search_path=auth
DB_NAMESPACE: auth
GOTRUE_SITE_URL: ${SITE_URL}
GOTRUE_URI_ALLOW_LIST: ${GOTRUE_URI_ALLOW_LIST}
GOTRUE_DISABLE_SIGNUP: ${DISABLE_SIGNUP}
GOTRUE_JWT_ADMIN_ROLES: service_role
GOTRUE_JWT_AUD: authenticated
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
GOTRUE_JWT_EXP: ${JWT_EXPIRY}
GOTRUE_JWT_SECRET: ${JWT_SECRET}
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM}
GOTRUE_SMTP_ADMIN_EMAIL: ${ADMIN_EMAIL}
GOTRUE_SMTP_HOST: ${SMTP_HOST}
GOTRUE_SMTP_PORT: ${SMTP_PORT}
GOTRUE_SMTP_USER: ${SMTP_USER}
GOTRUE_SMTP_PASS: ${SMTP_PASS}
GOTRUE_SMTP_SENDER_NAME: MC Cars
GOTRUE_PASSWORD_MIN_LENGTH: 10
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
# -------------------------------------------------------------------------
# PostgREST (REST API generated from Postgres schema)
# -------------------------------------------------------------------------
rest:
image: postgrest/postgrest:v12.2.0
container_name: mccars-rest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
PGRST_DB_SCHEMAS: public,storage
PGRST_DB_ANON_ROLE: anon
PGRST_JWT_SECRET: ${JWT_SECRET}
PGRST_DB_USE_LEGACY_GUCS: "false"
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
# -------------------------------------------------------------------------
# Storage API + imgproxy
# -------------------------------------------------------------------------
storage:
image: supabase/storage-api:v1.11.13
container_name: mccars-storage
restart: unless-stopped
depends_on:
db:
condition: service_healthy
rest:
condition: service_started
imgproxy:
condition: service_started
environment:
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}@db:5432/${POSTGRES_DB}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT}
STORAGE_BACKEND: ${STORAGE_BACKEND}
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
TENANT_ID: stub
REGION: stub
GLOBAL_S3_BUCKET: stub
ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:5001
volumes:
- /mnt/user/appdata/mc-cars/data/storage:/var/lib/storage
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
imgproxy:
image: darthsim/imgproxy:v3.8.0
container_name: mccars-imgproxy
restart: unless-stopped
environment:
IMGPROXY_BIND: ":5001"
IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
IMGPROXY_USE_ETAG: "true"
IMGPROXY_ENABLE_WEBP_DETECTION: "true"
volumes:
- /mnt/user/appdata/mc-cars/data/storage:/var/lib/storage
networks: [mccars]
# -------------------------------------------------------------------------
# Realtime (Phoenix/Elixir) - live subscriptions for leads/customers
# -------------------------------------------------------------------------
realtime:
image: supabase/realtime:v2.30.23
container_name: mccars-realtime
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
PORT: 4000
DB_HOST: db
DB_PORT: 5432
DB_USER: postgres
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_NAME: ${POSTGRES_DB}
DB_AFTER_CONNECT_QUERY: 'SET search_path TO _realtime'
DB_ENC_KEY: supabaserealtime
API_JWT_SECRET: ${JWT_SECRET}
FLY_ALLOC_ID: fly123
FLY_APP_NAME: realtime
SECRET_KEY_BASE: UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
ERL_AFLAGS: -proto_dist inet_tcp
ENABLE_TAILSCALE: "false"
DNS_NODES: "''"
RLIMIT_NOFILE: "10000"
APP_NAME: realtime
REALTIME_IP_VERSION: IPV4
command: >
sh -c "/app/bin/migrate && /app/bin/server"
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
# -------------------------------------------------------------------------
# Post-init: admin user + storage bucket + leads/customers migration.
# Exits 0 once done. Re-running is idempotent.
# -------------------------------------------------------------------------
post-init:
image: postgres:15-alpine
container_name: mccars-postinit
depends_on:
auth:
condition: service_started
storage:
condition: service_started
environment:
PGPASSWORD: ${POSTGRES_PASSWORD}
ADMIN_EMAIL: ${ADMIN_EMAIL}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
volumes:
- /mnt/user/appdata/mc-cars/supabase/migrations/post-boot.sql:/sql/post-boot.sql:ro
- /mnt/user/appdata/mc-cars/supabase/migrations/02-leads.sql:/sql/02-leads.sql:ro
entrypoint: ["sh","-c"]
command:
- |
set -e
echo "Waiting for auth.users and storage.buckets..."
for i in $$(seq 1 60); do
if psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -tAc "select 1 from auth.users limit 1" >/dev/null 2>&1 \
&& psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -tAc "select 1 from storage.buckets limit 1" >/dev/null 2>&1; then
echo "Schemas ready."
break
fi
sleep 2
done
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 \
-v admin_email="$$ADMIN_EMAIL" \
-v admin_password="$$ADMIN_PASSWORD" \
-f /sql/post-boot.sql
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 -f /sql/02-leads.sql
echo "post-init done."
restart: "no"
networks: [mccars]
# -------------------------------------------------------------------------
# postgres-meta (Studio uses this for schema introspection)
# -------------------------------------------------------------------------
meta:
image: supabase/postgres-meta:v0.84.2
container_name: mccars-meta
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
PG_META_PORT: 8080
PG_META_DB_HOST: db
PG_META_DB_PORT: 5432
PG_META_DB_NAME: ${POSTGRES_DB}
PG_META_DB_USER: postgres
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
networks: [mccars]
# -------------------------------------------------------------------------
# Kong - single API gateway for the browser
# -------------------------------------------------------------------------
kong:
image: kong:2.8.1
container_name: mccars-kong
restart: unless-stopped
depends_on:
- auth
- rest
- storage
- meta
- realtime
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
KONG_DNS_ORDER: LAST,A,CNAME
KONG_PLUGINS: bundled,request-transformer,cors,key-auth,acl,basic-auth
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
volumes:
- /mnt/user/appdata/mc-cars/supabase/kong.yml:/home/kong/kong.yml:ro
ports:
- "55521:8000/tcp"
- "55543:8443/tcp"
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
# -------------------------------------------------------------------------
# Supabase Studio
# -------------------------------------------------------------------------
studio:
image: supabase/studio:20241202-71e5240
container_name: mccars-studio
restart: unless-stopped
depends_on:
meta:
condition: service_started
environment:
STUDIO_PG_META_URL: http://meta:8080
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
DEFAULT_ORGANIZATION_NAME: MC Cars
DEFAULT_PROJECT_NAME: mc-cars
SUPABASE_URL: http://kong:8000
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
AUTH_JWT_SECRET: ${JWT_SECRET}
LOGFLARE_API_KEY: stub
LOGFLARE_URL: http://localhost:4000
NEXT_PUBLIC_ENABLE_LOGS: "false"
ports:
- "55530:3000"
networks: [mccars]
# -------------------------------------------------------------------------
# Public website (nginx + static assets). Anon key injected at boot.
# No build step — Portainer-compatible (image + bind mounts).
# -------------------------------------------------------------------------
web:
image: nginx:1.27-alpine
container_name: mccars-web
restart: unless-stopped
depends_on:
- kong
environment:
SUPABASE_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_ANON_KEY: ${ANON_KEY}
volumes:
- /mnt/user/appdata/mc-cars/frontend:/usr/share/nginx/html
- /mnt/user/appdata/mc-cars/frontend/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- /mnt/user/appdata/mc-cars/frontend/99-config.sh:/docker-entrypoint.d/99-config.sh:ro
ports:
- "55580:80"
networks: [mccars]
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }