Add Docker support with configuration files and environment setup
This commit is contained in:
21
.dockerignore
Normal file
21
.dockerignore
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
*.md
|
||||||
|
!DOCKER.md
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
coverage
|
||||||
|
.nyc_output
|
||||||
|
*.test.ts
|
||||||
|
*.test.tsx
|
||||||
|
*.spec.ts
|
||||||
|
*.spec.tsx
|
||||||
98
.env.example
Normal file
98
.env.example
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# =====================================================
|
||||||
|
# DECKERR DOCKER CONFIGURATION
|
||||||
|
# =====================================================
|
||||||
|
# Copy this file to .env and configure your settings
|
||||||
|
#
|
||||||
|
# Two deployment modes available:
|
||||||
|
# 1. External Supabase: Use docker-compose.yml (simpler)
|
||||||
|
# 2. Self-hosted Supabase: Use docker-compose.selfhosted.yml (full stack)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# MODE 1: EXTERNAL SUPABASE (docker-compose.yml)
|
||||||
|
# =====================================================
|
||||||
|
# Use this if you have:
|
||||||
|
# - A Supabase cloud account (supabase.com)
|
||||||
|
# - A separately self-hosted Supabase instance
|
||||||
|
# - Access to a paid hosted Supabase service
|
||||||
|
|
||||||
|
# Your Supabase project URL
|
||||||
|
VITE_SUPABASE_URL=https://your-project.supabase.co
|
||||||
|
|
||||||
|
# Your Supabase anonymous/public key
|
||||||
|
VITE_SUPABASE_ANON_KEY=your-anon-key-here
|
||||||
|
|
||||||
|
# Port to run Deckerr on (default: 3000)
|
||||||
|
PORT=3000
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# MODE 2: SELF-HOSTED SUPABASE (docker-compose.selfhosted.yml)
|
||||||
|
# =====================================================
|
||||||
|
# Use this to run everything locally, including Supabase
|
||||||
|
|
||||||
|
# --- Site Configuration ---
|
||||||
|
# Your domain or IP address (used for redirects)
|
||||||
|
SITE_URL=http://localhost:3000
|
||||||
|
|
||||||
|
# External API URL (Kong gateway)
|
||||||
|
API_EXTERNAL_URL=http://localhost:8000
|
||||||
|
|
||||||
|
# --- Port Configuration ---
|
||||||
|
DECKERR_PORT=3000
|
||||||
|
KONG_HTTP_PORT=8000
|
||||||
|
KONG_HTTPS_PORT=8443
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
# --- Security Keys ---
|
||||||
|
# IMPORTANT: Generate secure random values for production!
|
||||||
|
# You can use: openssl rand -base64 32
|
||||||
|
|
||||||
|
# PostgreSQL password
|
||||||
|
POSTGRES_PASSWORD=your-super-secret-postgres-password
|
||||||
|
|
||||||
|
# JWT Secret (must be at least 32 characters)
|
||||||
|
# Generate with: openssl rand -base64 32
|
||||||
|
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters
|
||||||
|
|
||||||
|
# JWT Expiry in seconds (default: 3600 = 1 hour)
|
||||||
|
JWT_EXPIRY=3600
|
||||||
|
|
||||||
|
# Supabase Anonymous Key
|
||||||
|
# Generate at: https://supabase.com/docs/guides/self-hosting#api-keys
|
||||||
|
# Or use: npx @supabase/cli@latest gen key --type anon --jwt-secret "YOUR_JWT_SECRET"
|
||||||
|
ANON_KEY=your-anon-key
|
||||||
|
|
||||||
|
# Supabase Service Role Key (admin access)
|
||||||
|
# Generate at: https://supabase.com/docs/guides/self-hosting#api-keys
|
||||||
|
# Or use: npx @supabase/cli@latest gen key --type service_role --jwt-secret "YOUR_JWT_SECRET"
|
||||||
|
SERVICE_ROLE_KEY=your-service-role-key
|
||||||
|
|
||||||
|
# --- Email Configuration (Optional) ---
|
||||||
|
# Required for email verification and password reset
|
||||||
|
SMTP_HOST=smtp.example.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USER=your-email@example.com
|
||||||
|
SMTP_PASS=your-email-password
|
||||||
|
SMTP_ADMIN_EMAIL=admin@example.com
|
||||||
|
SMTP_SENDER_NAME=Deckerr
|
||||||
|
|
||||||
|
# Enable email auto-confirm (set to true to skip email verification)
|
||||||
|
ENABLE_EMAIL_AUTOCONFIRM=true
|
||||||
|
|
||||||
|
# --- Feature Flags ---
|
||||||
|
# Disable new user signups
|
||||||
|
DISABLE_SIGNUP=false
|
||||||
|
|
||||||
|
# Enable email signup
|
||||||
|
ENABLE_EMAIL_SIGNUP=true
|
||||||
|
|
||||||
|
# Enable anonymous users
|
||||||
|
ENABLE_ANONYMOUS_USERS=false
|
||||||
|
|
||||||
|
# --- Advanced ---
|
||||||
|
# Additional redirect URLs (comma-separated)
|
||||||
|
ADDITIONAL_REDIRECT_URLS=
|
||||||
|
|
||||||
|
# PostgREST schemas
|
||||||
|
PGRST_DB_SCHEMAS=public,graphql_public
|
||||||
191
DOCKER.md
Normal file
191
DOCKER.md
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
# Deckerr Docker Deployment
|
||||||
|
|
||||||
|
Self-host Deckerr with two deployment options:
|
||||||
|
|
||||||
|
## Deployment Options
|
||||||
|
|
||||||
|
| Option | Use Case | Complexity |
|
||||||
|
|--------|----------|------------|
|
||||||
|
| **External Supabase** | Use hosted Supabase (cloud or paid) | Simple |
|
||||||
|
| **Self-hosted Supabase** | Run everything locally | Advanced |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Option 1: External Supabase (Recommended)
|
||||||
|
|
||||||
|
Use your own Supabase instance (cloud, paid hosted, or separately self-hosted).
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Copy environment template
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# 2. Edit .env with your Supabase credentials
|
||||||
|
VITE_SUPABASE_URL=https://your-project.supabase.co
|
||||||
|
VITE_SUPABASE_ANON_KEY=your-anon-key
|
||||||
|
PORT=3000
|
||||||
|
|
||||||
|
# 3. Run database migrations on your Supabase
|
||||||
|
# Go to Supabase Dashboard > SQL Editor and run:
|
||||||
|
# Contents of supabase/migrations/20250131132458_black_frost.sql
|
||||||
|
|
||||||
|
# 4. Start Deckerr
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# 5. Access at http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Hosted Supabase (Paid Service)
|
||||||
|
|
||||||
|
Contact the Deckerr team for access credentials to use the hosted backend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Option 2: Self-Hosted Supabase (Full Stack)
|
||||||
|
|
||||||
|
Run Deckerr with a complete self-hosted Supabase stack.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- 2GB+ RAM
|
||||||
|
- Ports: 3000, 5432, 8000
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Copy environment template
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# 2. Generate secure keys
|
||||||
|
# JWT Secret (required)
|
||||||
|
openssl rand -base64 32
|
||||||
|
|
||||||
|
# Generate Supabase API keys
|
||||||
|
# Option A: Use online generator at https://supabase.com/docs/guides/self-hosting#api-keys
|
||||||
|
# Option B: Use Supabase CLI
|
||||||
|
npx @supabase/cli@latest gen key --type anon --jwt-secret "YOUR_JWT_SECRET"
|
||||||
|
npx @supabase/cli@latest gen key --type service_role --jwt-secret "YOUR_JWT_SECRET"
|
||||||
|
|
||||||
|
# 3. Update .env with your generated values
|
||||||
|
POSTGRES_PASSWORD=<generated-password>
|
||||||
|
JWT_SECRET=<generated-jwt-secret>
|
||||||
|
ANON_KEY=<generated-anon-key>
|
||||||
|
SERVICE_ROLE_KEY=<generated-service-key>
|
||||||
|
|
||||||
|
# 4. Start all services
|
||||||
|
docker-compose -f docker-compose.selfhosted.yml up -d
|
||||||
|
|
||||||
|
# 5. Access Deckerr at http://localhost:3000
|
||||||
|
# API available at http://localhost:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Keys Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
JWT_SECRET=$(openssl rand -base64 32)
|
||||||
|
echo "JWT_SECRET=$JWT_SECRET"
|
||||||
|
echo ""
|
||||||
|
echo "Now generate API keys at:"
|
||||||
|
echo "https://supabase.com/docs/guides/self-hosting#api-keys"
|
||||||
|
echo "Use this JWT secret: $JWT_SECRET"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Self-Hosted Services
|
||||||
|
|
||||||
|
| Service | Port | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| Deckerr | 3000 | Frontend app |
|
||||||
|
| Kong | 8000 | API Gateway |
|
||||||
|
| PostgreSQL | 5432 | Database |
|
||||||
|
| Auth | 9999 | Authentication (internal) |
|
||||||
|
| REST | 3000 | PostgREST API (internal) |
|
||||||
|
| Realtime | 4000 | WebSocket (internal) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
### External Supabase Mode
|
||||||
|
|
||||||
|
| Variable | Required | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| `VITE_SUPABASE_URL` | Yes | Supabase project URL |
|
||||||
|
| `VITE_SUPABASE_ANON_KEY` | Yes | Supabase anonymous key |
|
||||||
|
| `PORT` | No | App port (default: 3000) |
|
||||||
|
|
||||||
|
### Self-Hosted Mode
|
||||||
|
|
||||||
|
| Variable | Required | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| `POSTGRES_PASSWORD` | Yes | PostgreSQL password |
|
||||||
|
| `JWT_SECRET` | Yes | JWT signing secret (32+ chars) |
|
||||||
|
| `ANON_KEY` | Yes | Supabase anonymous key |
|
||||||
|
| `SERVICE_ROLE_KEY` | Yes | Supabase service role key |
|
||||||
|
| `SITE_URL` | No | Your domain (default: localhost) |
|
||||||
|
| `SMTP_*` | No | Email configuration |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start (external Supabase)
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Start (self-hosted)
|
||||||
|
docker-compose -f docker-compose.selfhosted.yml up -d
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Rebuild after code changes
|
||||||
|
docker-compose build --no-cache
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Reset database (self-hosted only)
|
||||||
|
docker-compose -f docker-compose.selfhosted.yml down -v
|
||||||
|
docker-compose -f docker-compose.selfhosted.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Production Checklist
|
||||||
|
|
||||||
|
- [ ] Use strong passwords (generate with `openssl rand -base64 32`)
|
||||||
|
- [ ] Configure HTTPS with reverse proxy (nginx, Traefik, Caddy)
|
||||||
|
- [ ] Set up email (SMTP) for password reset
|
||||||
|
- [ ] Configure firewall rules
|
||||||
|
- [ ] Set up backups for PostgreSQL volume
|
||||||
|
- [ ] Consider rate limiting at reverse proxy level
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container won't start
|
||||||
|
```bash
|
||||||
|
docker-compose logs <service-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database connection issues
|
||||||
|
```bash
|
||||||
|
# Check if database is healthy
|
||||||
|
docker-compose exec db pg_isready -U postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reset everything
|
||||||
|
```bash
|
||||||
|
docker-compose down -v
|
||||||
|
docker-compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check service health
|
||||||
|
```bash
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
39
Dockerfile
Normal file
39
Dockerfile
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build arguments for Supabase configuration
|
||||||
|
ARG VITE_SUPABASE_URL
|
||||||
|
ARG VITE_SUPABASE_ANON_KEY
|
||||||
|
|
||||||
|
# Set environment variables for build
|
||||||
|
ENV VITE_SUPABASE_URL=$VITE_SUPABASE_URL
|
||||||
|
ENV VITE_SUPABASE_ANON_KEY=$VITE_SUPABASE_ANON_KEY
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Copy custom nginx config
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Copy built assets from builder
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Start nginx
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
201
docker-compose.selfhosted.yml
Normal file
201
docker-compose.selfhosted.yml
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
# Full self-hosted deployment with Supabase included
|
||||||
|
# This includes PostgreSQL, Auth, REST API, and the Deckerr frontend
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ============================================
|
||||||
|
# DECKERR FRONTEND
|
||||||
|
# ============================================
|
||||||
|
deckerr:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- VITE_SUPABASE_URL=http://${SITE_URL:-localhost}:${KONG_HTTP_PORT:-8000}
|
||||||
|
- VITE_SUPABASE_ANON_KEY=${ANON_KEY}
|
||||||
|
container_name: deckerr
|
||||||
|
ports:
|
||||||
|
- "${DECKERR_PORT:-3000}:80"
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
kong:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# SUPABASE SERVICES
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# PostgreSQL Database
|
||||||
|
db:
|
||||||
|
image: supabase/postgres:15.1.1.78
|
||||||
|
container_name: supabase-db
|
||||||
|
healthcheck:
|
||||||
|
test: pg_isready -U postgres -h localhost
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
ports:
|
||||||
|
- "${POSTGRES_PORT:-5432}:5432"
|
||||||
|
environment:
|
||||||
|
POSTGRES_HOST: /var/run/postgresql
|
||||||
|
PGPORT: 5432
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
PGPASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
PGDATABASE: postgres
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
volumes:
|
||||||
|
- supabase-db-data:/var/lib/postgresql/data
|
||||||
|
- ./supabase/migrations:/docker-entrypoint-initdb.d/migrations
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Supabase Kong API Gateway
|
||||||
|
kong:
|
||||||
|
image: kong:2.8.1
|
||||||
|
container_name: supabase-kong
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${KONG_HTTP_PORT:-8000}:8000/tcp"
|
||||||
|
- "${KONG_HTTPS_PORT:-8443}:8443/tcp"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
KONG_DATABASE: "off"
|
||||||
|
KONG_DECLARATIVE_CONFIG: /home/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_KEY: ${SERVICE_ROLE_KEY}
|
||||||
|
volumes:
|
||||||
|
- ./docker/kong.yml:/home/kong/kong.yml:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "kong", "health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# Supabase Auth (GoTrue)
|
||||||
|
auth:
|
||||||
|
image: supabase/gotrue:v2.143.0
|
||||||
|
container_name: supabase-auth
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9999/health"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
GOTRUE_API_HOST: 0.0.0.0
|
||||||
|
GOTRUE_API_PORT: 9999
|
||||||
|
API_EXTERNAL_URL: ${API_EXTERNAL_URL:-http://localhost:8000}
|
||||||
|
|
||||||
|
GOTRUE_DB_DRIVER: postgres
|
||||||
|
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@db:5432/postgres
|
||||||
|
|
||||||
|
GOTRUE_SITE_URL: ${SITE_URL:-http://localhost:3000}
|
||||||
|
GOTRUE_URI_ALLOW_LIST: ${ADDITIONAL_REDIRECT_URLS:-}
|
||||||
|
GOTRUE_DISABLE_SIGNUP: ${DISABLE_SIGNUP:-false}
|
||||||
|
|
||||||
|
GOTRUE_JWT_ADMIN_ROLES: service_role
|
||||||
|
GOTRUE_JWT_AUD: authenticated
|
||||||
|
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
|
||||||
|
GOTRUE_JWT_EXP: ${JWT_EXPIRY:-3600}
|
||||||
|
GOTRUE_JWT_SECRET: ${JWT_SECRET}
|
||||||
|
|
||||||
|
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP:-true}
|
||||||
|
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS:-false}
|
||||||
|
GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM:-false}
|
||||||
|
|
||||||
|
GOTRUE_SMTP_HOST: ${SMTP_HOST:-}
|
||||||
|
GOTRUE_SMTP_PORT: ${SMTP_PORT:-587}
|
||||||
|
GOTRUE_SMTP_USER: ${SMTP_USER:-}
|
||||||
|
GOTRUE_SMTP_PASS: ${SMTP_PASS:-}
|
||||||
|
GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL:-}
|
||||||
|
GOTRUE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME:-Deckerr}
|
||||||
|
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
|
||||||
|
|
||||||
|
# Supabase REST API (PostgREST)
|
||||||
|
rest:
|
||||||
|
image: postgrest/postgrest:v12.0.1
|
||||||
|
container_name: supabase-rest
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@db:5432/postgres
|
||||||
|
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS:-public,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}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost:3000/ready || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# Supabase Realtime
|
||||||
|
realtime:
|
||||||
|
image: supabase/realtime:v2.28.32
|
||||||
|
container_name: supabase-realtime
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", "-H", "Authorization: Bearer ${ANON_KEY}", "http://localhost:4000/api/tenants/realtime-dev/health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PORT: 4000
|
||||||
|
DB_HOST: db
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USER: supabase_admin
|
||||||
|
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
DB_NAME: postgres
|
||||||
|
DB_AFTER_CONNECT_QUERY: 'SET search_path TO _realtime'
|
||||||
|
DB_ENC_KEY: supabaserealtime
|
||||||
|
API_JWT_SECRET: ${JWT_SECRET}
|
||||||
|
SECRET_KEY_BASE: ${SECRET_KEY_BASE:-UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq}
|
||||||
|
ERL_AFLAGS: -proto_dist inet_tcp
|
||||||
|
DNS_NODES: "''"
|
||||||
|
RLIMIT_NOFILE: "10000"
|
||||||
|
APP_NAME: realtime
|
||||||
|
SEED_SELF_HOST: true
|
||||||
|
REPLICATION_MODE: RLS
|
||||||
|
REPLICATION_POLL_INTERVAL: 100
|
||||||
|
SECURE_CHANNELS: "true"
|
||||||
|
SLOT_NAME: supabase_realtime_rls
|
||||||
|
TEMPORARY_SLOT: "true"
|
||||||
|
|
||||||
|
# Supabase Meta (for Studio - optional)
|
||||||
|
meta:
|
||||||
|
image: supabase/postgres-meta:v0.80.0
|
||||||
|
container_name: supabase-meta
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PG_META_PORT: 8080
|
||||||
|
PG_META_DB_HOST: db
|
||||||
|
PG_META_DB_PORT: 5432
|
||||||
|
PG_META_DB_NAME: postgres
|
||||||
|
PG_META_DB_USER: supabase_admin
|
||||||
|
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
supabase-db-data:
|
||||||
138
docker/kong.yml
Normal file
138
docker/kong.yml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
_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 Lists
|
||||||
|
###
|
||||||
|
acls:
|
||||||
|
- consumer: anon
|
||||||
|
group: anon
|
||||||
|
- consumer: service_role
|
||||||
|
group: admin
|
||||||
|
|
||||||
|
###
|
||||||
|
### 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: false
|
||||||
|
- name: acl
|
||||||
|
config:
|
||||||
|
hide_groups_header: true
|
||||||
|
allow:
|
||||||
|
- admin
|
||||||
|
- anon
|
||||||
|
|
||||||
|
## Realtime routes
|
||||||
|
- name: realtime-v1
|
||||||
|
_comment: "Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*"
|
||||||
|
url: http://realtime:4000/socket/
|
||||||
|
routes:
|
||||||
|
- name: realtime-v1-all
|
||||||
|
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
|
||||||
|
|
||||||
|
## Meta routes (for Supabase Studio)
|
||||||
|
- name: meta
|
||||||
|
_comment: "pg-meta: /pg/* -> http://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
|
||||||
29
nginx.conf
Normal file
29
nginx.conf
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript application/json;
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle SPA routing - serve index.html for all routes
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user