# docker-compose.yml services: ddc: # Name of the service (freely selectable, here 'ddc') container_name: ddc # Equivalent to --name ddc # The published image: "docker compose pull" fetches updates from Docker Hub. # It named the local tag "dockerdiscordcontrol" until 2026-10-11, which only a # build from the source creates, so a pull fetched nothing. image: dockerdiscordcontrol/dockerdiscordcontrol:latest build: . # Optional, from a clone: "docker compose up --build" builds it from the source restart: unless-stopped # Equivalent to --restart unless-stopped ports: - "9374:9374" # Equivalent to -p 9374:9374 (:) # Change the host port (9374) if it's already in use. volumes: # The Docker socket (adjust if yours is located elsewhere). Only DDC's # allowlist proxy inside the container opens it; DDC itself talks to the # proxy (docs/V3_ARCHITECTURE_PLAN.md §4). ":ro" protects the socket FILE, # not the API behind it - the proxy is what limits what DDC can ask for. - /var/run/docker.sock:/var/run/docker.sock:ro # Mount for the configuration directory # Use relative paths for easier setup - ./config:/app/config:cached # Mount for logs - ./logs:/app/logs:cached # Note: cached_displays are now built into the Docker image for Community App compatibility # Do NOT set "user:" here: a container started with --user cannot run the # allowlist proxy and falls back to the raw socket. Choose the IDs DDC runs # as with PUID/PGID below instead. environment: # PUID: "99" # Unraid's nobody # PGID: "100" # Unraid's users # FLASK_SECRET_KEY: Optional, best set via a .env file. If empty, DDC generates a # random key once and keeps it in config/.flask_secret_key. FLASK_SECRET_KEY: ${FLASK_SECRET_KEY:-} # No DOCKER_HOST here: the image points it at the allowlist proxy # (unix:///run/ddc-proxy/docker.sock). Setting it to the raw socket sent # every "docker exec" session - reset_password.py, disable_2fa.py - # around the proxy. # SECURITY: Discord Bot Token via environment variable (recommended) DISCORD_BOT_TOKEN: ${DISCORD_BOT_TOKEN:-} # Uncomment and set this to change the default admin password (admin) # DDC_ADMIN_PASSWORD: ${DDC_ADMIN_PASSWORD} security_opt: - no-new-privileges:true # Capability hardening (currently disabled — kept here as a tested-but- # unverified configuration). The entrypoint needs root caps to chown the # data dirs and switch users via su-exec / setpriv. The minimal set below # has been derived from scripts/entrypoint.sh; enable & test on staging # before promoting to production: # # cap_drop: # - ALL # cap_add: # - CHOWN # chown -R on /app/config and /app/logs at first run # - DAC_OVERRIDE # read/write across user boundaries during bootstrap # - FOWNER # touch/chmod for marker files # - SETUID # su-exec / setpriv user switch # - SETGID # su-exec / setpriv group switch # - SETPCAP # capability transition for setpriv # # See AUDIT.md (S10) for the rollback plan. # healthcheck: provided by the image (Dockerfile HEALTHCHECK - ignores HTTP(S)_PROXY and # follows DDC_WEB_PORT). Don't override it here unless you really need to. logging: # Equivalent to --log-driver and --log-opt driver: json-file options: max-size: "10m" max-file: "3" # Resource configuration for scalability deploy: resources: limits: cpus: '2.0' # Allow up to 2 CPU cores for better performance memory: 512M # Allow up to 512MB memory for larger installations pids: 256 # Cap process count — defends against fork-bomb DoS reservations: cpus: '0.25' # Reserve 25% of a CPU core for responsiveness memory: 128M # Reserve 128MB memory as minimum