myos override for stack supabase
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
ARG SUPABASE_EDGE_RUNTIME_VERSION=v1.65.3
|
||||||
|
FROM supabase/edge-runtime:${SUPABASE_EDGE_RUNTIME_VERSION}
|
||||||
|
ARG DOCKER_BUILD_DIR=.
|
||||||
|
|
||||||
|
RUN mkdir -p /home/deno/functions
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/hello/ /home/deno/functions/hello/
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/main/ /home/deno/functions/main/
|
||||||
|
|
||||||
|
VOLUME /home/deno/functions
|
||||||
|
VOLUME /root/.cache
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Follow this setup guide to integrate the Deno language server with your editor:
|
||||||
|
// https://deno.land/manual/getting_started/setup_your_environment
|
||||||
|
// This enables autocomplete, go to definition, etc.
|
||||||
|
|
||||||
|
import { serve } from "https://deno.land/std@0.177.1/http/server.ts"
|
||||||
|
|
||||||
|
serve(async () => {
|
||||||
|
return new Response(
|
||||||
|
`"Hello from Edge Functions!"`,
|
||||||
|
{ headers: { "Content-Type": "application/json" } },
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// To invoke:
|
||||||
|
// curl 'http://localhost:<KONG_HTTP_PORT>/functions/v1/hello' \
|
||||||
|
// --header 'Authorization: Bearer <anon/service_role API key>'
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
|
||||||
|
import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts'
|
||||||
|
|
||||||
|
console.log('main function started')
|
||||||
|
|
||||||
|
const JWT_SECRET = Deno.env.get('JWT_SECRET')
|
||||||
|
const VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true'
|
||||||
|
|
||||||
|
function getAuthToken(req: Request) {
|
||||||
|
const authHeader = req.headers.get('authorization')
|
||||||
|
if (!authHeader) {
|
||||||
|
throw new Error('Missing authorization header')
|
||||||
|
}
|
||||||
|
const [bearer, token] = authHeader.split(' ')
|
||||||
|
if (bearer !== 'Bearer') {
|
||||||
|
throw new Error(`Auth header is not 'Bearer {token}'`)
|
||||||
|
}
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyJWT(jwt: string): Promise<boolean> {
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
const secretKey = encoder.encode(JWT_SECRET)
|
||||||
|
try {
|
||||||
|
await jose.jwtVerify(jwt, secretKey)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
serve(async (req: Request) => {
|
||||||
|
if (req.method !== 'OPTIONS' && VERIFY_JWT) {
|
||||||
|
try {
|
||||||
|
const token = getAuthToken(req)
|
||||||
|
const isValidJWT = await verifyJWT(token)
|
||||||
|
|
||||||
|
if (!isValidJWT) {
|
||||||
|
return new Response(JSON.stringify({ msg: 'Invalid JWT' }), {
|
||||||
|
status: 401,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return new Response(JSON.stringify({ msg: e.toString() }), {
|
||||||
|
status: 401,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = new URL(req.url)
|
||||||
|
const { pathname } = url
|
||||||
|
const path_parts = pathname.split('/')
|
||||||
|
const service_name = path_parts[1]
|
||||||
|
|
||||||
|
if (!service_name || service_name === '') {
|
||||||
|
const error = { msg: 'missing function name in request' }
|
||||||
|
return new Response(JSON.stringify(error), {
|
||||||
|
status: 400,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const servicePath = `/home/deno/functions/${service_name}`
|
||||||
|
console.error(`serving the request with ${servicePath}`)
|
||||||
|
|
||||||
|
const memoryLimitMb = 150
|
||||||
|
const workerTimeoutMs = 1 * 60 * 1000
|
||||||
|
const noModuleCache = false
|
||||||
|
const importMapPath = null
|
||||||
|
const envVarsObj = Deno.env.toObject()
|
||||||
|
const envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]])
|
||||||
|
|
||||||
|
try {
|
||||||
|
const worker = await EdgeRuntime.userWorkers.create({
|
||||||
|
servicePath,
|
||||||
|
memoryLimitMb,
|
||||||
|
workerTimeoutMs,
|
||||||
|
noModuleCache,
|
||||||
|
importMapPath,
|
||||||
|
envVars,
|
||||||
|
})
|
||||||
|
return await worker.fetch(req)
|
||||||
|
} catch (e) {
|
||||||
|
const error = { msg: e.toString() }
|
||||||
|
return new Response(JSON.stringify(error), {
|
||||||
|
status: 500,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
ARG SUPABASE_KONG_VERSION=3.9.0
|
||||||
|
FROM kong:${SUPABASE_KONG_VERSION}
|
||||||
|
ARG DOCKER_BUILD_DIR=.
|
||||||
|
ARG DOCKER_NETWORK=supabase_default
|
||||||
|
ARG REALTIME_TENANT=realtime-dev
|
||||||
|
|
||||||
|
RUN mkdir -p /home/kong
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/kong.yml /home/kong/temp.yml
|
||||||
|
# realtime tenant is taken from hostname in url
|
||||||
|
RUN sed -i 's/realtime-dev.supabase-realtime/'"${REALTIME_TENANT}"'.'"${DOCKER_NETWORK}"'/' /home/kong/temp.yml
|
||||||
|
|
||||||
|
VOLUME /home/kong
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
_format_version: '2.1'
|
||||||
|
_transform: true
|
||||||
|
|
||||||
|
###
|
||||||
|
### Consumers / Users
|
||||||
|
###
|
||||||
|
consumers:
|
||||||
|
- username: DASHBOARD
|
||||||
|
- username: anon
|
||||||
|
keyauth_credentials:
|
||||||
|
- key: $SUPABASE_ANON_KEY
|
||||||
|
- username: service_role
|
||||||
|
keyauth_credentials:
|
||||||
|
- key: $SUPABASE_SERVICE_KEY
|
||||||
|
|
||||||
|
###
|
||||||
|
### Access Control List
|
||||||
|
###
|
||||||
|
acls:
|
||||||
|
- consumer: anon
|
||||||
|
group: anon
|
||||||
|
- consumer: service_role
|
||||||
|
group: admin
|
||||||
|
|
||||||
|
###
|
||||||
|
### Dashboard credentials
|
||||||
|
###
|
||||||
|
basicauth_credentials:
|
||||||
|
- consumer: DASHBOARD
|
||||||
|
username: $DASHBOARD_USERNAME
|
||||||
|
password: $DASHBOARD_PASSWORD
|
||||||
|
|
||||||
|
###
|
||||||
|
### API Routes
|
||||||
|
###
|
||||||
|
services:
|
||||||
|
## Open Auth routes
|
||||||
|
- name: auth-v1-open
|
||||||
|
url: http://auth:9999/verify
|
||||||
|
routes:
|
||||||
|
- name: auth-v1-open
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /auth/v1/verify
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: auth-v1-open-callback
|
||||||
|
url: http://auth:9999/callback
|
||||||
|
routes:
|
||||||
|
- name: auth-v1-open-callback
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /auth/v1/callback
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: auth-v1-open-authorize
|
||||||
|
url: http://auth:9999/authorize
|
||||||
|
routes:
|
||||||
|
- name: auth-v1-open-authorize
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /auth/v1/authorize
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
|
||||||
|
## Secure Auth routes
|
||||||
|
- name: auth-v1
|
||||||
|
_comment: 'GoTrue: /auth/v1/* -> http://auth:9999/*'
|
||||||
|
url: http://auth:9999/
|
||||||
|
routes:
|
||||||
|
- name: auth-v1-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /auth/v1/
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: key-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: false
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
- anon
|
||||||
|
|
||||||
|
## Secure REST routes
|
||||||
|
- name: rest-v1
|
||||||
|
_comment: 'PostgREST: /rest/v1/* -> http://rest:3000/*'
|
||||||
|
url: http://rest:3000/
|
||||||
|
routes:
|
||||||
|
- name: rest-v1-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /rest/v1/
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: key-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: true
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
- anon
|
||||||
|
|
||||||
|
## Secure GraphQL routes
|
||||||
|
- name: graphql-v1
|
||||||
|
_comment: 'PostgREST: /graphql/v1/* -> http://rest:3000/rpc/graphql'
|
||||||
|
url: http://rest:3000/rpc/graphql
|
||||||
|
routes:
|
||||||
|
- name: graphql-v1-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /graphql/v1
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: key-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: true
|
||||||
|
- name: request-transformer
|
||||||
|
config:
|
||||||
|
add:
|
||||||
|
headers:
|
||||||
|
- Content-Profile:graphql_public
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
- anon
|
||||||
|
|
||||||
|
## Secure Realtime routes
|
||||||
|
- name: realtime-v1-ws
|
||||||
|
_comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
|
||||||
|
url: http://realtime-dev.supabase-realtime:4000/socket
|
||||||
|
protocol: ws
|
||||||
|
routes:
|
||||||
|
- name: realtime-v1-ws
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /realtime/v1/
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: key-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: false
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
- anon
|
||||||
|
- name: realtime-v1-rest
|
||||||
|
_comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
|
||||||
|
url: http://realtime-dev.supabase-realtime:4000/api
|
||||||
|
protocol: http
|
||||||
|
routes:
|
||||||
|
- name: realtime-v1-rest
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /realtime/v1/api
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: key-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: false
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
- anon
|
||||||
|
## Storage routes: the storage server manages its own auth
|
||||||
|
- name: storage-v1
|
||||||
|
_comment: 'Storage: /storage/v1/* -> http://storage:5000/*'
|
||||||
|
url: http://storage:5000/
|
||||||
|
routes:
|
||||||
|
- name: storage-v1-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /storage/v1/
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
|
||||||
|
## Edge Functions routes
|
||||||
|
- name: functions-v1
|
||||||
|
_comment: 'Edge Functions: /functions/v1/* -> http://functions:9000/*'
|
||||||
|
url: http://functions:9000/
|
||||||
|
routes:
|
||||||
|
- name: functions-v1-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /functions/v1/
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
|
||||||
|
## Analytics routes
|
||||||
|
- name: analytics-v1
|
||||||
|
_comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
|
||||||
|
url: http://analytics:4000/
|
||||||
|
routes:
|
||||||
|
- name: analytics-v1-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /analytics/v1/
|
||||||
|
|
||||||
|
## Secure Database routes
|
||||||
|
- name: meta
|
||||||
|
_comment: 'pg-meta: /pg/* -> http://pg-meta:8080/*'
|
||||||
|
url: http://meta:8080/
|
||||||
|
routes:
|
||||||
|
- name: meta-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /pg/
|
||||||
|
plugins:
|
||||||
|
- name: key-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: false
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
|
||||||
|
## Protected Dashboard - catch all remaining routes
|
||||||
|
- name: dashboard
|
||||||
|
_comment: 'Studio: /* -> http://studio:3000/*'
|
||||||
|
url: http://studio:3000/
|
||||||
|
routes:
|
||||||
|
- name: dashboard-all
|
||||||
|
strip_path: true
|
||||||
|
paths:
|
||||||
|
- /
|
||||||
|
plugins:
|
||||||
|
- name: cors
|
||||||
|
- name: basic-auth
|
||||||
|
config:
|
||||||
|
hide_credentials: true
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
ARG SUPABASE_POSTGRES_VERSION=15.6.1.146
|
||||||
|
FROM supabase/postgres:${SUPABASE_POSTGRES_VERSION}
|
||||||
|
ARG DOCKER_BUILD_DIR=.
|
||||||
|
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/realtime.sql /docker-entrypoint-initdb.d/migrations/99-realtime.sql
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/webhooks.sql /docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/roles.sql /docker-entrypoint-initdb.d/init-scripts/99-roles.sql
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/jwt.sql /docker-entrypoint-initdb.d/init-scripts/99-jwt.sql
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/_supabase.sql /docker-entrypoint-initdb.d/migrations/97-_supabase.sql
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/logs.sql /docker-entrypoint-initdb.d/migrations/99-logs.sql
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/pooler.sql /docker-entrypoint-initdb.d/migrations/99-pooler.sql
|
||||||
|
|
||||||
|
VOLUME /etc/postgresql-custom
|
||||||
|
VOLUME /var/lib/postgres
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
\set pguser `echo "$POSTGRES_USER"`
|
||||||
|
|
||||||
|
CREATE DATABASE _supabase WITH OWNER :pguser;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
\set jwt_secret `echo "$JWT_SECRET"`
|
||||||
|
\set jwt_exp `echo "$JWT_EXP"`
|
||||||
|
|
||||||
|
ALTER DATABASE postgres SET "app.settings.jwt_secret" TO :'jwt_secret';
|
||||||
|
ALTER DATABASE postgres SET "app.settings.jwt_exp" TO :'jwt_exp';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
\set pguser `echo "$POSTGRES_USER"`
|
||||||
|
|
||||||
|
\c _supabase
|
||||||
|
create schema if not exists _analytics;
|
||||||
|
alter schema _analytics owner to :pguser;
|
||||||
|
\c postgres
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
\set pguser `echo "$POSTGRES_USER"`
|
||||||
|
|
||||||
|
\c _supabase
|
||||||
|
create schema if not exists _supavisor;
|
||||||
|
alter schema _supavisor owner to :pguser;
|
||||||
|
\c postgres
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
\set pguser `echo "$POSTGRES_USER"`
|
||||||
|
|
||||||
|
create schema if not exists _realtime;
|
||||||
|
alter schema _realtime owner to :pguser;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- NOTE: change to your own passwords for production environments
|
||||||
|
\set pgpass `echo "$POSTGRES_PASSWORD"`
|
||||||
|
|
||||||
|
ALTER USER authenticator WITH PASSWORD :'pgpass';
|
||||||
|
ALTER USER pgbouncer WITH PASSWORD :'pgpass';
|
||||||
|
ALTER USER supabase_auth_admin WITH PASSWORD :'pgpass';
|
||||||
|
ALTER USER supabase_functions_admin WITH PASSWORD :'pgpass';
|
||||||
|
ALTER USER supabase_storage_admin WITH PASSWORD :'pgpass';
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
BEGIN;
|
||||||
|
-- Create pg_net extension
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions;
|
||||||
|
-- Create supabase_functions schema
|
||||||
|
CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin;
|
||||||
|
GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role;
|
||||||
|
-- supabase_functions.migrations definition
|
||||||
|
CREATE TABLE supabase_functions.migrations (
|
||||||
|
version text PRIMARY KEY,
|
||||||
|
inserted_at timestamptz NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
-- Initial supabase_functions migration
|
||||||
|
INSERT INTO supabase_functions.migrations (version) VALUES ('initial');
|
||||||
|
-- supabase_functions.hooks definition
|
||||||
|
CREATE TABLE supabase_functions.hooks (
|
||||||
|
id bigserial PRIMARY KEY,
|
||||||
|
hook_table_id integer NOT NULL,
|
||||||
|
hook_name text NOT NULL,
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
request_id bigint
|
||||||
|
);
|
||||||
|
CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id);
|
||||||
|
CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name);
|
||||||
|
COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.';
|
||||||
|
CREATE FUNCTION supabase_functions.http_request()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
DECLARE
|
||||||
|
request_id bigint;
|
||||||
|
payload jsonb;
|
||||||
|
url text := TG_ARGV[0]::text;
|
||||||
|
method text := TG_ARGV[1]::text;
|
||||||
|
headers jsonb DEFAULT '{}'::jsonb;
|
||||||
|
params jsonb DEFAULT '{}'::jsonb;
|
||||||
|
timeout_ms integer DEFAULT 1000;
|
||||||
|
BEGIN
|
||||||
|
IF url IS NULL OR url = 'null' THEN
|
||||||
|
RAISE EXCEPTION 'url argument is missing';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF method IS NULL OR method = 'null' THEN
|
||||||
|
RAISE EXCEPTION 'method argument is missing';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN
|
||||||
|
headers = '{"Content-Type": "application/json"}'::jsonb;
|
||||||
|
ELSE
|
||||||
|
headers = TG_ARGV[2]::jsonb;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN
|
||||||
|
params = '{}'::jsonb;
|
||||||
|
ELSE
|
||||||
|
params = TG_ARGV[3]::jsonb;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN
|
||||||
|
timeout_ms = 1000;
|
||||||
|
ELSE
|
||||||
|
timeout_ms = TG_ARGV[4]::integer;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CASE
|
||||||
|
WHEN method = 'GET' THEN
|
||||||
|
SELECT http_get INTO request_id FROM net.http_get(
|
||||||
|
url,
|
||||||
|
params,
|
||||||
|
headers,
|
||||||
|
timeout_ms
|
||||||
|
);
|
||||||
|
WHEN method = 'POST' THEN
|
||||||
|
payload = jsonb_build_object(
|
||||||
|
'old_record', OLD,
|
||||||
|
'record', NEW,
|
||||||
|
'type', TG_OP,
|
||||||
|
'table', TG_TABLE_NAME,
|
||||||
|
'schema', TG_TABLE_SCHEMA
|
||||||
|
);
|
||||||
|
|
||||||
|
SELECT http_post INTO request_id FROM net.http_post(
|
||||||
|
url,
|
||||||
|
payload,
|
||||||
|
params,
|
||||||
|
headers,
|
||||||
|
timeout_ms
|
||||||
|
);
|
||||||
|
ELSE
|
||||||
|
RAISE EXCEPTION 'method argument % is invalid', method;
|
||||||
|
END CASE;
|
||||||
|
|
||||||
|
INSERT INTO supabase_functions.hooks
|
||||||
|
(hook_table_id, hook_name, request_id)
|
||||||
|
VALUES
|
||||||
|
(TG_RELID, TG_NAME, request_id);
|
||||||
|
|
||||||
|
RETURN NEW;
|
||||||
|
END
|
||||||
|
$function$;
|
||||||
|
-- Supabase super admin
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_roles
|
||||||
|
WHERE rolname = 'supabase_functions_admin'
|
||||||
|
)
|
||||||
|
THEN
|
||||||
|
CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin;
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin;
|
||||||
|
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin;
|
||||||
|
ALTER USER supabase_functions_admin SET search_path = "supabase_functions";
|
||||||
|
ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin;
|
||||||
|
ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin;
|
||||||
|
ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin;
|
||||||
|
GRANT supabase_functions_admin TO postgres;
|
||||||
|
-- Remove unused supabase_pg_net_admin role
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_roles
|
||||||
|
WHERE rolname = 'supabase_pg_net_admin'
|
||||||
|
)
|
||||||
|
THEN
|
||||||
|
REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin;
|
||||||
|
DROP OWNED BY supabase_pg_net_admin;
|
||||||
|
DROP ROLE supabase_pg_net_admin;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
-- pg_net grants when extension is already enabled
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_extension
|
||||||
|
WHERE extname = 'pg_net'
|
||||||
|
)
|
||||||
|
THEN
|
||||||
|
GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
|
||||||
|
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
|
||||||
|
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
|
||||||
|
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
|
||||||
|
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
|
||||||
|
REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
|
||||||
|
REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
|
||||||
|
GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
|
||||||
|
GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
-- Event trigger for pg_net
|
||||||
|
CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access()
|
||||||
|
RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_event_trigger_ddl_commands() AS ev
|
||||||
|
JOIN pg_extension AS ext
|
||||||
|
ON ev.objid = ext.oid
|
||||||
|
WHERE ext.extname = 'pg_net'
|
||||||
|
)
|
||||||
|
THEN
|
||||||
|
GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
|
||||||
|
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
|
||||||
|
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
|
||||||
|
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
|
||||||
|
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
|
||||||
|
REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
|
||||||
|
REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
|
||||||
|
GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
|
||||||
|
GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net';
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_event_trigger
|
||||||
|
WHERE evtname = 'issue_pg_net_access'
|
||||||
|
) THEN
|
||||||
|
CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION')
|
||||||
|
EXECUTE PROCEDURE extensions.grant_pg_net_access();
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants');
|
||||||
|
ALTER function supabase_functions.http_request() SECURITY DEFINER;
|
||||||
|
ALTER function supabase_functions.http_request() SET search_path = supabase_functions;
|
||||||
|
REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC;
|
||||||
|
GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role;
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
ARG SUPABASE_VECTOR_VERSION=0.28.1-alpine
|
||||||
|
FROM timberio/vector:${SUPABASE_VECTOR_VERSION}
|
||||||
|
ARG DOCKER_BUILD_DIR=.
|
||||||
|
|
||||||
|
COPY ${DOCKER_BUILD_DIR}/vector.yml /etc/vector/vector.yml
|
||||||
|
|
||||||
|
VOLUME /etc/vector
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
api:
|
||||||
|
enabled: true
|
||||||
|
address: 0.0.0.0:9001
|
||||||
|
|
||||||
|
sources:
|
||||||
|
docker_host:
|
||||||
|
type: docker_logs
|
||||||
|
exclude_containers:
|
||||||
|
- supabase-vector
|
||||||
|
|
||||||
|
transforms:
|
||||||
|
project_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- docker_host
|
||||||
|
source: |-
|
||||||
|
.project = "default"
|
||||||
|
.event_message = del(.message)
|
||||||
|
.appname = del(.container_name)
|
||||||
|
del(.container_created_at)
|
||||||
|
del(.container_id)
|
||||||
|
del(.source_type)
|
||||||
|
del(.stream)
|
||||||
|
del(.label)
|
||||||
|
del(.image)
|
||||||
|
del(.host)
|
||||||
|
del(.stream)
|
||||||
|
router:
|
||||||
|
type: route
|
||||||
|
inputs:
|
||||||
|
- project_logs
|
||||||
|
route:
|
||||||
|
kong: '.appname == "supabase-kong"'
|
||||||
|
auth: '.appname == "supabase-auth"'
|
||||||
|
rest: '.appname == "supabase-rest"'
|
||||||
|
realtime: '.appname == "supabase-realtime"'
|
||||||
|
storage: '.appname == "supabase-storage"'
|
||||||
|
functions: '.appname == "supabase-functions"'
|
||||||
|
db: '.appname == "supabase-db"'
|
||||||
|
# Ignores non nginx errors since they are related with kong booting up
|
||||||
|
kong_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.kong
|
||||||
|
source: |-
|
||||||
|
req, err = parse_nginx_log(.event_message, "combined")
|
||||||
|
if err == null {
|
||||||
|
.timestamp = req.timestamp
|
||||||
|
.metadata.request.headers.referer = req.referer
|
||||||
|
.metadata.request.headers.user_agent = req.agent
|
||||||
|
.metadata.request.headers.cf_connecting_ip = req.client
|
||||||
|
.metadata.request.method = req.method
|
||||||
|
.metadata.request.path = req.path
|
||||||
|
.metadata.request.protocol = req.protocol
|
||||||
|
.metadata.response.status_code = req.status
|
||||||
|
}
|
||||||
|
if err != null {
|
||||||
|
abort
|
||||||
|
}
|
||||||
|
# Ignores non nginx errors since they are related with kong booting up
|
||||||
|
kong_err:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.kong
|
||||||
|
source: |-
|
||||||
|
.metadata.request.method = "GET"
|
||||||
|
.metadata.response.status_code = 200
|
||||||
|
parsed, err = parse_nginx_log(.event_message, "error")
|
||||||
|
if err == null {
|
||||||
|
.timestamp = parsed.timestamp
|
||||||
|
.severity = parsed.severity
|
||||||
|
.metadata.request.host = parsed.host
|
||||||
|
.metadata.request.headers.cf_connecting_ip = parsed.client
|
||||||
|
url, err = split(parsed.request, " ")
|
||||||
|
if err == null {
|
||||||
|
.metadata.request.method = url[0]
|
||||||
|
.metadata.request.path = url[1]
|
||||||
|
.metadata.request.protocol = url[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != null {
|
||||||
|
abort
|
||||||
|
}
|
||||||
|
# Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency.
|
||||||
|
auth_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.auth
|
||||||
|
source: |-
|
||||||
|
parsed, err = parse_json(.event_message)
|
||||||
|
if err == null {
|
||||||
|
.metadata.timestamp = parsed.time
|
||||||
|
.metadata = merge!(.metadata, parsed)
|
||||||
|
}
|
||||||
|
# PostgREST logs are structured so we separate timestamp from message using regex
|
||||||
|
rest_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.rest
|
||||||
|
source: |-
|
||||||
|
parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$')
|
||||||
|
if err == null {
|
||||||
|
.event_message = parsed.msg
|
||||||
|
.timestamp = to_timestamp!(parsed.time)
|
||||||
|
.metadata.host = .project
|
||||||
|
}
|
||||||
|
# Realtime logs are structured so we parse the severity level using regex (ignore time because it has no date)
|
||||||
|
realtime_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.realtime
|
||||||
|
source: |-
|
||||||
|
.metadata.project = del(.project)
|
||||||
|
.metadata.external_id = .metadata.project
|
||||||
|
parsed, err = parse_regex(.event_message, r'^(?P<time>\d+:\d+:\d+\.\d+) \[(?P<level>\w+)\] (?P<msg>.*)$')
|
||||||
|
if err == null {
|
||||||
|
.event_message = parsed.msg
|
||||||
|
.metadata.level = parsed.level
|
||||||
|
}
|
||||||
|
# Storage logs may contain json objects so we parse them for completeness
|
||||||
|
storage_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.storage
|
||||||
|
source: |-
|
||||||
|
.metadata.project = del(.project)
|
||||||
|
.metadata.tenantId = .metadata.project
|
||||||
|
parsed, err = parse_json(.event_message)
|
||||||
|
if err == null {
|
||||||
|
.event_message = parsed.msg
|
||||||
|
.metadata.level = parsed.level
|
||||||
|
.metadata.timestamp = parsed.time
|
||||||
|
.metadata.context[0].host = parsed.hostname
|
||||||
|
.metadata.context[0].pid = parsed.pid
|
||||||
|
}
|
||||||
|
# Postgres logs some messages to stderr which we map to warning severity level
|
||||||
|
db_logs:
|
||||||
|
type: remap
|
||||||
|
inputs:
|
||||||
|
- router.db
|
||||||
|
source: |-
|
||||||
|
.metadata.host = "db-default"
|
||||||
|
.metadata.parsed.timestamp = .timestamp
|
||||||
|
|
||||||
|
parsed, err = parse_regex(.event_message, r'.*(?P<level>INFO|NOTICE|WARNING|ERROR|LOG|FATAL|PANIC?):.*', numeric_groups: true)
|
||||||
|
|
||||||
|
if err != null || parsed == null {
|
||||||
|
.metadata.parsed.error_severity = "info"
|
||||||
|
}
|
||||||
|
if parsed != null {
|
||||||
|
.metadata.parsed.error_severity = parsed.level
|
||||||
|
}
|
||||||
|
if .metadata.parsed.error_severity == "info" {
|
||||||
|
.metadata.parsed.error_severity = "log"
|
||||||
|
}
|
||||||
|
.metadata.parsed.error_severity = upcase!(.metadata.parsed.error_severity)
|
||||||
|
|
||||||
|
sinks:
|
||||||
|
logflare_auth:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- auth_logs
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
|
logflare_realtime:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- realtime_logs
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
|
logflare_rest:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- rest_logs
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
|
logflare_db:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- db_logs
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
# We must route the sink through kong because ingesting logs before logflare is fully initialised will
|
||||||
|
# lead to broken queries from studio. This works by the assumption that containers are started in the
|
||||||
|
# following order: vector > db > logflare > kong
|
||||||
|
uri: 'http://kong:8000/analytics/v1/api/logs?source_name=postgres.logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
|
logflare_functions:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- router.functions
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
|
logflare_storage:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- storage_logs
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
|
logflare_kong:
|
||||||
|
type: 'http'
|
||||||
|
inputs:
|
||||||
|
- kong_logs
|
||||||
|
- kong_err
|
||||||
|
encoding:
|
||||||
|
codec: 'json'
|
||||||
|
method: 'post'
|
||||||
|
request:
|
||||||
|
retry_max_duration_secs: 10
|
||||||
|
uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
DOCKER_SOCKET_LOCATION=/var/run/docker.sock
|
||||||
|
SUPABASE_DASHBOARD_PASSWORD=$(head -c11 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
SUPABASE_JWT_IAT=${SUPABASE_JWT_IAT}
|
||||||
|
SUPABASE_JWT_EXP=${SUPABASE_JWT_EXP}
|
||||||
|
# JWT_SECRET: 40 chars
|
||||||
|
SUPABASE_JWT_SECRET=$(head -c30 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
SUPABASE_LOGFLARE_API_KEY=$(head -c42 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
# DB_ENC_KEY: 16 chars
|
||||||
|
SUPABASE_POSTGRES_DB_ENC_KEY=$(head -c12 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
SUPABASE_POSTGRES_PASSWORD=$(head -c42 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
# SECRET_KEY_BASE: 64 chars
|
||||||
|
SUPABASE_SECRET_KEY_BASE=$(head -c48 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
# VAULT_ENC_KEY: 32 chars
|
||||||
|
SUPABASE_VAULT_ENC_KEY=$(head -c24 /dev/random |base64 |sed 's/+/-/g;s/\//_/g;s/=*$//;')
|
||||||
|
|
||||||
|
## General
|
||||||
|
# SUPABASE_SITE_URL=http://localhost:3000
|
||||||
|
# SUPABASE_ADDITIONAL_REDIRECT_URLS=
|
||||||
|
# SUPABASE_JWT_EXPIRY=3600
|
||||||
|
# SUPABASE_DISABLE_SIGNUP=false
|
||||||
|
# SUPABASE_API_EXTERNAL_URL=http://kong:8000
|
||||||
|
# SUPABASE_POSTGRES_HOST=supabase-db
|
||||||
|
# SUPABASE_POSTGRES_DB=postgres
|
||||||
|
# SUPABASE_POSTGRES_PORT=5432
|
||||||
|
# SUPABASE_POSTGRES_USER=postgres
|
||||||
|
# SUPABASE_POSTGRES_PORT=5432
|
||||||
|
# SUPABASE_POOLER_PROXY_PORT_TRANSACTION=6543
|
||||||
|
# SUPABASE_POOLER_DEFAULT_POOL_SIZE=20
|
||||||
|
# SUPABASE_POOLER_MAX_CLIENT_CONN=100
|
||||||
|
# SUPABASE_POOLER_TENANT_ID=your-tenant-id
|
||||||
|
# SUPABASE_KONG_HTTP_PORT=8000
|
||||||
|
# SUPABASE_KONG_HTTPS_PORT=8443
|
||||||
|
## API - Configuration for PostgREST.
|
||||||
|
# SUPABASE_PGRST_DB_SCHEMAS=public,storage,graphql_public
|
||||||
|
## Auth - Configuration for the GoTrue authentication server.
|
||||||
|
# SUPABASE_GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI=pg-functions://postgres/public/mfa_verification_attempt
|
||||||
|
# SUPABASE_GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS=<standard-base64-secret>
|
||||||
|
# SUPABASE_GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI=pg-functions://postgres/public/mfa_verification_attempt
|
||||||
|
# SUPABASE_GOTRUE_HOOK_SEND_SMS_URI=pg-functions://postgres/public/custom_access_token_hook
|
||||||
|
# SUPABASE_GOTRUE_HOOK_SEND_SMS_SECRETS=v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n
|
||||||
|
# SUPABASE_GOTRUE_HOOK_SEND_EMAIL_URI=http://host.docker.internal:54321/functions/v1/email_sender
|
||||||
|
# SUPABASE_GOTRUE_HOOK_SEND_EMAIL_SECRETS=v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n
|
||||||
|
## Mailer Config
|
||||||
|
# SUPABASE_MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify"
|
||||||
|
# SUPABASE_MAILER_URLPATHS_INVITE="/auth/v1/verify"
|
||||||
|
# SUPABASE_MAILER_URLPATHS_RECOVERY="/auth/v1/verify"
|
||||||
|
# SUPABASE_MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify"
|
||||||
|
## Email auth
|
||||||
|
# SUPABASE_ENABLE_EMAIL_SIGNUP=true
|
||||||
|
# SUPABASE_ENABLE_EMAIL_AUTOCONFIRM=false
|
||||||
|
# SUPABASE_SMTP_ADMIN_EMAIL=admin@${DOMAINNAME}
|
||||||
|
# SUPABASE_SMTP_HOST=mail
|
||||||
|
# SUPABASE_SMTP_PORT=25
|
||||||
|
# SUPABASE_SMTP_USER=
|
||||||
|
# SUPABASE_SMTP_PASS=
|
||||||
|
# SUPABASE_SMTP_SENDER_NAME=supabase@${DOMAINNAME}
|
||||||
|
# SUPABASE_ENABLE_ANONYMOUS_USERS=false
|
||||||
|
## Phone auth
|
||||||
|
# SUPABASE_ENABLE_PHONE_SIGNUP=true
|
||||||
|
# SUPABASE_ENABLE_PHONE_AUTOCONFIRM=true
|
||||||
|
## Studio - Configuration for the Dashboard
|
||||||
|
# SUPABASE_STUDIO_DEFAULT_ORGANIZATION=Default Organization
|
||||||
|
# SUPABASE_STUDIO_DEFAULT_PROJECT=Default Project
|
||||||
|
## replace if you intend to use Studio outside of localhost
|
||||||
|
# SUPABASE_PUBLIC_URL=http://localhost:8000
|
||||||
|
## Enable webp support
|
||||||
|
# SUPABASE_IMGPROXY_ENABLE_WEBP_DETECTION=true
|
||||||
|
## Add your OpenAI API key to enable SQL Editor Assistant
|
||||||
|
# SUPABASE_OPENAI_API_KEY=
|
||||||
|
## Functions - Configuration for Functions
|
||||||
|
# SUPABASE_FUNCTIONS_VERIFY_JWT=false
|
||||||
|
# SUPABASE_GOOGLE_PROJECT_ID=
|
||||||
|
# SUPABASE_GOOGLE_PROJECT_NUMBER=
|
||||||
@@ -436,7 +436,7 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
volumes:
|
volumes:
|
||||||
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro
|
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro
|
||||||
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro
|
- ${DOCKER_SOCKET_LOCATION:-/var/run/docker.sock}:/var/run/docker.sock:ro
|
||||||
environment:
|
environment:
|
||||||
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
|
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
|
||||||
command: [ "--config", "/etc/vector/vector.yml" ]
|
command: [ "--config", "/etc/vector/vector.yml" ]
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
services:
|
||||||
|
analytics:
|
||||||
|
labels:
|
||||||
|
- SERVICE_4000_CHECK_HTTP=/health
|
||||||
|
- SERVICE_4000_NAME=${COMPOSE_SERVICE_NAME}-analytics-4000
|
||||||
|
auth:
|
||||||
|
labels:
|
||||||
|
- SERVICE_9999_CHECK_HTTP=/health
|
||||||
|
- SERVICE_9999_NAME=${COMPOSE_SERVICE_NAME}-auth-9999
|
||||||
|
db:
|
||||||
|
labels:
|
||||||
|
- SERVICE_5432_CHECK_TCP=true
|
||||||
|
- SERVICE_5432_NAME=${COMPOSE_SERVICE_NAME}-db-5432
|
||||||
|
functions:
|
||||||
|
labels:
|
||||||
|
- SERVICE_9000_CHECK_HTTP=/functions/v1/hello
|
||||||
|
- SERVICE_9000_NAME=${COMPOSE_SERVICE_NAME}-functions-9000
|
||||||
|
imgproxy:
|
||||||
|
labels:
|
||||||
|
- SERVICE_5001_CHECK_HTTP=/health
|
||||||
|
- SERVICE_5001_NAME=${COMPOSE_SERVICE_NAME}-imgproxy-5001
|
||||||
|
- SERVICE_8080_IGNORE=true
|
||||||
|
kong:
|
||||||
|
labels:
|
||||||
|
- SERVICE_8000_CHECK_TCP=true
|
||||||
|
- SERVICE_8000_NAME=${COMPOSE_SERVICE_NAME}-kong-8000
|
||||||
|
- SERVICE_8000_TAGS=${SUPABASE_KONG_SERVICE_8000_TAGS:-urlprefix-supabase.localhost/*}
|
||||||
|
- SERVICE_8001_IGNORE=true
|
||||||
|
- SERVICE_8443_IGNORE=true
|
||||||
|
- SERVICE_8444_IGNORE=true
|
||||||
|
meta:
|
||||||
|
labels:
|
||||||
|
- SERVICE_8080_CHECK_HTTP=/
|
||||||
|
- SERVICE_8080_NAME=${COMPOSE_SERVICE_NAME}-meta-8080
|
||||||
|
rest:
|
||||||
|
labels:
|
||||||
|
- SERVICE_3000_CHECK_HTTP=/
|
||||||
|
- SERVICE_3000_NAME=${COMPOSE_SERVICE_NAME}-rest-3000
|
||||||
|
realtime:
|
||||||
|
labels:
|
||||||
|
- SERVICE_4000_CHECK_HTTP=/
|
||||||
|
- SERVICE_4000_NAME=${COMPOSE_SERVICE_NAME}-realtime-4000
|
||||||
|
storage:
|
||||||
|
labels:
|
||||||
|
- SERVICE_5000_CHECK_HTTP=/status
|
||||||
|
- SERVICE_5000_NAME=${COMPOSE_SERVICE_NAME}-storage-5000
|
||||||
|
studio:
|
||||||
|
labels:
|
||||||
|
- SERVICE_3000_CHECK_HTTP=/api/profile
|
||||||
|
- SERVICE_3000_NAME=${COMPOSE_SERVICE_NAME}-studio-3000
|
||||||
|
supavisor:
|
||||||
|
labels:
|
||||||
|
- SERVICE_4000_CHECK_HTTP=/api/health
|
||||||
|
- SERVICE_4000_NAME=${COMPOSE_SERVICE_NAME}-supavisor-4000
|
||||||
|
- SERVICE_5432_IGNORE=true
|
||||||
|
- SERVICE_6543_IGNORE=true
|
||||||
|
vector:
|
||||||
|
labels:
|
||||||
|
- SERVICE_9001_CHECK_HTTP=/health
|
||||||
|
- SERVICE_9001_NAME=${COMPOSE_SERVICE_NAME}-vector-9001
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
supavisor:
|
||||||
|
ports:
|
||||||
|
- ${SUPABASE_POSTGRES_PORT:-5432}:5432/tcp
|
||||||
|
- ${SUPABASE_POOLER_PROXY_PORT_TRANSACTION:-6543}:6543/tcp
|
||||||
|
kong:
|
||||||
|
ports:
|
||||||
|
- ${SUPABASE_KONG_HTTP_PORT:-8000}:8000/tcp
|
||||||
|
- ${SUPABASE_KONG_HTTPS_PORT:-8443}:8443/tcp
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
ENV_VARS += SUPABASE_ADDITIONAL_REDIRECT_URLS SUPABASE_ANON_KEY SUPABASE_JWT_IAT SUPABASE_JWT_EXP SUPABASE_KONG_SERVICE_8000_TAGS SUPABASE_PUBLIC_URL SUPABASE_REALTIME_TENANT SUPABASE_SERVICE_ROLE_KEY SUPABASE_EDGE_RUNTIME_VERSION SUPABASE_KONG_VERSION SUPABASE_POSTGRES_VERSION SUPABASE_VECTOR_VERSION
|
||||||
|
SUPABASE_ADDITIONAL_REDIRECT_URLS ?= $(subst $(space),$(comma),$(call url,SUPABASE))
|
||||||
|
SUPABASE_ANON_KEY ?= $(call JWT,,$(SUPABASE_JWT_PAYLOAD_ANON),$(SUPABASE_JWT_SECRET))
|
||||||
|
SUPABASE_DOCKER_IMAGES ?= supabase/edge-runtime:$(SUPABASE_EDGE_RUNTIME_VERSION) kong:$(SUPABASE_KONG_VERSION) supabase/postgres:$(SUPABASE_POSTGRES_VERSION) timberio/vector:$(SUPABASE_VECTOR_VERSION)
|
||||||
|
SUPABASE_JWT_IAT ?= $(MAKE_UNIXTIME_START)
|
||||||
|
SUPABASE_JWT_EXP ?= $(shell echo $$(($(SUPABASE_JWT_IAT)+94608000)))
|
||||||
|
SUPABASE_JWT_PAYLOAD_ANON ?= {\n "role": "anon",\n "iss": "supabase",\n "iat": $(SUPABASE_JWT_IAT),\n "exp": $(SUPABASE_JWT_EXP)\n}
|
||||||
|
SUPABASE_JWT_PAYLOAD_SERVICE ?= {\n "role": "service_role",\n "iss": "supabase",\n "iat": $(SUPABASE_JWT_IAT),\n "exp": $(SUPABASE_JWT_EXP)\n}
|
||||||
|
SUPABASE_KONG_SERVICE_8000_TAGS ?= $(call tagprefix,SUPABASE,8000)
|
||||||
|
SUPABASE_PUBLIC_URL ?= $(SUPABASE_SERVICE_URL)
|
||||||
|
SUPABASE_REALTIME_TENANT ?= realtime-dev
|
||||||
|
SUPABASE_SERVICE_NAME ?= supabase
|
||||||
|
SUPABASE_SERVICE_ROLE_KEY ?= $(call JWT,,$(SUPABASE_JWT_PAYLOAD_SERVICE),$(SUPABASE_JWT_SECRET))
|
||||||
|
SUPABASE_SERVICE_URIS ?= $(call uri,SUPABASE)
|
||||||
|
SUPABASE_SERVICE_URL ?= $(call firstword,$(call url,SUPABASE))
|
||||||
|
SUPABASE_EDGE_RUNTIME_VERSION ?= $(shell awk -F: '/image: supabase\/edge-runtime:/ {print $$3}' stack/supabase/docker-compose.yml)
|
||||||
|
SUPABASE_KONG_VERSION ?= $(shell awk -F: '/image: kong:/ {print $$3}' stack/supabase/docker-compose.yml)
|
||||||
|
SUPABASE_POSTGRES_VERSION ?= $(shell awk -F: '/image: supabase\/postgres:/ {print $$3}' stack/supabase/docker-compose.yml)
|
||||||
|
SUPABASE_VECTOR_VERSION ?= $(shell awk -F: '/image: timberio\/vector:/ {print $$3}' stack/supabase/docker-compose.yml)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
volumes: !override
|
||||||
|
- db-data:/var/lib/postgresql/data
|
||||||
|
- db-config:/etc/postgres-custom
|
||||||
|
functions:
|
||||||
|
volumes: !override
|
||||||
|
- functions-cache:/root/.cache
|
||||||
|
- functions-home:/home/deno/functions
|
||||||
|
imgproxy:
|
||||||
|
volumes: !override
|
||||||
|
- storage-data:/var/lib/storage
|
||||||
|
kong:
|
||||||
|
volumes: !override
|
||||||
|
- kong-home:/home/kong
|
||||||
|
storage:
|
||||||
|
volumes: !override
|
||||||
|
- storage-data:/var/lib/storage
|
||||||
|
vector:
|
||||||
|
volumes: !override
|
||||||
|
- vector-config:/etc/vector:ro
|
||||||
|
- ${DOCKER_SOCKET_LOCATION:-/var/run/docker.sock}:/var/run/docker.sock:ro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-config:
|
||||||
|
db-data:
|
||||||
|
functions-cache:
|
||||||
|
functions-home:
|
||||||
|
kong-home:
|
||||||
|
storage-data:
|
||||||
|
vector-config:
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
services:
|
||||||
|
studio:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
STUDIO_PG_META_URL: ${SUPABASE_STUDIO_PG_META_URL:-http://meta:8080}
|
||||||
|
POSTGRES_PASSWORD: ${SUPABASE_POSTGRES_PASSWORD}
|
||||||
|
DEFAULT_ORGANIZATION_NAME: ${SUPABASE_STUDIO_DEFAULT_ORGANIZATION:-Default Organization}
|
||||||
|
DEFAULT_PROJECT_NAME: ${SUPABASE_STUDIO_DEFAULT_PROJECT:-Default Project}
|
||||||
|
OPENAI_API_KEY: ${SUPABASE_OPENAI_API_KEY:-}
|
||||||
|
SUPABASE_URL: ${SUPABASE_URL:-http://kong:8000}
|
||||||
|
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL:-http://localhost:8000}
|
||||||
|
SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
|
||||||
|
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
|
||||||
|
AUTH_JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
LOGFLARE_API_KEY: ${SUPABASE_LOGFLARE_API_KEY}
|
||||||
|
LOGFLARE_URL: ${SUPABASE_LOGFLARE_URL:-http://analytics:4000}
|
||||||
|
NEXT_PUBLIC_ENABLE_LOGS: ${SUPABASE_NEXT_PUBLIC_ENABLE_LOGS:-true}
|
||||||
|
NEXT_ANALYTICS_BACKEND_PROVIDER: ${SUPABASE_NEXT_ANALYTICS_BACKEND_PROVIDER:-postgres}
|
||||||
|
|
||||||
|
kong:
|
||||||
|
build:
|
||||||
|
args:
|
||||||
|
- DOCKER_BUILD_DIR=docker/supabase/kong
|
||||||
|
- DOCKER_NETWORK=${DOCKER_NETWORK_DEFAULT:-_default}
|
||||||
|
- REALTIME_TENANT=${SUPABASE_REALTIME_TENANT:-realtime-dev}
|
||||||
|
- SUPABASE_KONG_VERSION=${SUPABASE_KONG_VERSION:-2.8.1}
|
||||||
|
context: ../..
|
||||||
|
dockerfile: docker/supabase/kong/Dockerfile
|
||||||
|
container_name: !reset null
|
||||||
|
image: ${DOCKER_REPOSITORY}/kong:${DOCKER_IMAGE_TAG}
|
||||||
|
environment: !override
|
||||||
|
KONG_DATABASE: ${SUPABASE_KONG_DATABASE:-off}
|
||||||
|
KONG_DECLARATIVE_CONFIG: ${SUPABASE_KONG_DECLARATIVE_CONFIG:-/home/kong/kong.yml}
|
||||||
|
KONG_DNS_ORDER: ${SUPABASE_KONG_DNS_ORDER:-LAST,A,CNAME}
|
||||||
|
KONG_PLUGINS: ${SUPABASE_KONG_PLUGINS:-request-transformer,cors,key-auth,acl,basic-auth}
|
||||||
|
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: ${SUPABASE_KONG_NGINX_PROXY_PROXY_BUFFER_SIZE:-160k}
|
||||||
|
KONG_NGINX_PROXY_PROXY_BUFFERS: ${SUPABASE_KONG_NGINX_PROXY_PROXY_BUFFERS:-64 160k}
|
||||||
|
SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
|
||||||
|
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
|
||||||
|
DASHBOARD_USERNAME: ${SUPABASE_DASHBOARD_USERNAME:-supabase}
|
||||||
|
DASHBOARD_PASSWORD: ${SUPABASE_DASHBOARD_PASSWORD}
|
||||||
|
ports: !override
|
||||||
|
- 8000/tcp
|
||||||
|
- 8443/tcp
|
||||||
|
|
||||||
|
auth:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
GOTRUE_API_HOST: ${SUPABASE_GOTRUE_API_HOST:-0.0.0.0}
|
||||||
|
GOTRUE_API_PORT: ${SUPABASE_GOTRUE_API_PORT:-9999}
|
||||||
|
API_EXTERNAL_URL: ${SUPABASE_API_EXTERNAL_URL:-${SUPABASE_PUBLIC_URL:-http://localhost:8000}}
|
||||||
|
GOTRUE_DB_DRIVER: ${SUPABASE_GOTRUE_DB_DRIVER:-postgres}
|
||||||
|
GOTRUE_DB_DATABASE_URL: postgres://${SUPABASE_POSTGRES_USER_AUTH:-supabase_auth_admin}:${SUPABASE_POSTGRES_PASSWORD_AUTH:-${SUPABASE_POSTGRES_PASSWORD}}@${SUPABASE_POSTGRES_HOST:-db}:${SUPABASE_POSTGRES_PORT:-5432}/${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
GOTRUE_SITE_URL: ${SUPABASE_SITE_URL:-${SUPABASE_PUBLIC_URL:-http://localhost:3000}}
|
||||||
|
GOTRUE_URI_ALLOW_LIST: ${SUPABASE_ADDITIONAL_REDIRECT_URLS:-}
|
||||||
|
GOTRUE_DISABLE_SIGNUP: ${SUPABASE_DISABLE_SIGNUP:-false}
|
||||||
|
GOTRUE_JWT_ADMIN_ROLES: ${SUPABASE_JWT_ADMIN_ROLES:-service_role}
|
||||||
|
GOTRUE_JWT_AUD: ${SUPABASE_JWT_AUD:-authenticated}
|
||||||
|
GOTRUE_JWT_DEFAULT_GROUP_NAME: ${SUPABASE_JWT_DEFAULT_GROUP_NAME:-authenticated}
|
||||||
|
GOTRUE_JWT_EXP: ${SUPABASE_JWT_EXPIRY:-3600}
|
||||||
|
GOTRUE_JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${SUPABASE_ENABLE_EMAIL_SIGNUP:-true}
|
||||||
|
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${SUPABASE_ENABLE_ANONYMOUS_USERS:-false}
|
||||||
|
GOTRUE_MAILER_AUTOCONFIRM: ${SUPABASE_ENABLE_EMAIL_AUTOCONFIRM:-false}
|
||||||
|
GOTRUE_EXTERNAL_SKIP_NONCE_CHECK: ${SUPABASE_EXTERNAL_SKIP_NONCE_CHECK:-false}
|
||||||
|
GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED: ${SUPABASE_MAILER_SECURE_EMAIL_CHANGE_ENABLED:-true}
|
||||||
|
GOTRUE_SMTP_MAX_FREQUENCY: ${SUPABASE_SMTP_MAX_FREQUENCY:-1s}
|
||||||
|
GOTRUE_SMTP_ADMIN_EMAIL: ${SUPABASE_SMTP_ADMIN_EMAIL:-}
|
||||||
|
GOTRUE_SMTP_HOST: ${SUPABASE_SMTP_HOST:-}
|
||||||
|
GOTRUE_SMTP_PORT: ${SUPABASE_SMTP_PORT:-25}
|
||||||
|
GOTRUE_SMTP_USER: ${SUPABASE_SMTP_USER:-}
|
||||||
|
GOTRUE_SMTP_PASS: ${SUPABASE_SMTP_PASS:-}
|
||||||
|
GOTRUE_SMTP_SENDER_NAME: ${SUPABASE_SMTP_SENDER_NAME:-}
|
||||||
|
GOTRUE_MAILER_URLPATHS_INVITE: ${SUPABASE_MAILER_URLPATHS_INVITE:-/auth/v1/verify}
|
||||||
|
GOTRUE_MAILER_URLPATHS_CONFIRMATION: ${SUPABASE_MAILER_URLPATHS_CONFIRMATION:-/auth/v1/verify}
|
||||||
|
GOTRUE_MAILER_URLPATHS_RECOVERY: ${SUPABASE_MAILER_URLPATHS_RECOVERY:-/auth/v1/verify}
|
||||||
|
GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE: ${SUPABASE_MAILER_URLPATHS_EMAIL_CHANGE:-/auth/v1/verify}
|
||||||
|
GOTRUE_EXTERNAL_PHONE_ENABLED: ${SUPABASE_ENABLE_PHONE_SIGNUP:-true}
|
||||||
|
GOTRUE_SMS_AUTOCONFIRM: ${SUPABASE_ENABLE_PHONE_AUTOCONFIRM:-true}
|
||||||
|
GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: ${SUPABASE_GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED:-false}
|
||||||
|
GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI: ${SUPABASE_GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI:-}
|
||||||
|
GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS: ${SUPABASE_GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS:-}
|
||||||
|
GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED: ${SUPABASE_GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED:-false}
|
||||||
|
GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI: ${SUPABASE_GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI:-}
|
||||||
|
GOTRUE_HOOK_SEND_SMS_ENABLED: ${SUPABASE_GOTRUE_HOOK_SEND_SMS_ENABLED:-false}
|
||||||
|
GOTRUE_HOOK_SEND_SMS_URI: ${SUPABASE_GOTRUE_HOOK_SEND_SMS_URI:-}
|
||||||
|
GOTRUE_HOOK_SEND_SMS_SECRETS: ${SUPABASE_GOTRUE_HOOK_SEND_SMS_SECRETS:-}
|
||||||
|
GOTRUE_HOOK_SEND_EMAIL_ENABLED: ${SUPABASE_GOTRUE_HOOK_SEND_EMAIL_ENABLED:-false}
|
||||||
|
GOTRUE_HOOK_SEND_EMAIL_URI: ${SUPABASE_GOTRUE_HOOK_SEND_EMAIL_URI:-}
|
||||||
|
GOTRUE_HOOK_SEND_EMAIL_SECRETS: ${SUPABASE_GOTRUE_HOOK_SEND_EMAIL_SECRETS:-}
|
||||||
|
|
||||||
|
rest:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
PGRST_DB_URI: postgres://${SUPABASE_POSTGRES_USER_REST:-authenticator}:${SUPABASE_POSTGRES_PASSWORD_REST:-${SUPABASE_POSTGRES_PASSWORD}}@${SUPABASE_POSTGRES_HOST:-db}:${SUPABASE_POSTGRES_PORT:-5432}/${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
PGRST_DB_SCHEMAS: ${SUPABASE_PGRST_DB_SCHEMAS:-public,storage,graphql_public}
|
||||||
|
PGRST_DB_ANON_ROLE: ${SUPABASE_PGRST_DB_ANON_ROLE:-anon}
|
||||||
|
PGRST_JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
PGRST_DB_USE_LEGACY_GUCS: ${SUPABASE_PGRST_DB_USE_LEGACY_GUCS:-false}
|
||||||
|
PGRST_APP_SETTINGS_JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
PGRST_APP_SETTINGS_JWT_EXP: ${SUPABASE_JWT_EXPIRY:-3600}
|
||||||
|
|
||||||
|
realtime:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
PORT: ${SUPABASE_REALTIME_PORT:-4000}
|
||||||
|
DB_HOST: ${SUPABASE_POSTGRES_HOST:-db}
|
||||||
|
DB_PORT: ${SUPABASE_POSTGRES_PORT:-5432}
|
||||||
|
DB_USER: ${SUPABASE_POSTGRES_USER_SUPABASE:-supabase_admin}
|
||||||
|
DB_PASSWORD: ${SUPABASE_POSTGRES_PASSWORD_SUPABASE:-${SUPABASE_POSTGRES_PASSWORD}}
|
||||||
|
DB_NAME: ${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
DB_AFTER_CONNECT_QUERY: ${SUPABASE_POSTGRES_DB_AFTER_CONNECT_QUERY:-SET search_path TO _realtime}
|
||||||
|
DB_ENC_KEY: ${SUPABASE_POSTGRES_DB_ENC_KEY:-supabaserealtime}
|
||||||
|
API_JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
SECRET_KEY_BASE: ${SUPABASE_SECRET_KEY_BASE}
|
||||||
|
ERL_AFLAGS: ${SUPABASE_REALTIME_ERL_AFLAGS:--proto_dist inet_tcp}
|
||||||
|
DNS_NODES: ${SUPABASE_REALTIME_DNS_NODES:-''}
|
||||||
|
RLIMIT_NOFILE: ${SUPABASE_REALTIME_RLIMIT_NOFILE:-10000}
|
||||||
|
APP_NAME: ${SUPABE_REALTIME_APP_NAME:-realtime}
|
||||||
|
SEED_SELF_HOST: ${SUPABASE_REALTIME_SEED_SELF_HOST:-true}
|
||||||
|
RUN_JANITOR: ${SUPABASE_REALTIME_RUN_JANITOR:-true}
|
||||||
|
SELF_HOST_TENANT_NAME: ${SUPABASE_REALTIME_TENANT:-realtime-dev}
|
||||||
|
MIX_ENV: ${SUPABASE_REALTIME_MIX_ENV:-prod}
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD",
|
||||||
|
"curl",
|
||||||
|
"-sSfL",
|
||||||
|
"--head",
|
||||||
|
"-o",
|
||||||
|
"/dev/null",
|
||||||
|
"-H",
|
||||||
|
"Authorization: Bearer ${SUPABASE_ANON_KEY}",
|
||||||
|
"http://localhost:4000/api/tenants/${SUPABASE_REALTIME_TENANT:-realtime-dev}/health"
|
||||||
|
]
|
||||||
|
timeout: 5s
|
||||||
|
interval: 5s
|
||||||
|
retries: 3
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
aliases:
|
||||||
|
- ${SUPABASE_REALTIME_TENANT:-realtime-dev}
|
||||||
|
|
||||||
|
storage:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
ANON_KEY: ${SUPABASE_ANON_KEY}
|
||||||
|
SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
|
||||||
|
POSTGREST_URL: ${SUPABASE_POSTGREST_URL:-http://rest:3000}
|
||||||
|
PGRST_JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
DATABASE_URL: postgres://${SUPABASE_POSTGRES_USER_STORAGE:-supabase_storage_admin}:${SUPABASE_POSTGRES_PASSWORD_STORAGE:-${SUPABASE_POSTGRES_PASSWORD}}@${SUPABASE_POSTGRES_HOST:-db}:${SUPABASE_POSTGRES_PORT:-5432}/${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
FILE_SIZE_LIMIT: ${SUPABASE_STORAGE_FILE_SIZE_LIMIT:-52428800}
|
||||||
|
STORAGE_BACKEND: ${SUPABASE_STORAGE_BACKEND:-file}
|
||||||
|
FILE_STORAGE_BACKEND_PATH: ${SUPABASE_FILE_STORAGE_BACKEND_PATH:-/var/lib/storage}
|
||||||
|
TENANT_ID: ${SUPABASE_STORAGE_TENANT_ID:-stub}
|
||||||
|
REGION: ${SUPABASE_STORAGE_REGION:-stub}
|
||||||
|
GLOBAL_S3_BUCKET: ${SUPABASE_STORAGE_GLOBAL_S3_BUCKET:-stub}
|
||||||
|
ENABLE_IMAGE_TRANSFORMATION: ${SUPABASE_STORAGE_ENABLE_IMAGE_TRANSFORMATION:-true}
|
||||||
|
IMGPROXY_URL: ${SUPABASE_IMGPROXY_URL:-http://imgproxy:5001}
|
||||||
|
|
||||||
|
imgproxy:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
IMGPROXY_BIND: ${SUPABASE_IMGPROXY_BIND:-:5001}
|
||||||
|
IMGPROXY_LOCAL_FILESYSTEM_ROOT: ${SUPABASE_IMGPROXY_LOCAL_FILESYSTEM_ROOT:-/}
|
||||||
|
IMGPROXY_USE_ETAG: ${SUPABASE_IMGPROXY_USE_ETAG:-true}
|
||||||
|
IMGPROXY_ENABLE_WEBP_DETECTION: ${SUPABASE_IMGPROXY_ENABLE_WEBP_DETECTION:-true}
|
||||||
|
|
||||||
|
meta:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
PG_META_PORT: ${SUPABASE_META_PORT:-8080}
|
||||||
|
PG_META_DB_HOST: ${SUPABASE_POSTGRES_HOST:-db}
|
||||||
|
PG_META_DB_PORT: ${SUPABASE_POSTGRES_PORT:-5432}
|
||||||
|
PG_META_DB_NAME: ${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
PG_META_DB_USER: ${SUPABASE_POSTGRES_USER_SUPABASE:-supabase_admin}
|
||||||
|
PG_META_DB_PASSWORD: ${SUPABASE_POSTGRES_PASSWORD_SUPABASE:-${SUPABASE_POSTGRES_PASSWORD}}
|
||||||
|
|
||||||
|
functions:
|
||||||
|
build:
|
||||||
|
args:
|
||||||
|
- DOCKER_BUILD_DIR=docker/supabase/edge-runtime
|
||||||
|
- SUPABASE_EDGE_RUNTIME_VERSION=${SUPABASE_EDGE_RUNTIME_VERSION:-v1.65.3}
|
||||||
|
context: ../..
|
||||||
|
dockerfile: docker/supabase/edge-runtime/Dockerfile
|
||||||
|
container_name: !reset null
|
||||||
|
image: ${DOCKER_REPOSITORY}/edge-runtime:${DOCKER_IMAGE_TAG}
|
||||||
|
environment: !override
|
||||||
|
JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
SUPABASE_URL: ${SUPABASE_URL:-http://kong:8000}
|
||||||
|
SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
|
||||||
|
SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
|
||||||
|
SUPABASE_DB_URL: postgresql://${SUPABASE_POSTGRES_USER:-postgres}:${SUPABASE_POSTGRES_PASSWORD}@${SUPABASE_POSTGRES_HOST:-db}:${SUPABASE_POSTGRES_PORT:-5432}/${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
VERIFY_JWT: "${SUPABASE_FUNCTIONS_VERIFY_JWT}"
|
||||||
|
|
||||||
|
analytics:
|
||||||
|
container_name: !reset null
|
||||||
|
environment: !override
|
||||||
|
LOGFLARE_NODE_HOST: ${SUPABASE_LOGFLARE_NODE_HOST:-127.0.0.1}
|
||||||
|
DB_USERNAME: ${SUPABASE_POSTGRES_USER_SUPABASE:-supabase_admin}
|
||||||
|
DB_DATABASE: ${SUPABASE_POSTGRES_DB_SUPABASE:-_supabase}
|
||||||
|
DB_HOSTNAME: ${SUPABASE_POSTGRES_HOST:-db}
|
||||||
|
DB_PORT: ${SUPABASE_POSTGRES_PORT:-5432}
|
||||||
|
DB_PASSWORD: ${SUPABASE_POSTGRES_PASSWORD_SUPABASE:-${SUPABASE_POSTGRES_PASSWORD}}
|
||||||
|
DB_SCHEMA: ${SUPABASE_POSTGRES_SCHEMA_SUPABASE:-_analytics}
|
||||||
|
LOGFLARE_API_KEY: ${SUPABASE_LOGFLARE_API_KEY}
|
||||||
|
LOGFLARE_SINGLE_TENANT: ${SUPABASE_LOGFLARE_SINGLE_TENANT:-true}
|
||||||
|
LOGFLARE_SUPABASE_MODE: ${SUPABASE_LOGFLARE_SUPABASE_MODE:-true}
|
||||||
|
LOGFLARE_MIN_CLUSTER_SIZE: ${SUPABASE_LOGFLARE_MIN_CLUSTER_SIZE:-1}
|
||||||
|
POSTGRES_BACKEND_URL: postgresql://${SUPABASE_POSTGRES_USER_SUPABASE:-supabase_admin}:${SUPABASE_POSTGRES_PASSWORD_SUPABASE:-${SUPABASE_POSTGRES_PASSWORD}}@${SUPABASE_POSTGRES_HOST:-db}:${SUPABASE_POSTGRES_PORT:-5432}/${SUPABASE_POSTGRES_DB_SUPABASE:-_supabase}
|
||||||
|
POSTGRES_BACKEND_SCHEMA: ${SUPABASE_POSTGRES_SCHEMA_SUPABASE:-_analytics}
|
||||||
|
LOGFLARE_FEATURE_FLAG_OVERRIDE: ${SUPABASE_LOGFLARE_FEATURE_FLAG_OVERRIDE:-multibackend=true}
|
||||||
|
GOOGLE_PROJECT_ID: ${SUPABASE_GOOGLE_PROJECT_ID:-}
|
||||||
|
GOOGLE_PROJECT_NUMBER: ${SUPABASE_GOOGLE_PROJECT_NUMBER:-}
|
||||||
|
ports: !override
|
||||||
|
- 4000
|
||||||
|
|
||||||
|
db:
|
||||||
|
build:
|
||||||
|
args:
|
||||||
|
- DOCKER_BUILD_DIR=docker/supabase/postgres
|
||||||
|
- SUPABASE_POSTGRES_VERSION=${SUPABASE_POSTGRES_VERSION:-15.6.1.146}
|
||||||
|
context: ../..
|
||||||
|
dockerfile: docker/supabase/postgres/Dockerfile
|
||||||
|
container_name: !reset null
|
||||||
|
image: ${DOCKER_REPOSITORY}/postgres:${DOCKER_IMAGE_TAG}
|
||||||
|
environment: !override
|
||||||
|
POSTGRES_HOST: /var/run/postgresql
|
||||||
|
PGPORT: ${SUPABASE_POSTGRES_PORT:-5432}
|
||||||
|
POSTGRES_PORT: ${SUPABASE_POSTGRES_PORT:-5432}
|
||||||
|
PGPASSWORD: ${SUPABASE_POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_PASSWORD: ${SUPABASE_POSTGRES_PASSWORD}
|
||||||
|
PGDATABASE: ${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
POSTGRES_DB: ${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
JWT_SECRET: ${SUPABASE_JWT_SECRET}
|
||||||
|
JWT_EXP: ${SUPABASE_JWT_EXPIRY:-3600}
|
||||||
|
|
||||||
|
vector:
|
||||||
|
build:
|
||||||
|
args:
|
||||||
|
- DOCKER_BUILD_DIR=docker/supabase/vector
|
||||||
|
- SUPABASE_VECTOR_VERSION=${SUPABASE_VECTOR_VERSION:-0.28.1-alpine}
|
||||||
|
context: ../..
|
||||||
|
dockerfile: docker/supabase/vector/Dockerfile
|
||||||
|
container_name: !reset null
|
||||||
|
image: ${DOCKER_REPOSITORY}/vector:${DOCKER_IMAGE_TAG}
|
||||||
|
environment: !override
|
||||||
|
LOGFLARE_API_KEY: ${SUPABASE_LOGFLARE_API_KEY}
|
||||||
|
|
||||||
|
supavisor:
|
||||||
|
container_name: !reset null
|
||||||
|
ports: !override
|
||||||
|
- 5432
|
||||||
|
- 6543
|
||||||
|
environment: !override
|
||||||
|
- PORT=${SUPABASE_SUPAVISOR_PORT:-4000}
|
||||||
|
- POSTGRES_PORT=${SUPABASE_POSTGRES_PORT:-5432}
|
||||||
|
- POSTGRES_DB=${SUPABASE_POSTGRES_DB:-postgres}
|
||||||
|
- POSTGRES_PASSWORD=${SUPABASE_POSTGRES_PASSWORD}
|
||||||
|
- DATABASE_URL=ecto://${SUPABASE_POSTGRES_USER_SUPABASE:-supabase_admin}:${SUPABASE_POSTGRES_PASSWORD_SUPABASE:-${SUPABASE_POSTGRES_PASSWORD}}@${SUPABASE_POSTGRES_HOST:-db}:${SUPABASE_POSTGRES_PORT:-5432}/${SUPABASE_POSTGRES_DB_SUPABASE:-_supabase}
|
||||||
|
- CLUSTER_POSTGRES=true
|
||||||
|
- SECRET_KEY_BASE=${SUPABASE_SECRET_KEY_BASE}
|
||||||
|
- VAULT_ENC_KEY=${SUPABASE_VAULT_ENC_KEY}
|
||||||
|
- API_JWT_SECRET=${SUPABASE_JWT_SECRET}
|
||||||
|
- METRICS_JWT_SECRET=${SUPABASE_JWT_SECRET}
|
||||||
|
- REGION=${SUPABASE_SUPAVISOR_REGION:-local}
|
||||||
|
- ERL_AFLAGS=${SUPABASE_SUPAVISOR_ERL_AFLAGS:--proto_dist inet_tcp}
|
||||||
|
- POOLER_TENANT_ID=${SUPABASE_POOLER_TENANT_ID:-local}
|
||||||
|
- POOLER_DEFAULT_POOL_SIZE=${SUPABASE_POOLER_DEFAULT_POOL_SIZE:-20}
|
||||||
|
- POOLER_MAX_CLIENT_CONN=${SUPABASE_POOLER_MAX_CLIENT_CONN:-100}
|
||||||
|
- POOLER_POOL_MODE=${SUPABASE_POOLER_POOL_MODE:-transaction}
|
||||||
Reference in New Issue
Block a user