# ============================================================================= # docker-socket-proxy + gateway nginx (api-key) — per host SiCABE. # # Control-panel (sicabe-control-panel) TIDAK pernah menyentuh /var/run/docker.sock # langsung. Di setiap host yang dikelola dipasang stack ini; panel berbicara ke # endpoint HTTP gateway (lihat desain: # docs/desain-kontrol-multi-host-docker-socket-proxy.md). # # Arsitektur: # panel ──HTTP + X-Api-Key──► gateway (nginx, allowlist path) # └──► docker-proxy (docker-socket-proxy, ACL) # └──► /var/run/docker.sock (:ro) # # Keamanan (jangan longgarkan tanpa kebutuhan): # * Socket daemon di-mount READ-ONLY (:ro). # * docker-socket-proxy TIDAK punya auth — container tsb HANYA di jaringan # internal compose (expose, tanpa port host). Yang diekspos ke host hanyalah # gateway nginx. # * nginx memeriksa header `X-Api-Key` (wajib sama dengan PROXY_API_KEY) dan # allowlist path (hanya route yang dibutuhkan kontrol, sisanya 403). # * ACL docker-socket-proxy hanya mengizinkan yang dibutuhkan: # CONTAINERS (list/inspect/restart/stop/start/logs/top), POST (restart), # INFO (version/ping), SYSTEM (/events). # Kategori lain (EXEC, BUILD, IMAGES, NETWORKS, VOLUMES, ...) DIMATIKAN. # * Versi image DIPATOK (bukan :latest) untuk produksi. # # Mode alternatif SSH-tunnel / single-host (tanpa api-key): # Hapus/komentari service `gateway`, lalu pada service `docker-proxy` ganti # `expose` dengan port publik: # ports: # - "127.0.0.1:${PROXY_PORT:-22375}:2375" # # Cara pakai (HTTP + api-key): # PROXY_API_KEY='' PROXY_BIND_IP=127.0.0.1 PROXY_PORT=22375 \ # docker compose up -d # - PROXY_API_KEY WAJIB diisi (compose akan error bila kosong). Ini secret — # jangan di-commit; isi via env/deploy. # - PROXY_BIND_IP: 127.0.0.1 utk single-host/SSH-tunnel; IP internal host bila # panel di host lain dalam network tepercaya. JANGAN expose ke internet. # - Panel: SICABE_HOSTS=[{"name":"...","proxyUrl":"http://:", # "apiKey":"","enabled":true}] # ============================================================================= name: sicabe-docker-proxy services: # --- docker-socket-proxy: ACL, hanya di jaringan internal compose --------- docker-proxy: image: tecnativa/docker-socket-proxy:v0.5.0 container_name: sicabe-docker-proxy environment: # --- ACL: hanya yang dibutuhkan kontrol --- CONTAINERS: "1" # list/inspect/restart/stop/start/logs/top POST: "1" # dibutuhkan utk restart/start/stop INFO: "1" # info daemon (version, /_ping, healthcheck) SYSTEM: "1" # /events (feed Observability). Set "0" bila tak dipakai # --- matikan semua yang tidak perlu --- EXEC: "0" SWARM: "0" SERVICES: "0" SECRETS: "0" CONFIGS: "0" NETWORKS: "0" VOLUMES: "0" IMAGES: "0" BUILD: "0" GRPC: "0" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro expose: - "2375" # hanya reachable dari gateway (network compose) read_only: true tmpfs: - /tmp - /run # HAProxy menulis pidfile /run/haproxy.pid restart: unless-stopped logging: driver: json-file options: max-size: "10m" max-file: "3" # --- gateway nginx: api-key + allowlist path (satu-satunya port ke host) -- gateway: image: nginx:1.30.4-alpine3.24 container_name: sicabe-docker-proxy-gateway depends_on: - docker-proxy environment: # WAJIB: compose error bila PROXY_API_KEY tidak di-set. PROXY_API_KEY: ${PROXY_API_KEY:?PROXY_API_KEY wajib diisi (secret acak kuat)} ports: - "${PROXY_BIND_IP:-127.0.0.1}:${PROXY_PORT:-22375}:80" volumes: # Template di-substitute oleh envsubst docker-entrypoint nginx saat start # (${PROXY_API_KEY} diganti nilai env; $http_* tetap utuh) → output ke # /etc/nginx/conf.d/default.conf (menggantikan default bawaan image). - ./nginx/gateway.conf.template:/etc/nginx/templates/default.conf.template:ro restart: unless-stopped logging: driver: json-file options: max-size: "10m" max-file: "3"