# Reference deployment: a single manager container that controls Docker through # the host's Docker socket, mounted directly (DOCKER_HOST=unix:///var/run/docker.sock). # # RECOMMENDED HARDENING: uncomment the socket-proxy service below, then on the # manager set DOCKER_HOST to tcp://socket-proxy:2375, remove the socket bind # mount, and add socket-proxy-net to its networks. The manager then only gets # the Docker API endpoints it actually uses (containers, images, ping) — exec, # volumes, networks, build, swarm, and secrets stay blocked at the proxy. # Caveat: the proxy filters endpoints, not payloads — container *creation* is # still allowed, so this narrows the blast radius rather than eliminating it. # # On Unraid, set HOST_DATA_DIR to the real appdata path so bind mounts for the # spawned game containers resolve correctly on the host, e.g. # HOST_DATA_DIR=/mnt/user/appdata/palisade name: palisade services: manager: image: ghcr.io/shakes63/palisade:latest build: context: . dockerfile: Dockerfile container_name: palisade environment: NODE_ENV: production API_PORT: 8787 WEB_PORT: 3000 PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-http://localhost:3000} DATA_DIR: /data DATABASE_URL: file:/data/db.sqlite HOST_DATA_DIR: ${HOST_DATA_DIR:-/mnt/user/appdata/palisade} DOCKER_HOST: unix:///var/run/docker.sock SECRETS_KEY: ${SECRETS_KEY:?set a 64-hex-char SECRETS_KEY} JWT_SECRET: ${JWT_SECRET:?set a JWT_SECRET} PUID: ${PUID:-99} PGID: ${PGID:-100} TZ: ${TZ:-UTC} # Run game containers on the host network (removes Docker NAT → more reliable # ASA/EOS public listing). When on, the manager reaches RCON via # host.docker.internal (see extra_hosts below). Default off = palisade-net bridge. GAME_HOST_NETWORK: ${GAME_HOST_NETWORK:-false} volumes: - ${HOST_DATA_DIR:-./data}:/data # Direct Docker control. The manager runs as root in-container, so it can use # the root:docker-owned host socket without a group-add. - /var/run/docker.sock:/var/run/docker.sock # Lets the manager reach game-container RCON via host.docker.internal when # GAME_HOST_NETWORK is on; harmless when it's off. extra_hosts: - "host.docker.internal:host-gateway" ports: - "3000:3000" # web UI - "8787:8787" # API (optional to expose; web can proxy) networks: [palisade-net] restart: unless-stopped # Least-privilege Docker API gateway (opt in — see header comment). # socket-proxy: # image: tecnativa/docker-socket-proxy:latest # container_name: palisade-socket-proxy # environment: # # Palisade's full API surface: container lifecycle + image pulls + ping. # CONTAINERS: 1 # list/inspect/logs/stats/attach/wait # IMAGES: 1 # image inspect + pull (with POST) # POST: 1 # create/remove/wait and other writes # ALLOW_START: 1 # ALLOW_STOP: 1 # ALLOW_RESTARTS: 1 # # Everything else stays at the proxy's deny-by-default: # # EXEC/VOLUMES/NETWORKS/BUILD/SWARM/SECRETS/AUTH/PLUGINS = 0 # volumes: # - /var/run/docker.sock:/var/run/docker.sock:ro # networks: [socket-proxy-net] # restart: unless-stopped networks: # Named, not compose-prefixed: the manager creates game containers on this exact # name. It sorts after br0/bond0/eth0 on purpose — see DEFAULT_SHARED_NETWORK. palisade-net: name: palisade-net # socket-proxy-net: # internal: true # no outbound access; only the manager talks to the proxy