# Self-hosted Supabase for this tutorial (no secret values here)

Run date: 2026-11-01 to 2026-11-02, macOS, Docker Desktop. Compose file from `supabase/supabase` `docker/` (shallow sparse checkout).

```sh
git clone --depth 1 --filter=blob:none --sparse https://github.com/supabase/supabase supabase-src
cd supabase-src && git sparse-checkout set docker && cd ..
cp -R supabase-src/docker stack && cd stack

# 1. throwaway secrets (JWT secret, anon/service keys, Postgres and dashboard passwords)
cp .env.example .env
sh utils/generate-keys.sh --update-env      # prints and writes the values into .env; do not paste them anywhere

# 2. gateway on a free local port, bound to loopback only
#    (8000 was taken by another container, so this run used 8100)
sed -i.bak -e 's|^API_GW_HTTP_PORT=.*|API_GW_HTTP_PORT=127.0.0.1:8100|' \
           -e 's|^SUPABASE_PUBLIC_URL=.*|SUPABASE_PUBLIC_URL=http://localhost:8100|' \
           -e 's|^API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost:8100/auth/v1|' .env && rm .env.bak

# 3. Postgres pooler ports on loopback only
sed -i.bak 's|^      - ${POSTGRES_PORT}:5432|      - 127.0.0.1:${POSTGRES_PORT}:5432|; s|^      - ${POOLER_PROXY_PORT_TRANSACTION}:6543|      - 127.0.0.1:${POOLER_PROXY_PORT_TRANSACTION}:6543|' docker-compose.yml && rm docker-compose.yml.bak

docker compose -p kb-supabase up -d
docker compose -p kb-supabase ps

# Database URL for psql / psycopg goes through the pooler (user is postgres.<POOLER_TENANT_ID>):
#   postgresql://postgres.your-tenant-id:YOUR_POSTGRES_PASSWORD@127.0.0.1:5432/postgres

# Edge Function: copy functions/kb-query into stack/volumes/functions/kb-query, no restart needed.

# Cleanup
docker compose -p kb-supabase down -v
```

Studio: `http://localhost:8100`, basic auth with DASHBOARD_USERNAME / DASHBOARD_PASSWORD from `.env`.
