feat: add Docker Compose production stack with Traefik + Logto
7-service stack: Traefik (reverse proxy), PostgreSQL (shared), Logto (identity), cameleer-saas (control plane), cameleer3-server (observability), ClickHouse (traces). ForwardAuth middleware for tenant-aware routing to cameleer3-server. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
25
.env.example
Normal file
25
.env.example
Normal file
@@ -0,0 +1,25 @@
|
||||
# Cameleer SaaS Environment Variables
|
||||
# Copy to .env and fill in values
|
||||
|
||||
# Application version
|
||||
VERSION=latest
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_USER=cameleer
|
||||
POSTGRES_PASSWORD=change_me_in_production
|
||||
POSTGRES_DB=cameleer_saas
|
||||
|
||||
# Logto Identity Provider
|
||||
LOGTO_ENDPOINT=http://logto:3001
|
||||
LOGTO_ISSUER_URI=http://logto:3001/oidc
|
||||
LOGTO_JWK_SET_URI=http://logto:3001/oidc/jwks
|
||||
LOGTO_DB_PASSWORD=change_me_in_production
|
||||
LOGTO_M2M_CLIENT_ID=
|
||||
LOGTO_M2M_CLIENT_SECRET=
|
||||
|
||||
# Ed25519 Keys (mount PEM files)
|
||||
CAMELEER_JWT_PRIVATE_KEY_PATH=/etc/cameleer/keys/ed25519.key
|
||||
CAMELEER_JWT_PUBLIC_KEY_PATH=/etc/cameleer/keys/ed25519.pub
|
||||
|
||||
# Domain (for Traefik TLS)
|
||||
DOMAIN=localhost
|
||||
21
docker-compose.dev.yml
Normal file
21
docker-compose.dev.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
# Development overrides: exposes ports for direct access
|
||||
# Usage: docker compose -f docker-compose.yml -f docker-compose.dev.yml up
|
||||
services:
|
||||
postgres:
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
logto:
|
||||
ports:
|
||||
- "3001:3001"
|
||||
- "3002:3002"
|
||||
|
||||
cameleer-saas:
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: dev
|
||||
|
||||
clickhouse:
|
||||
ports:
|
||||
- "8123:8123"
|
||||
@@ -1,14 +1,122 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik.yml:/etc/traefik/traefik.yml:ro
|
||||
- acme:/etc/traefik/acme
|
||||
networks:
|
||||
- cameleer
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: cameleer_saas
|
||||
POSTGRES_USER: cameleer
|
||||
POSTGRES_PASSWORD: cameleer_dev
|
||||
ports:
|
||||
- "5432:5432"
|
||||
POSTGRES_DB: ${POSTGRES_DB:-cameleer_saas}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-cameleer}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-cameleer_dev}
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
- ./docker/init-databases.sh:/docker-entrypoint-initdb.d/init-databases.sh:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-cameleer}"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- cameleer
|
||||
|
||||
logto:
|
||||
image: ghcr.io/logto-io/logto:latest
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
entrypoint: ["sh", "-c", "npm run cli db seed -- --swe && npm start"]
|
||||
environment:
|
||||
DB_URL: postgres://${POSTGRES_USER:-cameleer}:${POSTGRES_PASSWORD:-cameleer_dev}@postgres:5432/logto
|
||||
ENDPOINT: ${LOGTO_ENDPOINT:-http://localhost:3001}
|
||||
ADMIN_ENDPOINT: ${LOGTO_ADMIN_ENDPOINT:-http://localhost:3002}
|
||||
TRUST_PROXY_HEADER: 1
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.logto.rule=PathPrefix(`/oidc`) || PathPrefix(`/interaction`)
|
||||
- traefik.http.services.logto.loadbalancer.server.port=3001
|
||||
networks:
|
||||
- cameleer
|
||||
|
||||
cameleer-saas:
|
||||
image: ${CAMELEER_IMAGE:-gitea.siegeln.net/cameleer/cameleer-saas}:${VERSION:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./keys:/etc/cameleer/keys:ro
|
||||
environment:
|
||||
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:-cameleer_saas}
|
||||
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER:-cameleer}
|
||||
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD:-cameleer_dev}
|
||||
LOGTO_ENDPOINT: ${LOGTO_ENDPOINT:-http://logto:3001}
|
||||
LOGTO_ISSUER_URI: ${LOGTO_ISSUER_URI:-http://logto:3001/oidc}
|
||||
LOGTO_JWK_SET_URI: ${LOGTO_JWK_SET_URI:-http://logto:3001/oidc/jwks}
|
||||
LOGTO_M2M_CLIENT_ID: ${LOGTO_M2M_CLIENT_ID:-}
|
||||
LOGTO_M2M_CLIENT_SECRET: ${LOGTO_M2M_CLIENT_SECRET:-}
|
||||
CAMELEER_JWT_PRIVATE_KEY_PATH: ${CAMELEER_JWT_PRIVATE_KEY_PATH:-}
|
||||
CAMELEER_JWT_PUBLIC_KEY_PATH: ${CAMELEER_JWT_PUBLIC_KEY_PATH:-}
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.api.rule=PathPrefix(`/api`)
|
||||
- traefik.http.services.api.loadbalancer.server.port=8080
|
||||
- traefik.http.routers.forwardauth.rule=Path(`/auth/verify`)
|
||||
- traefik.http.services.forwardauth.loadbalancer.server.port=8080
|
||||
networks:
|
||||
- cameleer
|
||||
|
||||
cameleer3-server:
|
||||
image: ${CAMELEER3_SERVER_IMAGE:-gitea.siegeln.net/cameleer/cameleer3-server}:${VERSION:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
clickhouse:
|
||||
condition: service_started
|
||||
environment:
|
||||
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:-cameleer_saas}
|
||||
CLICKHOUSE_URL: jdbc:clickhouse://clickhouse:8123/cameleer
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.observe.rule=PathPrefix(`/observe`)
|
||||
- traefik.http.routers.observe.middlewares=forward-auth
|
||||
- traefik.http.middlewares.forward-auth.forwardauth.address=http://cameleer-saas:8080/auth/verify
|
||||
- traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Tenant-Id,X-User-Id,X-User-Email
|
||||
- traefik.http.services.observe.loadbalancer.server.port=8080
|
||||
networks:
|
||||
- cameleer
|
||||
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- chdata:/var/lib/clickhouse
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "clickhouse-client --query 'SELECT 1'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
networks:
|
||||
- cameleer
|
||||
|
||||
networks:
|
||||
cameleer:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
chdata:
|
||||
acme:
|
||||
|
||||
7
docker/init-databases.sh
Normal file
7
docker/init-databases.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
|
||||
CREATE DATABASE logto;
|
||||
GRANT ALL PRIVILEGES ON DATABASE logto TO $POSTGRES_USER;
|
||||
EOSQL
|
||||
14
traefik.yml
Normal file
14
traefik.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
api:
|
||||
dashboard: false
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
network: cameleer
|
||||
Reference in New Issue
Block a user