From 6f6ad52072393ea2ac910fa22a64be5484fa0596 Mon Sep 17 00:00:00 2001 From: Bruno Mercier Costa <94469565+emrcbrn@users.noreply.github.com> Date: Thu, 15 Oct 2026 15:35:51 +0200 Subject: [PATCH] docs: add common issues to the troubleshooting hub and fill out the area tiles (#1039) * docs: add common issues to the troubleshooting hub and fill out the area tiles Lead the Troubleshooting hub with a table of the issues support sees most often, and give each area tile the sections a reader actually needs, including a new Reverse Proxy tile. Add the case where a teammate signs in and gets their own account to the pending approval page, with sign-in domains as the fix. List the headings rendered by the troubleshooting components in "On this page", which previously only showed Markdown headings. * docs: address review on account-access and support wording - Personal-address teammate: drop the direct-invite advice, since a user who already has an account can't be invited; point to the work address or NetBird Support instead. - Support audience: say NetBird Support is mainly for paying Cloud customers and commercial-license deployments, consistently across the troubleshooting hub, the support page, and the report-bug page. * docs: align the troubleshooting hub table and rework Still stuck - Common issues table: fixed 50/50 columns, with the Start here column padded to line up with the right-hand area tiles at any width. - Still stuck: match the width and side padding of the tiles, center the title and buttons, and put a short audience note under each button. The report hint moves to its own line above the links, with a new Debug bundle link. --- mdx/rehype.mjs | 21 ++- src/components/StillStuck.jsx | 113 ++++++++++---- src/pages/help/netbird-support.mdx | 4 +- src/pages/help/report-bug-issues.mdx | 2 +- .../help/troubleshooting-account-access.mdx | 28 +++- src/pages/help/troubleshooting.mdx | 145 ++++++++++++------ src/pages/selfhosted/troubleshooting.mdx | 1 + 7 files changed, 237 insertions(+), 77 deletions(-) diff --git a/mdx/rehype.mjs b/mdx/rehype.mjs index d6b85d9d..4dfa606c 100644 --- a/mdx/rehype.mjs +++ b/mdx/rehype.mjs @@ -165,11 +165,30 @@ function rehypeAddMDXExports(getExports) { } } +// Components that render their own `h2` from `title` and `id` props. The +// heading is not in the MDX tree, so it is added to the table of contents here. +const sectionComponents = ['TroubleshootingStart', 'TroubleshootingTiles', 'StillStuck'] + +function jsxStringAttribute(node, name) { + let attribute = node.attributes?.find((a) => a.name === name) + return typeof attribute?.value === 'string' ? attribute.value : undefined +} + function getSections(node) { let sections = [] for (let child of node.children ?? []) { - if (child.type === 'element' && ['h2', 'h3', 'h4', 'h5', 'h6'].includes(child.tagName)) { + if (child.type === 'mdxJsxFlowElement' && sectionComponents.includes(child.name)) { + let title = jsxStringAttribute(child, 'title') + let id = jsxStringAttribute(child, 'id') + if (title && id) { + sections.push(`{ + title: ${JSON.stringify(title)}, + id: ${JSON.stringify(id)}, + tagName: "h2" + }`) + } + } else if (child.type === 'element' && ['h2', 'h3', 'h4', 'h5', 'h6'].includes(child.tagName)) { sections.push(`{ title: ${JSON.stringify(toString(child))}, id: ${JSON.stringify(child.properties.id)}, diff --git a/src/components/StillStuck.jsx b/src/components/StillStuck.jsx index 5eb9b145..06920e74 100644 --- a/src/components/StillStuck.jsx +++ b/src/components/StillStuck.jsx @@ -1,48 +1,105 @@ import { Fragment } from 'react' +import Link from 'next/link' import { Button } from '@/components/Button' /** * "Still stuck?" call-to-action banner for the bottom of the Troubleshooting - * hub. Renders a short prompt and a row of action buttons. + * hub. Renders a centered title, a row of action buttons with an optional note + * under each, and an optional row of secondary links. * * @param {string} [title='Still stuck?'] - * @param {string} description - * @param {Array<{label: string, href: string, primary?: boolean}>} actions + * @param {string} [id] - Optional id for the title anchor (listed in "On this page") + * @param {string} [description] + * @param {Array<{label: string, href: string, primary?: boolean, note?: string}>} actions * @param {string} [separator] - Optional word rendered between buttons (e.g. "or"), * so two equally-weighted actions don't read as a recommended-vs-secondary pair. + * @param {string} [linksLabel] - Lead-in text, on its own line above the secondary links + * @param {Array<{label: string, href: string}>} [links] - Secondary text links */ export function StillStuck({ title = 'Still stuck?', + id, description, actions = [], separator, + linksLabel, + links = [], }) { + // `not-prose` on the card would also drop the prose layout (left margin and + // max width), so the outer div keeps it and matches TroubleshootingTiles. return ( -
-

- {title} -

- {description && ( -

- {description} -

- )} -
- {actions.map((action, i) => ( - - {i > 0 && separator && ( - - {separator} - - )} - - - ))} +
+
+

+ {title} +

+ {description && ( +

+ {description} +

+ )} + {/* Stacked in reading order on phones. From `sm` up, a two-row grid puts + each note under its button and keeps the separator level with the + buttons, not the notes. */} +
'minmax(0, 16rem)').join(' auto '), + }} + > + {actions.map((action, i) => ( + + {i > 0 && separator && ( + + {separator} + + )} +
+ +
+ {action.note && ( +

+ {action.note} +

+ )} +
+ ))} +
+ {links.length > 0 && ( +
+ {linksLabel &&

{linksLabel}

} +

+ {links.map((link, i) => ( + + {i > 0 && } + + {link.label} + + + ))} +

+
+ )}
) diff --git a/src/pages/help/netbird-support.mdx b/src/pages/help/netbird-support.mdx index 1e5ab522..737c2fbf 100644 --- a/src/pages/help/netbird-support.mdx +++ b/src/pages/help/netbird-support.mdx @@ -1,7 +1,7 @@ import { SupportBanner } from "@/components/SupportBanner" export const description = - "NetBird Support for (paying) Cloud customers and users, and commercial-license self-hosted deployments: reach the team with a pre-filled report." + "NetBird Support, mainly for paying Cloud customers and commercial-license self-hosted deployments: reach the team with a pre-filled report." export const reportTemplate = `NetBird issue report ===================== @@ -39,7 +39,7 @@ export const supportMailto = `mailto:support@netbird.io?subject=${encodeURICompo diff --git a/src/pages/help/troubleshooting-account-access.mdx b/src/pages/help/troubleshooting-account-access.mdx index bfd22280..ab52d3bb 100644 --- a/src/pages/help/troubleshooting-account-access.mdx +++ b/src/pages/help/troubleshooting-account-access.mdx @@ -1,11 +1,13 @@ import {Note} from "@/components/mdx"; -export const description = "Why NetBird shows you a Waiting for Approval screen, or adds you to an account you don't recognize, and how to resolve it safely." +export const description = "Why NetBird shows you a Waiting for Approval screen, adds you to an account you don't recognize, or gives a teammate an account of their own, and how to resolve it safely." # Pending approval and account invitations Signed in to NetBird and landed on a **Waiting for Approval** screen, or in a NetBird account you don't recognize? This usually is not a bug. It almost always means you were added to an existing organization automatically, and someone in that organization still has to approve you. +The opposite also happens: a teammate signs in and gets a new, empty account of their own instead of joining yours. See [A teammate got their own account](#a-teammate-got-their-own-account). + ## What the Waiting for Approval screen tells you After you sign in, the dashboard shows three steps: **Account Created**, **Waiting for Approval**, and **Join Account**. Your user exists, but the account requires new users to be approved before they can use it, so you are held at the second step until someone approves you. @@ -23,7 +25,7 @@ The screen has two buttons: NetBird can add people to an account without a manual, one-by-one invite: -- **Indirect (domain) invites.** If an account has verified your email domain, new sign-ups with that domain join it automatically. See [Indirect user invites](/manage/team/add-users-to-your-network#indirect-user-invites). +- **Domain matching.** On NetBird Cloud, new sign-ups join an existing account automatically when their email domain belongs to it: either the private domain the account signed up with, or another domain the account has verified as a [sign-in domain](/manage/team/sign-in-domains). See [Indirect user invites](/manage/team/add-users-to-your-network#indirect-user-invites). - **Identity provider sync.** If your organization connects NetBird to its identity provider, being added to a synced group in the IdP provisions your user in NetBird. See [Provision users and groups from your identity provider](/manage/team/idp-sync). - **Approval is required.** When an account turns on [user approval](/manage/team/approve-users#require-user-approval), new users stay blocked until an admin approves them. That block is the Waiting for Approval screen you see. @@ -38,6 +40,28 @@ NetBird can add people to an account without a manual, one-by-one invite: On self-hosted NetBird, the Waiting for Approval screen needs dashboard v2.93.0 or later, and the owner's address on it needs management v0.80.0 or later. Older dashboards show a **User Approval Pending** error page with only a **Sign Out** button instead: the steps above still apply, but after you are approved, sign out and sign in again. +## A teammate got their own account + +A teammate signs in to NetBird Cloud and lands in a new, empty account, with none of your peers, users, or policies. NetBird did not match their email domain to your account, so it created a separate one for them. One of these is usually the reason: + +- **They use another of your business's domains.** Only the domain your account signed up with matches from the start. A country domain such as `company.co.uk`, a subsidiary, or a second brand matches only after an Owner or Admin adds and verifies it as a [sign-in domain](/manage/team/sign-in-domains). +- **They signed in with a personal address**, such as a Gmail account. Public email domains never match an account. Ask them to sign in with their work address instead. You can't [invite them directly](/manage/team/add-users-to-your-network#direct-user-invites) now that they have their own account, so if they need to keep the personal address, contact [NetBird Support](/help/netbird-support). +- **Your domain was not classified as private.** NetBird only groups sign-ups by domain when it classifies the domain as private. If it is unsure, it plays safe and does not group them. [NetBird Support](/help/netbird-support) can correct the classification. See [Indirect user invites](/manage/team/add-users-to-your-network#indirect-user-invites). + +To fix it for the next person, an Owner or Admin adds and verifies the domain under **Settings → Authentication → Sign-in Domains**, or invites the user directly. Do this before onboarding a team on another domain, not after. + +The **Sign-in Domains** section only appears once your account's own domain is classified as private. If you don't see it, invite the user directly or contact [NetBird Support](/help/netbird-support). + +To confirm the cause, ask your teammate which email address they signed in with, and check its domain against the Sign-in Domains list. + +Verifying a domain does not move a teammate who already has an account of their own: it only changes where new sign-ins land. For a teammate already in a separate account, contact [NetBird Support](/help/netbird-support). + +If your account requires user approval, a teammate who joins through domain matching is held for approval. That is the [Waiting for Approval](#what-the-waiting-for-approval-screen-tells-you) screen above, and an admin approves them as described in [What to do](#what-to-do). + + +On self-hosted NetBird, domain matching and sign-in domains do not apply: by default, every user joins the same account. + + Still unsure who owns the account, or think you were added to the wrong one? Reach out through [NetBird Support](/help/netbird-support) and the team can help confirm the account and its owner. diff --git a/src/pages/help/troubleshooting.mdx b/src/pages/help/troubleshooting.mdx index 62a9a447..2e0ab167 100644 --- a/src/pages/help/troubleshooting.mdx +++ b/src/pages/help/troubleshooting.mdx @@ -2,43 +2,90 @@ import { TroubleshootingTiles } from "@/components/TroubleshootingTiles" import { StillStuck } from "@/components/StillStuck" export const description = - "Start here to troubleshoot NetBird. Find your issue by area and jump straight to the relevant guide." + "Start here to troubleshoot NetBird. See the common issues, or browse by area." # Troubleshooting -Something not working as expected? Pick the area closest to your problem and jump to the -guide and section that covers it. Each section links to troubleshooting docs that live -next to the feature they cover, so nothing here is a copy. +Something not working as expected? Check the common issues below, or browse by area. + +## Common issues + +The problems support sees most often. + +
+ +| Symptom | Start here | +|---|---| +| The dashboard shows **Waiting for Approval** after you sign in | [Pending approval and account invitations](/help/troubleshooting-account-access) | +| The client keeps asking you to log in again, or a peer shows `Login required` | [Peer session expiration](/manage/settings/enforce-periodic-user-authentication) | +| A peer shows `Relayed` instead of `P2P` | [Troubleshooting relayed connections](/help/troubleshooting-relayed-connections) | +| The tunnel works but is slow, or takes long to connect | [Troubleshooting performance](/help/troubleshooting-performance) | +| A service behind a routing peer is unreachable, or a new resource never shows up | [Troubleshooting resource connectivity](/help/troubleshooting-resource-connectivity) | +| A network or host firewall blocks NetBird, or traffic stops at a security product such as a SASE or SSL-inspection service | [Ports & firewalls](/about-netbird/ports-and-firewalls)
On the peer itself: [Symptoms of host-based firewall issues](/about-netbird/ports-and-firewalls#symptoms-of-host-based-firewall-issues) | +| Names do not resolve, or DNS stops working after NetBird disconnects | [DNS troubleshooting](/manage/dns/troubleshooting) | +| A NetBird Reverse Proxy service returns `502`, times out, or its certificate is never issued | [Reverse proxy troubleshooting](/manage/reverse-proxy/troubleshooting)
Certificate: [Certificate is not issued after verification](/manage/reverse-proxy/custom-domains#certificate-is-not-issued-after-verification) | + +
diff --git a/src/pages/selfhosted/troubleshooting.mdx b/src/pages/selfhosted/troubleshooting.mdx index 0cd1bc5f..9b999102 100644 --- a/src/pages/selfhosted/troubleshooting.mdx +++ b/src/pages/selfhosted/troubleshooting.mdx @@ -41,6 +41,7 @@ This page helps with issues when self-hosting NetBird. Collect the diagnostics b