services: traefik: image: traefik:v3.2 command: - --configFile=/etc/traefik/traefik.yml ports: - "0.0.0.0:8288:80" - "0.0.0.0:2288:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro - ./traefik/dynamic:/etc/traefik/dynamic - ./traefik/letsencrypt:/letsencrypt networks: - portal_net restart: unless-stopped db: image: postgres:16 environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - pg_data:/var/lib/postgresql/data networks: - portal_net restart: unless-stopped api: build: context: ./app command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "${UVICORN_WORKERS:-6}"] environment: DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB} SIGNING_KEY: ${SIGNING_KEY} PUBLIC_HOST: ${PUBLIC_HOST} ADMIN_USERNAME: ${ADMIN_USERNAME} ADMIN_PASSWORD: ${ADMIN_PASSWORD} SESSION_IDLE_SECONDS: ${SESSION_IDLE_SECONDS:-7200} PREWARM_POOL_SIZE: ${PREWARM_POOL_SIZE:-2} UNIVERSAL_POOL_SIZE: ${UNIVERSAL_POOL_SIZE:-0} WEB_POOL_SIZE: ${WEB_POOL_SIZE:-20} WEB_POOL_BUFFER: ${WEB_POOL_BUFFER:-2} X11VNC_FLAGS: ${X11VNC_FLAGS:--wait 5 -defer 5 -threads} MAX_ACTIVE_SERVICES_PER_USER: ${MAX_ACTIVE_SERVICES_PER_USER:-4} LOG_LEVEL: ${LOG_LEVEL:-INFO} LOG_SLOW_REQUEST_MS: ${LOG_SLOW_REQUEST_MS:-2000} GO_USER_LOCK_TIMEOUT_SECONDS: ${GO_USER_LOCK_TIMEOUT_SECONDS:-8} GO_POOL_LOCK_TIMEOUT_SECONDS: ${GO_POOL_LOCK_TIMEOUT_SECONDS:-20} POOL_DISPATCH_RETRIES: ${POOL_DISPATCH_RETRIES:-6} POOL_DISPATCH_REQUEST_TIMEOUT_SECONDS: ${POOL_DISPATCH_REQUEST_TIMEOUT_SECONDS:-2.0} POOL_DISPATCH_SLEEP_SECONDS: ${POOL_DISPATCH_SLEEP_SECONDS:-0.3} TRAEFIK_INTERNAL_URL: ${TRAEFIK_INTERNAL_URL:-http://traefik} WEB_RESOLUTION_MIN_WIDTH: ${WEB_RESOLUTION_MIN_WIDTH:-1024} WEB_RESOLUTION_MIN_HEIGHT: ${WEB_RESOLUTION_MIN_HEIGHT:-720} WEB_RESOLUTION_MAX_WIDTH: ${WEB_RESOLUTION_MAX_WIDTH:-3840} WEB_RESOLUTION_MAX_HEIGHT: ${WEB_RESOLUTION_MAX_HEIGHT:-2160} ENABLE_STARTUP_MAINTENANCE: ${ENABLE_STARTUP_MAINTENANCE:-0} depends_on: - db volumes: - /var/run/docker.sock:/var/run/docker.sock - ./app/static/service-icons:/app/static/service-icons labels: - traefik.enable=true - traefik.docker.network=portal_net - traefik.http.routers.portal.rule=Host(`${PUBLIC_HOST}`) - traefik.http.routers.portal.entrypoints=websecure - traefik.http.routers.portal.tls=true - traefik.http.routers.portal.tls.certresolver=letsencrypt - traefik.http.routers.portal.priority=1 - traefik.http.services.portal.loadbalancer.server.port=8000 - traefik.http.routers.portal.middlewares=secure-headers@file networks: - portal_net restart: unless-stopped maintenance: build: context: ./app command: [python, maintenance_runner.py] environment: DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB} SIGNING_KEY: ${SIGNING_KEY} PUBLIC_HOST: ${PUBLIC_HOST} ADMIN_USERNAME: ${ADMIN_USERNAME} ADMIN_PASSWORD: ${ADMIN_PASSWORD} SESSION_IDLE_SECONDS: ${SESSION_IDLE_SECONDS:-7200} PREWARM_POOL_SIZE: ${PREWARM_POOL_SIZE:-2} UNIVERSAL_POOL_SIZE: ${UNIVERSAL_POOL_SIZE:-0} WEB_POOL_SIZE: ${WEB_POOL_SIZE:-20} WEB_POOL_BUFFER: ${WEB_POOL_BUFFER:-2} X11VNC_FLAGS: ${X11VNC_FLAGS:--wait 5 -defer 5 -threads} MAX_ACTIVE_SERVICES_PER_USER: ${MAX_ACTIVE_SERVICES_PER_USER:-4} LOG_LEVEL: ${LOG_LEVEL:-INFO} LOG_SLOW_REQUEST_MS: ${LOG_SLOW_REQUEST_MS:-2000} GO_USER_LOCK_TIMEOUT_SECONDS: ${GO_USER_LOCK_TIMEOUT_SECONDS:-8} GO_POOL_LOCK_TIMEOUT_SECONDS: ${GO_POOL_LOCK_TIMEOUT_SECONDS:-20} POOL_DISPATCH_RETRIES: ${POOL_DISPATCH_RETRIES:-6} POOL_DISPATCH_REQUEST_TIMEOUT_SECONDS: ${POOL_DISPATCH_REQUEST_TIMEOUT_SECONDS:-2.0} POOL_DISPATCH_SLEEP_SECONDS: ${POOL_DISPATCH_SLEEP_SECONDS:-0.3} TRAEFIK_INTERNAL_URL: ${TRAEFIK_INTERNAL_URL:-http://traefik} WEB_RESOLUTION_MIN_WIDTH: ${WEB_RESOLUTION_MIN_WIDTH:-1024} WEB_RESOLUTION_MIN_HEIGHT: ${WEB_RESOLUTION_MIN_HEIGHT:-720} WEB_RESOLUTION_MAX_WIDTH: ${WEB_RESOLUTION_MAX_WIDTH:-3840} WEB_RESOLUTION_MAX_HEIGHT: ${WEB_RESOLUTION_MAX_HEIGHT:-2160} ENABLE_STARTUP_MAINTENANCE: ${ENABLE_STARTUP_MAINTENANCE:-0} depends_on: - db volumes: - /var/run/docker.sock:/var/run/docker.sock - ./app/static/service-icons:/app/static/service-icons networks: - portal_net restart: unless-stopped kiosk-image: image: portal-kiosk:latest build: context: ./kiosk profiles: ["build-only"] rdp-proxy-image: image: portal-rdp-proxy:latest build: context: ./rdp-proxy profiles: ["build-only"] universal-runtime-image: image: portal-universal-runtime:latest build: context: ./universal-runtime profiles: ["build-only"] networks: portal_net: name: portal_net volumes: pg_data: