mirror of
https://github.com/Dokploy/templates.git
synced 2026-11-11 13:38:07 -06:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17a53fa567 |
@@ -11,7 +11,7 @@ name: supabase
|
||||
services:
|
||||
|
||||
studio:
|
||||
image: supabase/studio:2026.06.03-sha-0bca601
|
||||
image: supabase/studio:2026.08.03-sha-022b374
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
@@ -23,9 +23,6 @@ services:
|
||||
interval: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
depends_on:
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
HOSTNAME: "0.0.0.0"
|
||||
|
||||
@@ -35,6 +32,9 @@ services:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
|
||||
# See: https://supabase.com/docs/guides/self-hosting/remove-superuser-access
|
||||
POSTGRES_USER_READ_WRITE: postgres
|
||||
|
||||
PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
|
||||
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
|
||||
PGRST_DB_MAX_ROWS: ${PGRST_DB_MAX_ROWS:-1000}
|
||||
@@ -49,14 +49,12 @@ services:
|
||||
SUPABASE_ANON_KEY: ${ANON_KEY}
|
||||
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
AUTH_JWT_SECRET: ${JWT_SECRET}
|
||||
SUPABASE_PUBLISHABLE_KEY: ${SUPABASE_PUBLISHABLE_KEY:-}
|
||||
SUPABASE_SECRET_KEY: ${SUPABASE_SECRET_KEY:-}
|
||||
|
||||
LOGFLARE_API_KEY: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
|
||||
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
|
||||
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
|
||||
# Analytics (Logflare) was removed from the upstream self-hosted stack
|
||||
ENABLED_FEATURES_LOGS_ALL: "false"
|
||||
|
||||
LOGFLARE_URL: http://analytics:4000
|
||||
NEXT_PUBLIC_ENABLE_LOGS: "true"
|
||||
NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
|
||||
SNIPPETS_MANAGEMENT_FOLDER: /app/snippets
|
||||
EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions
|
||||
volumes:
|
||||
@@ -64,7 +62,7 @@ services:
|
||||
- ../files/volumes/functions:/app/edge-functions:Z
|
||||
|
||||
kong:
|
||||
image: kong/kong:3.9.1
|
||||
image: kong/kong:3.9.3
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "kong", "health"]
|
||||
@@ -138,6 +136,7 @@ services:
|
||||
GOTRUE_JWT_EXP: ${JWT_EXPIRY}
|
||||
GOTRUE_JWT_SECRET: ${JWT_SECRET}
|
||||
GOTRUE_JWT_KEYS: ${JWT_KEYS:-[]}
|
||||
GOTRUE_JWT_ISSUER: ${API_EXTERNAL_URL}
|
||||
|
||||
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
|
||||
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS}
|
||||
@@ -163,12 +162,19 @@ services:
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: [ "CMD", "postgrest", "--ready" ]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
environment:
|
||||
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
||||
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
|
||||
PGRST_DB_MAX_ROWS: ${PGRST_DB_MAX_ROWS:-1000}
|
||||
PGRST_DB_EXTRA_SEARCH_PATH: ${PGRST_DB_EXTRA_SEARCH_PATH:-public}
|
||||
PGRST_DB_ANON_ROLE: anon
|
||||
PGRST_ADMIN_SERVER_PORT: 3001
|
||||
PGRST_ADMIN_SERVER_HOST: localhost
|
||||
PGRST_JWT_SECRET: ${JWT_SECRET}
|
||||
PGRST_DB_USE_LEGACY_GUCS: "false"
|
||||
PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
|
||||
@@ -292,7 +298,8 @@ services:
|
||||
PG_META_DB_HOST: ${POSTGRES_HOST}
|
||||
PG_META_DB_PORT: ${POSTGRES_PORT}
|
||||
PG_META_DB_NAME: ${POSTGRES_DB}
|
||||
PG_META_DB_USER: supabase_admin
|
||||
# See: https://supabase.com/docs/guides/self-hosting/remove-superuser-access
|
||||
PG_META_DB_USER: postgres
|
||||
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
|
||||
|
||||
@@ -322,43 +329,9 @@ services:
|
||||
"/home/deno/functions/main"
|
||||
]
|
||||
|
||||
analytics:
|
||||
image: supabase/logflare:1.36.1
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- 4000
|
||||
# First boot: Logflare seeds _analytics in Postgres; allow extra time before marking unhealthy.
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"curl -sSfL -o /dev/null http://localhost:4000/health"
|
||||
]
|
||||
timeout: 10s
|
||||
interval: 5s
|
||||
retries: 15
|
||||
start_period: 90s
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
LOGFLARE_NODE_HOST: 127.0.0.1
|
||||
DB_USERNAME: supabase_admin
|
||||
DB_DATABASE: _supabase
|
||||
DB_HOSTNAME: ${POSTGRES_HOST}
|
||||
DB_PORT: ${POSTGRES_PORT}
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
DB_SCHEMA: _analytics
|
||||
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
|
||||
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
|
||||
LOGFLARE_SINGLE_TENANT: "true"
|
||||
LOGFLARE_SUPABASE_MODE: "true"
|
||||
LOGFLARE_MIN_CLUSTER_SIZE: 1
|
||||
POSTGRES_BACKEND_URL: postgresql://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase
|
||||
POSTGRES_BACKEND_SCHEMA: _analytics
|
||||
LOGFLARE_FEATURE_FLAG_OVERRIDE: multibackend=true
|
||||
|
||||
db:
|
||||
# Major upgrade from Postgres 15 requires a dump/restore for existing installs.
|
||||
# See: https://github.com/orgs/supabase/discussions/46080
|
||||
image: supabase/postgres:17.6.1.136
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
@@ -385,9 +358,6 @@ services:
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
vector:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
POSTGRES_HOST: /var/run/postgresql
|
||||
PGPORT: ${POSTGRES_PORT}
|
||||
@@ -407,36 +377,6 @@ services:
|
||||
"log_min_messages=fatal"
|
||||
]
|
||||
|
||||
vector:
|
||||
image: timberio/vector:0.53.0-alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ../files/volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
|
||||
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro,z
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"wget",
|
||||
"--no-verbose",
|
||||
"--tries=1",
|
||||
"--spider",
|
||||
"http://vector:9001/health"
|
||||
]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
environment:
|
||||
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
|
||||
command:
|
||||
[
|
||||
"--config",
|
||||
"/etc/vector/vector.yml"
|
||||
]
|
||||
security_opt:
|
||||
- "label=disable"
|
||||
|
||||
supavisor:
|
||||
image: supabase/supavisor:2.9.5
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "supabase",
|
||||
"name": "SupaBase",
|
||||
"version": "2026.06.03 / dokploy >= 0.22.5",
|
||||
"version": "2026.08.03 / dokploy >= 0.22.5",
|
||||
"description": "The open source Firebase alternative. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications. This require at least version 0.22.5 of dokploy.",
|
||||
"links": {
|
||||
"github": "https://github.com/supabase/supabase",
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
main_domain = "${domain}"
|
||||
postgres_password = "${password:32}"
|
||||
dashboard_password = "${password:32}"
|
||||
logflare_public_access_token = "${password:32}"
|
||||
logflare_private_access_token = "${password:32}"
|
||||
pg_meta_crypto_key = "${password:32}"
|
||||
s3_protocol_access_key_id = "${password:24}"
|
||||
s3_protocol_access_key_secret = "${password:48}"
|
||||
@@ -59,8 +57,6 @@ env = [
|
||||
'SECRET_KEY_BASE=${secret_key_base}',
|
||||
'VAULT_ENC_KEY=${vault_enc_key}',
|
||||
'PG_META_CRYPTO_KEY=${pg_meta_crypto_key}',
|
||||
'LOGFLARE_PUBLIC_ACCESS_TOKEN=${logflare_public_access_token}',
|
||||
'LOGFLARE_PRIVATE_ACCESS_TOKEN=${logflare_private_access_token}',
|
||||
'',
|
||||
'',
|
||||
'############',
|
||||
@@ -164,19 +160,7 @@ env = [
|
||||
'# Functions - Configuration for Functions',
|
||||
'############',
|
||||
'# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.',
|
||||
'FUNCTIONS_VERIFY_JWT=false',
|
||||
'',
|
||||
'',
|
||||
'############',
|
||||
'# Logs - Configuration for Logflare',
|
||||
'############',
|
||||
'',
|
||||
'# Docker socket location - this value will differ depending on your OS',
|
||||
'DOCKER_SOCKET_LOCATION=/var/run/docker.sock',
|
||||
'',
|
||||
'# Google Cloud Project details',
|
||||
'GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID',
|
||||
'GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER']
|
||||
'FUNCTIONS_VERIFY_JWT=false']
|
||||
|
||||
[[config.mounts]]
|
||||
filePath = "/volumes/api/kong-entrypoint.sh"
|
||||
@@ -1007,278 +991,6 @@ Deno.serve(async (req: Request) => {
|
||||
})
|
||||
"""
|
||||
|
||||
[[config.mounts]]
|
||||
filePath = "/volumes/logs/vector.yml"
|
||||
content = """api:
|
||||
enabled: true
|
||||
address: 0.0.0.0:9001
|
||||
|
||||
sources:
|
||||
docker_host:
|
||||
type: docker_logs
|
||||
|
||||
transforms:
|
||||
project_logs:
|
||||
type: remap
|
||||
inputs:
|
||||
- docker_host
|
||||
source: |-
|
||||
.project = "default"
|
||||
.event_message = del(.message)
|
||||
compose_service, label_err = get(.label, ["com.docker.compose.service"])
|
||||
if label_err != null || compose_service == null {
|
||||
abort
|
||||
}
|
||||
compose_service = to_string!(compose_service)
|
||||
if compose_service == "vector" {
|
||||
abort
|
||||
}
|
||||
.appname = "supabase-" + compose_service
|
||||
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" || .appname == "supabase-envoy"'
|
||||
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.response.status_code = req.status
|
||||
url, split_err = split(req.request, " ")
|
||||
if split_err == null {
|
||||
.metadata.request.method = url[0]
|
||||
.metadata.request.path = url[1]
|
||||
.metadata.request.protocol = url[2]
|
||||
}
|
||||
}
|
||||
if err != null {
|
||||
abort
|
||||
}
|
||||
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 = parse_timestamp!(value: parsed.time,format: "%d/%b/%Y:%H:%M:%S %z")
|
||||
.metadata.host = .project
|
||||
}
|
||||
realtime_logs_filtered:
|
||||
type: filter
|
||||
inputs:
|
||||
- router.realtime
|
||||
condition: '!contains(string!(.event_message), "/health")'
|
||||
realtime_logs:
|
||||
type: remap
|
||||
inputs:
|
||||
- realtime_logs_filtered
|
||||
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
|
||||
}
|
||||
functions_logs:
|
||||
type: remap
|
||||
inputs:
|
||||
- router.functions
|
||||
source: |-
|
||||
.metadata.project_ref = del(.project)
|
||||
# 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.level != 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: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod'
|
||||
logflare_realtime:
|
||||
type: 'http'
|
||||
inputs:
|
||||
- realtime_logs
|
||||
encoding:
|
||||
codec: 'json'
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod'
|
||||
logflare_rest:
|
||||
type: 'http'
|
||||
inputs:
|
||||
- rest_logs
|
||||
encoding:
|
||||
codec: 'json'
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod'
|
||||
logflare_db:
|
||||
type: 'http'
|
||||
inputs:
|
||||
- db_logs
|
||||
encoding:
|
||||
codec: 'json'
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=postgres.logs'
|
||||
logflare_functions:
|
||||
type: 'http'
|
||||
inputs:
|
||||
- functions_logs
|
||||
encoding:
|
||||
codec: 'json'
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs'
|
||||
logflare_storage:
|
||||
type: 'http'
|
||||
inputs:
|
||||
- storage_logs
|
||||
encoding:
|
||||
codec: 'json'
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2'
|
||||
logflare_kong:
|
||||
type: 'http'
|
||||
inputs:
|
||||
- kong_logs
|
||||
- kong_err
|
||||
encoding:
|
||||
codec: 'json'
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 30
|
||||
retry_initial_backoff_secs: 1
|
||||
headers:
|
||||
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
|
||||
uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod'
|
||||
"""
|
||||
|
||||
[[config.mounts]]
|
||||
filePath = "/volumes/pooler/pooler.exs"
|
||||
content = """{:ok, _} = Application.ensure_all_started(:supavisor)
|
||||
|
||||
Reference in New Issue
Block a user