Fix: Remove hardcoded UUIDs and secrets from deploy scripts

- deploy.py: UUIDs from env vars or Coolify API lookup by name
- fast-deploy.sh: No hardcoded UUIDs, APP_DOMAIN from env
- docker-compose.yml: All secrets from env vars, no hardcoded values
- .env.example: All required vars documented
- Deleted obsolete fast-frontend-deploy.sh with hardcoded container name
This commit is contained in:
Agent Zero
2026-08-04 11:13:44 +02:00
parent e7edc46286
commit 7d3007b6c4
5 changed files with 633 additions and 359 deletions
+27 -25
View File
@@ -14,10 +14,12 @@
# - RLS policy enforcement
# - Health & domain verification
#
# No hardcoded secrets, UUIDs, or domains — everything from environment.
#
# Usage (local testing):
# cp .env.docker.example .env.docker
# $EDITOR .env.docker # fill SECRET_KEY, POSTGRES_PASSWORD, ...
# docker compose --env-file .env.docker up --build
# cp .env.example .env
# $EDITOR .env # fill SECRET_KEY, DB_PASSWORD, REDIS_PASSWORD, ...
# docker compose up --build
# curl http://localhost:8000/api/v1/health
# =============================================================================
@@ -25,11 +27,11 @@ services:
# ── PostgreSQL 16 with pgvector ─────────────────────────────────────
postgres:
image: pgvector/pgvector:pg16
container_name: crm-postgres
container_name: ${POSTGRES_CONTAINER_NAME:-crm-postgres}
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-crm_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
POSTGRES_DB: ${POSTGRES_DB:-crm_db}
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
@@ -53,7 +55,7 @@ services:
# ── Redis 7 (sessions, rate limiting, ARQ queue) ────────────────────
redis:
image: redis:7-alpine
container_name: crm-redis
container_name: ${REDIS_CONTAINER_NAME:-crm-redis}
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD is required}
volumes:
@@ -73,15 +75,15 @@ services:
build:
context: .
dockerfile: Dockerfile
container_name: crm-app
container_name: ${APP_CONTAINER_NAME:-crm-app}
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.http.routers.crm.rule=Host(`crm.media-on.de`)
- traefik.http.routers.crm.rule=Host(`${APP_HOST:-crm.media-on.de}`)
- traefik.http.routers.crm.entryPoints=http,https
- traefik.http.routers.crm.tls=true
- traefik.http.routers.crm.tls.certresolver=letsencrypt
- traefik.http.services.crm.loadbalancer.server.port=8000
- traefik.http.services.crm.loadbalancer.server.port=${APP_PORT:-8000}
networks:
- crm-net
- coolify
@@ -92,15 +94,15 @@ services:
condition: service_healthy
environment:
# API uses crm_api (NOSUPERUSER, NOBYPASSRLS) — RLS enforced
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://crm_api:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
# Auth uses crm_auth (NOSUPERUSER, NOBYPASSRLS) — identity tables only
AUTH_DATABASE_URL: ${AUTH_DATABASE_URL:-postgresql+asyncpg://crm_auth:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
AUTH_DATABASE_URL: ${AUTH_DATABASE_URL:-postgresql+asyncpg://crm_auth:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
# Migration/DDL uses crm_migration (owner, NOBYPASSRLS)
MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD}@redis:6379/0}
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)}
CORS_ORIGINS: ${CORS_ORIGINS:-https://crm.media-on.de}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:8000}
CORS_ORIGINS: ${CORS_ORIGINS:-${APP_DOMAIN:-http://localhost:8000}}
FRONTEND_URL: ${FRONTEND_URL:-${APP_DOMAIN:-http://localhost:8000}}
ENVIRONMENT: ${ENVIRONMENT:-production}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true}
@@ -125,7 +127,7 @@ services:
volumes:
- storage:/data/storage
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8000/api/v1/health"]
test: ["CMD", "curl", "-fsS", "http://localhost:${APP_PORT:-8000}/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
@@ -141,7 +143,7 @@ services:
build:
context: .
dockerfile: Dockerfile
container_name: crm-worker
container_name: ${WORKER_CONTAINER_NAME:-crm-worker}
restart: unless-stopped
depends_on:
postgres:
@@ -162,12 +164,12 @@ services:
cpus: "1.0"
environment:
# Worker uses crm_worker (NOSUPERUSER, NOBYPASSRLS) — RLS enforced
DATABASE_URL: ${WORKER_DATABASE_URL:-${DATABASE_URL:?DATABASE_URL is required}}
WORKER_DATABASE_URL: ${WORKER_DATABASE_URL:-postgresql+asyncpg://crm_worker:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
DATABASE_URL: ${WORKER_DATABASE_URL:-postgresql+asyncpg://crm_worker:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
WORKER_DATABASE_URL: ${WORKER_DATABASE_URL:-postgresql+asyncpg://crm_worker:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD}@redis:6379/0}
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:8000}
FRONTEND_URL: ${FRONTEND_URL:-${APP_DOMAIN:-http://localhost:8000}}
ENVIRONMENT: ${ENVIRONMENT:-production}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true}
@@ -191,16 +193,16 @@ services:
volumes:
pgdata:
name: crm_pgdata
name: ${PGDATA_VOLUME_NAME:-crm_pgdata}
redisdata:
name: crm_redisdata
name: ${REDISDATA_VOLUME_NAME:-crm_redisdata}
storage:
name: crm_storage
name: ${STORAGE_VOLUME_NAME:-crm_storage}
networks:
crm-net:
name: crm-net
name: ${CRM_NETWORK_NAME:-crm-net}
driver: bridge
coolify:
name: coolify
name: ${COOLIFY_NETWORK_NAME:-coolify}
external: true