diff --git a/core/archipelago/src/container/prod_orchestrator.rs b/core/archipelago/src/container/prod_orchestrator.rs index 26d9852f..73c0ffa6 100644 --- a/core/archipelago/src/container/prod_orchestrator.rs +++ b/core/archipelago/src/container/prod_orchestrator.rs @@ -469,7 +469,18 @@ async fn http_host_port_ready(port: u16, path: &str) -> bool { } async fn wait_for_manifest_host_ports(manifest: &AppManifest, timeout_secs: u64) -> Result<()> { - for port in manifest.app.ports.iter().map(|p| p.host) { + // Only TCP host ports are reachability-probed: the probe is a TCP connect, + // which a UDP/SCTP listener (e.g. netbird's 3478/udp STUN) can never answer, + // so probing it would always "fail" and drive an endless host-port repair + // loop (observed on .228 after netbird's manifest deploy). Default protocol + // (empty) is tcp. + for port in manifest + .app + .ports + .iter() + .filter(|p| matches!(p.protocol.to_ascii_lowercase().as_str(), "" | "tcp")) + .map(|p| p.host) + { let ready = match manifest.app.id.as_str() { "uptime-kuma" => wait_for_http_host_port(port, "/", timeout_secs).await, _ => wait_for_host_port(port, timeout_secs).await,