From 854261bf987cb34864f6e0ef61a43b9f6e122460 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 18:42:30 +0000 Subject: [PATCH 1/5] Fix coturn healthcheck: use netstat instead of ss The coturn/coturn Docker image is Alpine-based and doesn't include iproute2 (which provides ss). This caused the healthcheck to fail immediately, marking coturn as unhealthy and preventing the asterisk container from starting due to its service_healthy dependency. Alpine's busybox includes netstat, so use that instead. https://claude.ai/code/session_01Vm6NLaQuzM4VosAotqS1q8 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 52d8031..233c64a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -101,7 +101,7 @@ services: exec turnserver $$ARGS restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "ss -uln | grep -q ':3478'"] + test: ["CMD-SHELL", "netstat -uln | grep -q ':3478'"] interval: 30s timeout: 5s retries: 3 From a5e6e18015d7c7b33b176e127817c4a251b5d300 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 20:04:38 +0000 Subject: [PATCH 2/5] Use turnutils_stunclient for coturn healthcheck The coturn/coturn Alpine image doesn't include ss or netstat. Use turnutils_stunclient (included in the coturn image) which actually verifies the STUN server is responding, not just that a port is open. Also add start_period to avoid false failures during startup. https://claude.ai/code/session_01Vm6NLaQuzM4VosAotqS1q8 --- docker-compose.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 233c64a..c731367 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -101,10 +101,11 @@ services: exec turnserver $$ARGS restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "netstat -uln | grep -q ':3478'"] - interval: 30s + test: ["CMD", "turnutils_stunclient", "127.0.0.1"] + interval: 10s timeout: 5s retries: 3 + start_period: 10s volumes: asterisk-config: From 37765f45691eb5c3a1e48fd03b3835902e3c202b Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 20:09:02 +0000 Subject: [PATCH 3/5] Rewrite coturn service to fix startup crash Three changes to fix coturn failing to start: 1. Use environment vars instead of mixing Compose interpolation (${VAR}) with shell escaping ($$ARGS) in the command - the old approach was fragile and could produce broken shell scripts 2. Remove --no-loopback-peers - since Asterisk runs on the same host (network_mode: host), coturn must allow relay to localhost otherwise it refuses to relay media to Asterisk 3. Health check: redirect output to /dev/null to avoid noise https://claude.ai/code/session_01Vm6NLaQuzM4VosAotqS1q8 --- docker-compose.yml | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c731367..faf6fec 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,26 +82,36 @@ services: image: coturn/coturn:latest container_name: easy-asterisk-coturn network_mode: host + # Pass env vars into container, then use simple shell to build command + environment: + - TURN_USER=${TURN_USERNAME:-easyasterisk} + - TURN_PASS=${TURN_PASSWORD:-changeme} + - REALM=${DOMAIN_NAME:-localhost} + - MIN_PORT=${TURN_RELAY_MIN:-49152} + - MAX_PORT=${TURN_RELAY_MAX:-49252} + - EXT_IP=${PUBLIC_IP:-} entrypoint: ["/bin/sh", "-c"] command: - | - # Build coturn arguments - ARGS="-n --listening-port=3478 --fingerprint --lt-cred-mech" - ARGS="$$ARGS --user=${TURN_USERNAME:-easyasterisk}:${TURN_PASSWORD:-changeme}" - ARGS="$$ARGS --realm=${DOMAIN_NAME:-localhost}" - ARGS="$$ARGS --min-port=${TURN_RELAY_MIN:-49152}" - ARGS="$$ARGS --max-port=${TURN_RELAY_MAX:-49252}" - # Only add external-ip if PUBLIC_IP is set - if [ -n "${PUBLIC_IP:-}" ]; then - ARGS="$$ARGS --external-ip=${PUBLIC_IP}" + EXTRA="" + if [ -n "$EXT_IP" ]; then + EXTRA="--external-ip=$EXT_IP" fi - ARGS="$$ARGS --no-tls --no-dtls --no-cli" - ARGS="$$ARGS --no-multicast-peers --no-loopback-peers" - ARGS="$$ARGS --log-file=stdout" - exec turnserver $$ARGS + exec turnserver -n \ + --listening-port=3478 \ + --fingerprint \ + --lt-cred-mech \ + --user=$TURN_USER:$TURN_PASS \ + --realm=$REALM \ + --min-port=$MIN_PORT \ + --max-port=$MAX_PORT \ + --no-tls --no-dtls --no-cli \ + --no-multicast-peers \ + --log-file=stdout \ + $EXTRA restart: unless-stopped healthcheck: - test: ["CMD", "turnutils_stunclient", "127.0.0.1"] + test: ["CMD-SHELL", "turnutils_stunclient 127.0.0.1 >/dev/null 2>&1"] interval: 10s timeout: 5s retries: 3 From 8a14b3eded6473e08e3ac5dde6893eb552738db7 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 20:18:22 +0000 Subject: [PATCH 4/5] Remove shell entrypoint override from coturn - use native image entrypoint The coturn/coturn image has its own docker-entrypoint.sh that handles arg parsing. Overriding it with /bin/sh -c adds a failure point. Now passing args as a clean list directly to the native entrypoint. Also drops --external-ip for now (added back once coturn starts). https://claude.ai/code/session_01Vm6NLaQuzM4VosAotqS1q8 --- docker-compose.yml | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index faf6fec..b909494 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,33 +82,22 @@ services: image: coturn/coturn:latest container_name: easy-asterisk-coturn network_mode: host - # Pass env vars into container, then use simple shell to build command - environment: - - TURN_USER=${TURN_USERNAME:-easyasterisk} - - TURN_PASS=${TURN_PASSWORD:-changeme} - - REALM=${DOMAIN_NAME:-localhost} - - MIN_PORT=${TURN_RELAY_MIN:-49152} - - MAX_PORT=${TURN_RELAY_MAX:-49252} - - EXT_IP=${PUBLIC_IP:-} - entrypoint: ["/bin/sh", "-c"] + # Uses the image's native docker-entrypoint.sh (no shell override) + # which prepends 'turnserver' when first arg starts with '-' command: - - | - EXTRA="" - if [ -n "$EXT_IP" ]; then - EXTRA="--external-ip=$EXT_IP" - fi - exec turnserver -n \ - --listening-port=3478 \ - --fingerprint \ - --lt-cred-mech \ - --user=$TURN_USER:$TURN_PASS \ - --realm=$REALM \ - --min-port=$MIN_PORT \ - --max-port=$MAX_PORT \ - --no-tls --no-dtls --no-cli \ - --no-multicast-peers \ - --log-file=stdout \ - $EXTRA + - -n + - --listening-port=3478 + - --fingerprint + - --lt-cred-mech + - --user=${TURN_USERNAME:-easyasterisk}:${TURN_PASSWORD:-changeme} + - --realm=${DOMAIN_NAME:-localhost} + - --min-port=${TURN_RELAY_MIN:-49152} + - --max-port=${TURN_RELAY_MAX:-49252} + - --no-tls + - --no-dtls + - --no-cli + - --no-multicast-peers + - --log-file=stdout restart: unless-stopped healthcheck: test: ["CMD-SHELL", "turnutils_stunclient 127.0.0.1 >/dev/null 2>&1"] From f71bec27e5f8b3c9a8bbcb1be0ee48a2191dfa61 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 00:27:46 +0000 Subject: [PATCH 5/5] Fix coturn crash: image runs as nobody, can't create pidfile The coturn/coturn:latest image sets USER nobody:nogroup. On startup, turnserver tries to create /var/run/turnserver.pid which nobody can't write to, causing an immediate crash (the 2.2s "Error" in compose). Fix: add user: root to the coturn service. Since we already use network_mode: host, the container has broad host access anyway. Also adds DETECT_EXTERNAL_IP=yes which is the image's native way to auto-detect and set --external-ip, replacing our shell script. https://claude.ai/code/session_01Vm6NLaQuzM4VosAotqS1q8 --- docker-compose.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b909494..cfeea95 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,8 +82,12 @@ services: image: coturn/coturn:latest container_name: easy-asterisk-coturn network_mode: host - # Uses the image's native docker-entrypoint.sh (no shell override) - # which prepends 'turnserver' when first arg starts with '-' + # The coturn image runs as nobody:nogroup by default, which cannot + # create /var/run/turnserver.pid. Run as root to avoid this. + user: root + environment: + # Image-native external IP detection (adds --external-ip automatically) + - DETECT_EXTERNAL_IP=${DETECT_EXTERNAL_IP:-yes} command: - -n - --listening-port=3478