# Docker Compose for deployment behind an existing Traefik reverse proxy # All domains and the proxy web name are configurable via environment variables services: # PostgreSQL Database postgres: image: postgres:15-alpine container_name: hq-postgres environment: POSTGRES_USER: ${POSTGRES_USER:-headquarter} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-headquarter} POSTGRES_DB: ${POSTGRES_DB:-headquarter} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-headquarter} -d ${POSTGRES_DB:-headquarter}"] interval: 10s timeout: 5s retries: 5 start_period: 10s networks: - backend restart: unless-stopped # Redis Cache redis: image: redis:7-alpine container_name: hq-redis command: redis-server --appendonly yes volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 start_period: 5s networks: - backend restart: unless-stopped # API Service api: build: context: ./apps/api dockerfile: Dockerfile container_name: hq-api environment: APP_ENV: production DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-headquarter}:${POSTGRES_PASSWORD:-headquarter}@postgres:5432/${POSTGRES_DB:-headquarter} REDIS_URL: redis://redis:6379/0 JWT_SECRET: ${JWT_SECRET:-change-me-in-production} REPO_BASE_PATH: /data/repos API_DOMAIN: ${API_DOMAIN} WEB_DOMAIN: ${WEB_DOMAIN} AUTHENTIK_DOMAIN: ${AUTHENTIK_DOMAIN} API_PUBLIC_URL: ${API_PUBLIC_URL:-} WEB_PUBLIC_URL: ${WEB_PUBLIC_URL:-} AUTHENTIK_CLIENT_ID: ${AUTHENTIK_CLIENT_ID:-headquarter-web} AUTHENTIK_CLIENT_SECRET: ${AUTHENTIK_CLIENT_SECRET} AUTHENTIK_AUTHORIZE_URL: ${AUTHENTIK_AUTHORIZE_URL:-} AUTHENTIK_TOKEN_URL: ${AUTHENTIK_TOKEN_URL:-} AUTHENTIK_JWKS_URL: ${AUTHENTIK_JWKS_URL:-} AUTHENTIK_ISSUER: ${AUTHENTIK_ISSUER:-} AUTHENTIK_AUDIENCE: ${AUTHENTIK_AUDIENCE:-headquarter-web} volumes: - repo_data:/data/repos - avatar_uploads:/app/uploads depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - backend - traefik restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-api.rule=Host(`${API_DOMAIN}`)" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-api.entrypoints=websecure" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-api.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}" - "traefik.http.services.${TRAEFIK_ROUTER_PREFIX:-hq}-api.loadbalancer.server.port=8000" - "traefik.http.middlewares.${TRAEFIK_ROUTER_PREFIX:-hq}-api-strip.stripprefix.prefixes=/api" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-api.middlewares=${TRAEFIK_ROUTER_PREFIX:-hq}-api-strip" # Web Frontend web: build: context: ./apps/web dockerfile: Dockerfile container_name: hq-web environment: VITE_API_BASE_URL: ${API_PUBLIC_URL:-https://${API_DOMAIN}} VITE_APP_URL: ${WEB_PUBLIC_URL:-https://${WEB_DOMAIN}} depends_on: - api networks: - backend - traefik restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-web.rule=Host(`${WEB_DOMAIN}`)" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-web.entrypoints=websecure" - "traefik.http.routers.${TRAEFIK_ROUTER_PREFIX:-hq}-web.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}" - "traefik.http.services.${TRAEFIK_ROUTER_PREFIX:-hq}-web.loadbalancer.server.port=80" volumes: postgres_data: redis_data: repo_data: avatar_uploads: networks: backend: driver: bridge traefik: external: true name: ${TRAEFIK_NETWORK:-traefik}