services: backend: build: ./backend user: "${DOCKER_UID:-1000}:${DOCKER_GID:-1000}" cap_drop: - ALL cap_add: - NET_RAW # required for ICMP ping (discovery feature) # no-new-privileges omitted: ping relies on file capabilities (cap_net_raw=ep). volumes: - ./db_data:/app/data restart: unless-stopped networks: - internal environment: - SECRET_KEY=${SECRET_KEY} - INITIAL_ADMIN_PASSWORD=${INITIAL_ADMIN_PASSWORD} - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-*} # ── Docker secret alternative for SECRET_KEY ───────────────────────────── # Instead of passing SECRET_KEY via environment, you can mount a secret file. # The backend reads data/secret_key.txt when SECRET_KEY env var is unset. # # 1. Generate the secret: # python3 -c "import secrets; print(secrets.token_hex(32))" \ # > ~/.secrets/topologie_secret_key # chmod 600 ~/.secrets/topologie_secret_key # # 2. Uncomment the blocks below and the top-level `secrets:` section, # then remove SECRET_KEY from .env. # #secrets: # - source: secret_key # target: /app/data/secret_key.txt # mode: 0400 healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"] interval: 30s timeout: 5s retries: 3 start_period: 15s frontend: build: ./frontend ports: - "${BIND_ADDRESS:-0.0.0.0}:8080:8080" cap_drop: - ALL security_opt: - no-new-privileges:true depends_on: backend: condition: service_healthy restart: unless-stopped networks: - internal healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:8080/"] interval: 30s timeout: 5s retries: 3 start_period: 10s networks: internal: driver: bridge # ── Docker secret (uncomment to use — see backend service above) ───────────── #secrets: # secret_key: # file: ~/.secrets/topologie_secret_key