diff --git a/docker-compose.host.yml b/docker-compose.host.yml new file mode 100644 index 0000000..603f648 --- /dev/null +++ b/docker-compose.host.yml @@ -0,0 +1,30 @@ +# Override file: switch the bot to host networking so WebRTC ICE works. +# +# Use: +# docker compose -f docker-compose.yml -f docker-compose.host.yml up -d +# +# Effect: +# * The bridge "ts6-net" attachment + the 127.0.0.1:8080 port mapping +# are stripped (compose merges by REPLACING list-valued keys when the +# overlay sets `null`-valued analogues, but Compose v2 needs the +# explicit empty list trick - see below). +# * `network_mode: host` joins the bot to the host's network namespace +# so it sees the real LAN/WAN interface; STUN now returns a usable +# srflx candidate and viewers can NAT-punch back through. +# +# Notes for this mode: +# * The host's port 8080 must be free (nothing else listening there). +# * `TS6_HOST` in .env should resolve from the HOST namespace, not the +# bridge: usually 127.0.0.1 if the TS6 server runs on the same host. +# * No `ports:` section in host mode (port mapping makes no sense). + +services: + bot: + network_mode: host + # Compose v2 needs both the explicit reset and the empty list to drop + # the bridge attachment from the base file. + networks: !reset null + ports: !reset null + +networks: + ts6-net: !reset null diff --git a/docker-compose.yml b/docker-compose.yml index d1672b5..27cfc35 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,26 +5,17 @@ # voice protocol directly to push the result into a TS6 channel via the # server's built-in stream feature. No HLS, no second nginx container. # -# Two networking modes are available via compose profiles: +# Default networking is the standard ts6-net bridge - simple, isolated, but +# WebRTC ICE candidate gathering can struggle behind docker NAT (STUN +# responses don't establish a usable srflx, so peers can't NAT-punch back +# to the bot). If you hit that, layer the host-network override on top: # -# * default (profile "bridge"): bot runs in the standard ts6-net bridge. -# Simple, isolated, but WebRTC ICE candidate gathering can struggle - -# STUN responses to the docker bridge IP often don't establish a -# usable srflx candidate, so peers can't NAT-punch back to the bot. +# docker compose up -d # bridge +# docker compose -f docker-compose.yml \ +# -f docker-compose.host.yml up -d # host net # -# * profile "host": bot runs in the host network namespace. The host's -# real LAN/WAN IPs become the ICE candidates, STUN works normally, -# and viewers can reach the bot. Trade-off: shares the host's port -# space (8080 must be free on the host), needs the TS6 server -# reachable via 127.0.0.1 / a public hostname. -# -# Use one or the other, not both: -# -# docker compose --profile bridge up -d # original behaviour -# docker compose --profile host up -d # works around ICE failures -# -# Without --profile only the bridge service runs (matching prior behaviour -# so existing setups keep working unchanged). +# The host overlay drops the bridge network + port mapping and joins the +# host network namespace so STUN gives the bot real LAN/WAN candidates. services: bot: @@ -32,7 +23,6 @@ services: context: . dockerfile: docker/Dockerfile container_name: ts6-stream-bot - profiles: ["", "bridge"] restart: unless-stopped env_file: .env shm_size: "1gb" @@ -49,25 +39,6 @@ services: retries: 3 start_period: 20s - bot-host: - build: - context: . - dockerfile: docker/Dockerfile - container_name: ts6-stream-bot - profiles: ["host"] - restart: unless-stopped - env_file: .env - shm_size: "1gb" - network_mode: host - volumes: - - ./src:/app/src:ro - healthcheck: - test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 20s - networks: ts6-net: external: true