Skip to content

fix: improve initial setup and dashboard status#27

Merged
TechHutTV merged 1 commit into
mainfrom
fix/disable-without-setup-key
Jul 15, 2026
Merged

fix: improve initial setup and dashboard status#27
TechHutTV merged 1 commit into
mainfrom
fix/disable-without-setup-key

Conversation

@TechHutTV

@TechHutTV TechHutTV commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Description

Fixes #25.

Problem

A fresh install starts NetBird before a profile has been configured. Without a setup key the daemon cannot connect, but the Settings page also blocks saving the disabled state because it validates the setup key first.

The dashboard then shows the expected authentication failure as a large error, which makes an unconfigured install look broken instead of simply waiting for setup.

Changes

  • Fresh installs now default to disabled and stay stopped until NetBird is configured and enabled.
  • Disabling only updates the global setting and stops the daemon; it no longer requires or rewrites profile credentials.
  • Enabling still requires a setup key when the profile needs to be registered or re-registered.
  • Upgrades preserve the existing enabled or disabled state. Older installs without a saved netbird.cfg keep their previous enabled behavior.
  • The dashboard now shows Disabled or Awaiting configuration, hides the expected pre-setup authentication error, and wraps unexpected errors so they cannot stretch the tile.
  • nginx reloads when wt0 first appears so the WebGUI becomes available on the NetBird address after initial setup.
  • README and Community Applications text now explain that NetBird must be configured and enabled after installation.

While testing the upgrade, I also found that fallback-built packages stored files with a ./ prefix. Unraid did not recognize ./install/doinst.sh during upgrades, so the event hooks disappeared and /install was left behind. The fallback builder now uses proper Slackware paths and rejects packages with a misplaced install script or prefixed payload paths.

Testing

Tested on a live Unraid 7.3.2 server with NetBird 0.74.4:

  • Upgraded an enabled install from 2026.07.14.1016; NetBird restarted, reconnected with the same identity and address, and preserved the config and profile hashes.
  • Disabled NetBird without sending profile credentials; the daemon stopped and the profile remained unchanged.
  • Confirmed rc.netbird start stays stopped while disabled and the dashboard shows Disabled.
  • Upgraded while disabled; the setting and profile were preserved and the daemon remained stopped.
  • Upgraded with the corrected package layout; Unraid ran doinst.sh, recreated the event hooks, stored the install script in pkgtools, and left no /install directory behind.
  • Ran PHP and Bash syntax checks, git diff --check, and package-layout validation.

Summary by CodeRabbit

  • New Features

    • NetBird is now disabled by default on fresh installations until configured and enabled.
    • Added clearer settings and dashboard states for disabled, awaiting configuration, connected, running, and stopped conditions.
    • NetBird can automatically reload the web interface after successful setup.
  • Bug Fixes

    • Preserved enablement settings across upgrades and reinstalls.
    • Improved package validation to ensure installation scripts are correctly placed.
    • Disabled installations now remain stopped across array starts and reboots.
  • Documentation

    • Updated setup instructions, daemon behavior, logging, and reboot persistence details.

@github-actions github-actions Bot added the fix label Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The plugin now defaults to disabled, preserves enablement during upgrades, gates startup and settings validation, improves dashboard states, reloads Nginx after wt0 readiness, updates documentation, and validates package archive layout.

NetBird enablement lifecycle

Layer / File(s) Summary
Runtime defaults and installation lifecycle
src/usr/local/emhttp/plugins/netbird/default.cfg, src/usr/local/etc/rc.d/rc.netbird, plugin/netbird.plg, src/install/doinst.sh
NetBird defaults to disabled, startup honors packaged and persistent configuration, and installation updates preserve or migrate enablement state.
Settings save and apply flow
src/usr/local/emhttp/plugins/netbird/Netbird-1-Settings.page, src/usr/local/emhttp/plugins/netbird/include/action.php, src/usr/local/emhttp/plugins/netbird/scripts/apply.sh
Enable and disable operations use separate validation and persistence paths; successful connection waits for wt0 before reloading Nginx.
Dashboard and behavior documentation
src/usr/local/emhttp/plugins/netbird/Netbird_dashboard.page, README.md, plugin/ca_template.xml
Dashboard states and error display reflect configuration status, while setup and array-start behavior are documented.
Package archive validation
scripts/build.sh
Tar fallback packaging preserves archive-root paths and verifies install/doinst.sh placement.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant Settings
  participant Apply
  participant NetBird
  participant Nginx
  Admin->>Settings: enable or disable NetBird
  Settings->>Apply: submit configuration
  Apply->>NetBird: apply settings
  NetBird-->>Apply: wt0 becomes ready
  Apply->>Nginx: reload WebGUI
Loading

Poem

A rabbit toggles “off” with a hop,
No daemon wakes when told to stop.
When wt0 blooms, logs softly sing,
The dashboard shows the proper thing.
Packages land with paths in place.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes unrelated packaging, docs, and nginx-reload changes beyond the disablement/dashboard fix in #25. Split the packaging, docs, and nginx-reload work into separate changes or justify them in the linked issue scope.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main fix to initial setup and dashboard status.
Linked Issues check ✅ Passed The PR allows NetBird to stay disabled before setup and hides the expected unconfigured dashboard error, matching #25.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/disable-without-setup-key

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
scripts/build.sh (1)

65-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Defend against filenames starting with a dash.

When expanding globs into command arguments, it is good practice to use -- to prevent filenames starting with a dash from being interpreted as options by the command.

♻️ Proposed refactor
-        tar --owner=0 --group=0 -cJf "${DIST_DIR}/${PKG_FILE}" "${package_entries[@]}"
+        tar --owner=0 --group=0 -cJf "${DIST_DIR}/${PKG_FILE}" -- "${package_entries[@]}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build.sh` at line 65, Update the tar invocation in the package
archive step to include the option terminator before the expanded
package_entries arguments, ensuring filenames beginning with a dash are treated
as archive entries rather than command options.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/usr/local/emhttp/plugins/netbird/include/action.php`:
- Around line 358-367: Reorder the configuration writes in the surrounding
action handler so Netbird\writeProfileCfg($name, $creds) completes successfully
before Netbird\writeGlobalCfg($globalCfg) persists ENABLE_NETBIRD=1. Preserve
the existing HTTP 500 responses and error messages, and ensure a profile-write
failure exits before the global configuration is written.

In `@src/usr/local/emhttp/plugins/netbird/scripts/apply.sh`:
- Around line 50-64: Update reload_nginx_when_wt0_ready so its polling condition
requires wt0 to have an assigned IPv4 address, rather than only verifying that
the interface exists. Keep the existing retry loop and reload behavior unchanged
once an address is detected.

---

Nitpick comments:
In `@scripts/build.sh`:
- Line 65: Update the tar invocation in the package archive step to include the
option terminator before the expanded package_entries arguments, ensuring
filenames beginning with a dash are treated as archive entries rather than
command options.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a104ee3-d512-42b2-95e3-d72afd82ace0

📥 Commits

Reviewing files that changed from the base of the PR and between 21dae7f and 474d901.

📒 Files selected for processing (11)
  • README.md
  • plugin/ca_template.xml
  • plugin/netbird.plg
  • scripts/build.sh
  • src/install/doinst.sh
  • src/usr/local/emhttp/plugins/netbird/Netbird-1-Settings.page
  • src/usr/local/emhttp/plugins/netbird/Netbird_dashboard.page
  • src/usr/local/emhttp/plugins/netbird/default.cfg
  • src/usr/local/emhttp/plugins/netbird/include/action.php
  • src/usr/local/emhttp/plugins/netbird/scripts/apply.sh
  • src/usr/local/etc/rc.d/rc.netbird

Comment on lines +358 to 367
if (!Netbird\writeGlobalCfg($globalCfg)) {
http_response_code(500);
echo json_encode(['type' => 'error', 'message' => 'Could not write the NetBird global configuration.']);
break;
}

if (!Netbird\writeProfileCfg($name, $creds)) {
if ($enable === '1' && !Netbird\writeProfileCfg($name, $creds)) {
http_response_code(500);
echo json_encode(['type' => 'error', 'message' => "Could not write profile '$name'."]);
break;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Persist the profile before enabling NetBird globally.

If writeProfileCfg() fails, ENABLE_NETBIRD=1 remains saved despite the reported failure. A later array start can therefore launch NetBird with missing or stale credentials.

Proposed fix
-        if (!Netbird\writeGlobalCfg($globalCfg)) {
-            http_response_code(500);
-            echo json_encode(['type' => 'error', 'message' => 'Could not write the NetBird global configuration.']);
-            break;
-        }
         if ($enable === '1' && !Netbird\writeProfileCfg($name, $creds)) {
             http_response_code(500);
             echo json_encode(['type' => 'error', 'message' => "Could not write profile '$name'."]);
             break;
         }
+        if (!Netbird\writeGlobalCfg($globalCfg)) {
+            http_response_code(500);
+            echo json_encode(['type' => 'error', 'message' => 'Could not write the NetBird global configuration.']);
+            break;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!Netbird\writeGlobalCfg($globalCfg)) {
http_response_code(500);
echo json_encode(['type' => 'error', 'message' => 'Could not write the NetBird global configuration.']);
break;
}
if (!Netbird\writeProfileCfg($name, $creds)) {
if ($enable === '1' && !Netbird\writeProfileCfg($name, $creds)) {
http_response_code(500);
echo json_encode(['type' => 'error', 'message' => "Could not write profile '$name'."]);
break;
}
if ($enable === '1' && !Netbird\writeProfileCfg($name, $creds)) {
http_response_code(500);
echo json_encode(['type' => 'error', 'message' => "Could not write profile '$name'."]);
break;
}
if (!Netbird\writeGlobalCfg($globalCfg)) {
http_response_code(500);
echo json_encode(['type' => 'error', 'message' => 'Could not write the NetBird global configuration.']);
break;
}
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 359-359: Avoid side effects in a file that defines symbols
Context: echo json_encode(['type' => 'error', 'message' => 'Could not write the NetBird global configuration.']);
Note: [CWE-710] Improper Adherence to Coding Standards.

(no-side-effect)


[warning] 364-364: Avoid side effects in a file that defines symbols
Context: echo json_encode(['type' => 'error', 'message' => "Could not write profile '$name'."]);
Note: [CWE-710] Improper Adherence to Coding Standards.

(no-side-effect)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/usr/local/emhttp/plugins/netbird/include/action.php` around lines 358 -
367, Reorder the configuration writes in the surrounding action handler so
Netbird\writeProfileCfg($name, $creds) completes successfully before
Netbird\writeGlobalCfg($globalCfg) persists ENABLE_NETBIRD=1. Preserve the
existing HTTP 500 responses and error messages, and ensure a profile-write
failure exits before the global configuration is written.

Comment on lines +50 to +64
# Once a first-time connection creates wt0, reload nginx so the Unraid WebGUI
# binds to the NetBird address added to network-extra.cfg by the installer. The
# watcher closes the apply lock descriptor so it cannot delay another operation.
reload_nginx_when_wt0_ready() {
(
exec 9>&-
for _ in $(seq 1 15); do
if ip -4 addr show wt0 >/dev/null 2>&1; then
/etc/rc.d/rc.nginx reload >/dev/null 2>&1
exit 0
fi
sleep 2
done
) >/dev/null 2>&1 </dev/null &
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Wait for an IPv4 address, not merely the wt0 device.

ip -4 addr show wt0 succeeds when the interface exists even if address assignment is still pending. The watcher can reload Nginx too early and then exit without retrying.

Proposed fix
-            if ip -4 addr show wt0 >/dev/null 2>&1; then
+            if ip -4 -o addr show dev wt0 | grep -q ' inet '; then
                 /etc/rc.d/rc.nginx reload >/dev/null 2>&1
                 exit 0
             fi

Also applies to: 230-230

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/usr/local/emhttp/plugins/netbird/scripts/apply.sh` around lines 50 - 64,
Update reload_nginx_when_wt0_ready so its polling condition requires wt0 to have
an assigned IPv4 address, rather than only verifying that the interface exists.
Keep the existing retry loop and reload behavior unchanged once an address is
detected.

@TechHutTV
TechHutTV merged commit 8e25225 into main Jul 15, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot disable netbird

1 participant