From 8a4d5c77e06cb9c8f2b6b5538a8404133216a4f8 Mon Sep 17 00:00:00 2001 From: Levente Farkas Date: Mon, 13 Jul 2026 14:56:50 +0200 Subject: [PATCH 1/3] fix: correct stale app.netbird.io management URL for NetBird Cloud (#401) Older installs persisted https://app.netbird.io (the dashboard host) as the Management URL in config.json. That host only serves the web UI and does not negotiate the HTTP/2 ALPN the management gRPC service requires, so the client fails with "missing selected ALPN property" and never connects. NetBird's built-in migration ignores this host, so the service script now rewrites it to https://api.netbird.io when the user has set no management_url of their own. Co-Authored-By: Claude Opus 4.8 --- .../rootfs/etc/s6-overlay/s6-rc.d/netbird/run | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run b/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run index 93a07e4..b4ba634 100755 --- a/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run +++ b/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run @@ -23,6 +23,23 @@ rosenpass="$(bashio::config 'rosenpass')" rosenpass_permissive="$(bashio::config 'rosenpass_permissive')" log_level="$(bashio::config 'log_level')" +# Self-heal a stale NetBird Cloud management URL (see issue #401). +# Older installs persisted https://app.netbird.io as the Management URL in +# config.json. app.netbird.io only serves the web dashboard and does not +# negotiate the HTTP/2 ALPN that the management gRPC service requires, so the +# client fails with "missing selected ALPN property" and never connects. +# NetBird's built-in auto-migration ignores this host, so correct it here by +# pointing the client at the real cloud management endpoint. Only applied when +# the user has not set their own management_url, leaving self-hosted setups +# untouched; NetBird then rewrites and persists the corrected URL on startup. +if [ "${management_url}" = "" ] && [ -f "${CONFIG_PATH}" ]; then + current_mgmt_host="$(jq -r '.ManagementURL.Host // empty' "${CONFIG_PATH}" 2>/dev/null)" + if [ "${current_mgmt_host%%:*}" = "app.netbird.io" ]; then + bashio::log.warning "Persisted Management URL points at app.netbird.io (dashboard); correcting to https://api.netbird.io" + management_url="https://api.netbird.io" + fi +fi + options+=(--foreground-mode) options+=(--config "${CONFIG_PATH}") options+=(--log-file console) From a1c7528e63ca0d0aa3f6cfc650b99ff8fe90e53a Mon Sep 17 00:00:00 2001 From: Levente Farkas Date: Mon, 13 Jul 2026 15:01:23 +0200 Subject: [PATCH 2/3] fix: read flat ManagementURL string for self-heal check The persisted NetBird config.json stores ManagementURL as a flat string (e.g. https://app.netbird.io:443), not a nested object. The previous .ManagementURL.Host jq filter always returned empty, so the self-heal never triggered. Read the string and derive the host from it. Co-Authored-By: Claude Opus 4.8 --- netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run b/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run index b4ba634..ddb799f 100755 --- a/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run +++ b/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run @@ -33,7 +33,9 @@ log_level="$(bashio::config 'log_level')" # the user has not set their own management_url, leaving self-hosted setups # untouched; NetBird then rewrites and persists the corrected URL on startup. if [ "${management_url}" = "" ] && [ -f "${CONFIG_PATH}" ]; then - current_mgmt_host="$(jq -r '.ManagementURL.Host // empty' "${CONFIG_PATH}" 2>/dev/null)" + current_mgmt_url="$(jq -r '.ManagementURL // empty' "${CONFIG_PATH}" 2>/dev/null)" + current_mgmt_host="${current_mgmt_url#*://}" + current_mgmt_host="${current_mgmt_host%%/*}" if [ "${current_mgmt_host%%:*}" = "app.netbird.io" ]; then bashio::log.warning "Persisted Management URL points at app.netbird.io (dashboard); correcting to https://api.netbird.io" management_url="https://api.netbird.io" From 58d98646d3f3e8a5c684c46a8362c6c637a0910f Mon Sep 17 00:00:00 2001 From: Levente Farkas Date: Mon, 13 Jul 2026 15:04:01 +0200 Subject: [PATCH 3/3] fix: read Management host from nested ManagementURL.Host in config.json Revert an incorrect review suggestion. NetBird persists ManagementURL as a nested object (net/url.URL marshals via reflected struct fields, not as a string), so the host lives at .ManagementURL.Host. Verified empirically with a Go json.Marshal test and confirmed bash -n + shellcheck clean. Co-Authored-By: Claude Opus 4.8 --- netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run b/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run index ddb799f..b4ba634 100755 --- a/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run +++ b/netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run @@ -33,9 +33,7 @@ log_level="$(bashio::config 'log_level')" # the user has not set their own management_url, leaving self-hosted setups # untouched; NetBird then rewrites and persists the corrected URL on startup. if [ "${management_url}" = "" ] && [ -f "${CONFIG_PATH}" ]; then - current_mgmt_url="$(jq -r '.ManagementURL // empty' "${CONFIG_PATH}" 2>/dev/null)" - current_mgmt_host="${current_mgmt_url#*://}" - current_mgmt_host="${current_mgmt_host%%/*}" + current_mgmt_host="$(jq -r '.ManagementURL.Host // empty' "${CONFIG_PATH}" 2>/dev/null)" if [ "${current_mgmt_host%%:*}" = "app.netbird.io" ]; then bashio::log.warning "Persisted Management URL points at app.netbird.io (dashboard); correcting to https://api.netbird.io" management_url="https://api.netbird.io"