Merge branch 'main' into platforms-new-organization
4
.gitignore
vendored
@@ -27,3 +27,7 @@ package-lock.json
|
||||
/generator/openapi/
|
||||
/generator/openapi.yml
|
||||
/generator/expandOpenAPIRef
|
||||
|
||||
# LLM documentation (generated)
|
||||
/public/llms/
|
||||
/public/llms.txt
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"dev": "npm run gen:llm && next dev",
|
||||
"build": "npm run gen:llm && next build",
|
||||
"gen": "swagger-codegen generate -i https://raw.githubusercontent.com/netbirdio/netbird/main/management/server/http/api/openapi.yml -l openapi -o generator/openapi && npx ts-node generator/index.ts gen --input generator/openapi/openapi.json --output src/pages/ipa/resources",
|
||||
"gen:llm": "node scripts/generate-llm-docs.mjs",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
|
||||
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 197 KiB |
|
After Width: | Height: | Size: 267 KiB |
|
After Width: | Height: | Size: 272 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 258 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 552 KiB After Width: | Height: | Size: 552 KiB |
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 220 KiB |
|
Before Width: | Height: | Size: 376 KiB After Width: | Height: | Size: 376 KiB |
|
Before Width: | Height: | Size: 414 KiB After Width: | Height: | Size: 414 KiB |
|
Before Width: | Height: | Size: 538 KiB After Width: | Height: | Size: 538 KiB |
|
Before Width: | Height: | Size: 444 KiB After Width: | Height: | Size: 444 KiB |
|
Before Width: | Height: | Size: 568 KiB After Width: | Height: | Size: 568 KiB |
|
Before Width: | Height: | Size: 339 KiB After Width: | Height: | Size: 339 KiB |
|
Before Width: | Height: | Size: 552 KiB After Width: | Height: | Size: 552 KiB |
|
Before Width: | Height: | Size: 518 KiB After Width: | Height: | Size: 518 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 407 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 315 KiB After Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 670 KiB After Width: | Height: | Size: 670 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 464 KiB After Width: | Height: | Size: 464 KiB |
|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 158 KiB |
238
scripts/generate-llm-docs.mjs
Normal file
@@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* LLM Documentation Generator
|
||||
*
|
||||
* Generates clean markdown files from MDX pages for LLM indexing.
|
||||
* Creates:
|
||||
* - public/llms/*.md - Clean markdown versions of each page
|
||||
* - public/llms.txt - Index file linking to all pages
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT_DIR = path.join(__dirname, '..');
|
||||
const PAGES_DIR = path.join(ROOT_DIR, 'src/pages');
|
||||
const OUTPUT_DIR = path.join(ROOT_DIR, 'public/llms');
|
||||
const LLMS_TXT_PATH = path.join(ROOT_DIR, 'public/llms.txt');
|
||||
|
||||
// Base URL for the docs site
|
||||
const BASE_URL = 'https://docs.netbird.io';
|
||||
|
||||
/**
|
||||
* Strip JSX/React components from MDX content, keeping clean markdown
|
||||
*/
|
||||
function stripJsx(content) {
|
||||
let result = content;
|
||||
|
||||
// Remove import statements
|
||||
result = result.replace(/^import\s+.*?[;\n]/gm, '');
|
||||
|
||||
// Remove export statements (but keep the content if it's a description)
|
||||
result = result.replace(/^export\s+const\s+description\s*=\s*(['"`])(.+?)\1;?\s*$/gm, '');
|
||||
result = result.replace(/^export\s+.*?[;\n]/gm, '');
|
||||
|
||||
// Remove JSX self-closing tags like <Note />, <Button />, etc.
|
||||
result = result.replace(/<[A-Z][a-zA-Z]*\s*\/>/g, '');
|
||||
|
||||
// Remove JSX components with children like <Note>...</Note>
|
||||
// Handle multi-line JSX blocks
|
||||
result = result.replace(/<([A-Z][a-zA-Z]*)[^>]*>[\s\S]*?<\/\1>/g, (match, tagName) => {
|
||||
// For Note components, try to extract the text content
|
||||
if (tagName === 'Note' || tagName === 'Warning' || tagName === 'Info') {
|
||||
const innerContent = match.replace(/<[^>]+>/g, '').trim();
|
||||
if (innerContent) {
|
||||
return `> **Note:** ${innerContent}\n`;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
// Remove remaining JSX tags but keep inner text for simple cases
|
||||
result = result.replace(/<([a-z][a-zA-Z]*)[^>]*>([\s\S]*?)<\/\1>/g, '$2');
|
||||
|
||||
// Remove self-closing HTML/JSX tags with attributes
|
||||
result = result.replace(/<[a-zA-Z]+[^>]*\/>/g, '');
|
||||
|
||||
// Remove div tags with className (common in MDX)
|
||||
result = result.replace(/<div[^>]*className[^>]*>[\s\S]*?<\/div>/g, '');
|
||||
|
||||
// Remove iframe embeds (videos, etc.)
|
||||
result = result.replace(/<iframe[\s\S]*?<\/iframe>/g, '[Video content]');
|
||||
result = result.replace(/<iframe[^>]*\/>/g, '[Video content]');
|
||||
|
||||
// Remove Button components but note the link
|
||||
result = result.replace(/<Button[^>]*href="([^"]*)"[^>]*>([^<]*)<\/Button>/g, '[$2]($1)');
|
||||
result = result.replace(/<Button[^>]*children="([^"]*)"[^>]*href="([^"]*)"[^>]*\/>/g, '[$1]($2)');
|
||||
result = result.replace(/<Button[^>]*href="([^"]*)"[^>]*children="([^"]*)"[^>]*\/>/g, '[$2]($1)');
|
||||
|
||||
// Clean up excessive newlines
|
||||
result = result.replace(/\n{3,}/g, '\n\n');
|
||||
|
||||
// Clean up leading/trailing whitespace
|
||||
result = result.trim();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract title from MDX content
|
||||
*/
|
||||
function extractTitle(content) {
|
||||
// Try to find # heading
|
||||
const h1Match = content.match(/^#\s+(.+)$/m);
|
||||
if (h1Match) {
|
||||
return h1Match[1].trim();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all MDX files recursively
|
||||
*/
|
||||
function getMdxFiles(dir, baseDir = dir) {
|
||||
const files = [];
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
// Skip api/ipa directories if you want (they're auto-generated)
|
||||
files.push(...getMdxFiles(fullPath, baseDir));
|
||||
} else if (entry.name.endsWith('.mdx')) {
|
||||
const relativePath = path.relative(baseDir, fullPath);
|
||||
files.push({
|
||||
fullPath,
|
||||
relativePath,
|
||||
slug: relativePath.replace(/\.mdx$/, '').replace(/\/index$/, ''),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main generation function
|
||||
*/
|
||||
async function generate() {
|
||||
console.log('Generating LLM documentation...\n');
|
||||
|
||||
// Ensure output directory exists
|
||||
if (fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.rmSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
|
||||
// Get all MDX files
|
||||
const mdxFiles = getMdxFiles(PAGES_DIR);
|
||||
console.log(`Found ${mdxFiles.length} MDX files\n`);
|
||||
|
||||
const pages = [];
|
||||
|
||||
for (const file of mdxFiles) {
|
||||
const content = fs.readFileSync(file.fullPath, 'utf-8');
|
||||
const cleanContent = stripJsx(content);
|
||||
const title = extractTitle(cleanContent) || file.slug.split('/').pop();
|
||||
|
||||
// Create output path maintaining directory structure
|
||||
const outputPath = path.join(OUTPUT_DIR, `${file.slug}.md`);
|
||||
const outputDir = path.dirname(outputPath);
|
||||
|
||||
// Ensure directory exists
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
|
||||
// Add metadata header
|
||||
const finalContent = `# ${title}\n\nSource: ${BASE_URL}/${file.slug}\n\n---\n\n${cleanContent}`;
|
||||
|
||||
fs.writeFileSync(outputPath, finalContent);
|
||||
|
||||
pages.push({
|
||||
title,
|
||||
slug: file.slug,
|
||||
path: `/llms/${file.slug}.md`,
|
||||
});
|
||||
|
||||
console.log(` Generated: ${file.slug}.md`);
|
||||
}
|
||||
|
||||
// Generate llms.txt
|
||||
const llmsTxt = generateLlmsTxt(pages);
|
||||
fs.writeFileSync(LLMS_TXT_PATH, llmsTxt);
|
||||
console.log(`\nGenerated llms.txt with ${pages.length} pages`);
|
||||
|
||||
console.log('\nDone!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate llms.txt content
|
||||
*/
|
||||
function generateLlmsTxt(pages) {
|
||||
// Group pages by section
|
||||
const sections = {};
|
||||
for (const page of pages) {
|
||||
const parts = page.slug.split('/');
|
||||
const section = parts[0] || 'root';
|
||||
if (!sections[section]) {
|
||||
sections[section] = [];
|
||||
}
|
||||
sections[section].push(page);
|
||||
}
|
||||
|
||||
let content = `# NetBird Documentation
|
||||
|
||||
> NetBird is an open-source WireGuard-based mesh VPN platform that creates secure private networks.
|
||||
> This file provides an index of all documentation pages in markdown format for LLM consumption.
|
||||
|
||||
## About
|
||||
|
||||
- Website: https://netbird.io
|
||||
- Documentation: ${BASE_URL}
|
||||
- GitHub: https://github.com/netbirdio/netbird
|
||||
|
||||
## Documentation Index
|
||||
|
||||
Each link below points to a clean markdown version of the documentation page.
|
||||
|
||||
`;
|
||||
|
||||
// Section display names
|
||||
const sectionNames = {
|
||||
'introduction': 'Introduction',
|
||||
'about-netbird': 'About NetBird',
|
||||
'get-started': 'Getting Started',
|
||||
'manage': 'Managing NetBird',
|
||||
'selfhosted': 'Self-Hosting',
|
||||
'ipa': 'API Reference',
|
||||
'use-cases': 'Use Cases',
|
||||
'client': 'Client',
|
||||
'help': 'Help & Troubleshooting',
|
||||
};
|
||||
|
||||
for (const [section, sectionPages] of Object.entries(sections)) {
|
||||
const sectionTitle = sectionNames[section] || section.charAt(0).toUpperCase() + section.slice(1);
|
||||
content += `### ${sectionTitle}\n\n`;
|
||||
|
||||
for (const page of sectionPages) {
|
||||
content += `- [${page.title}](${BASE_URL}${page.path})\n`;
|
||||
}
|
||||
content += '\n';
|
||||
}
|
||||
|
||||
content += `---
|
||||
|
||||
## Usage
|
||||
|
||||
LLMs can fetch individual markdown files to get detailed information about specific topics.
|
||||
Each markdown file contains the clean documentation content with a link back to the original page.
|
||||
|
||||
Generated: ${new Date().toISOString()}
|
||||
`;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
// Run
|
||||
generate().catch(console.error);
|
||||
@@ -1,30 +1,28 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import clsx from 'clsx'
|
||||
import {
|
||||
ActivePageMarker,
|
||||
NavLink,
|
||||
TopLevelNavItem,
|
||||
VisibleSectionHighlight
|
||||
} from "@/components/NavigationAPI";
|
||||
import {AnimatePresence, motion} from "framer-motion";
|
||||
import {Button} from "@/components/mdx";
|
||||
import {useState} from "react";
|
||||
import {NavigationStateProvider, useNavigationState} from "@/components/NavigationState";
|
||||
import ChevronDownIcon from "@/components/icons/ChevronDownIcon";
|
||||
|
||||
ActivePageMarker,
|
||||
NavLink,
|
||||
TopLevelNavItem,
|
||||
VisibleSectionHighlight
|
||||
} from '@/components/NavigationAPI'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { Button } from '@/components/mdx'
|
||||
import { useState } from 'react'
|
||||
import { NavigationStateProvider, useNavigationState } from '@/components/NavigationState'
|
||||
import ChevronDownIcon from '@/components/icons/ChevronDownIcon'
|
||||
|
||||
export const docsNavigation = [
|
||||
{
|
||||
title: 'ABOUT',
|
||||
links: [
|
||||
{ title: 'How NetBird Works', href: '/about-netbird/how-netbird-works'},
|
||||
{ title: 'How NetBird Works', href: '/about-netbird/how-netbird-works' },
|
||||
{ title: 'NetBird vs. Traditional VPN', href: '/about-netbird/netbird-vs-traditional-vpn' },
|
||||
{ title: 'Why WireGuard with NetBird', href: '/about-netbird/why-wireguard-with-netbird' },
|
||||
{ title: 'Browser Client Architecture', href: '/about-netbird/browser-client-architecture' },
|
||||
{ title: 'FAQ', href: '/about-netbird/faq' },
|
||||
/*{ title: 'Whats new in version xx', href: '/welcome/how-netbird-works' },
|
||||
{ title: 'Release notes', href: '/about-netbird/netbird-vs-traditional-vpn' },*/
|
||||
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -58,350 +56,361 @@ export const docsNavigation = [
|
||||
links: [
|
||||
{ title: 'Control Center', href: '/manage/control-center' },
|
||||
{
|
||||
title: 'Peers',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Add Peers', href: '/manage/peers/add-machines-to-your-network' },
|
||||
{ title: 'Approve Peers', href: '/manage/peers/approve-peers' },
|
||||
{ title: 'Setup Keys', href: '/manage/peers/register-machines-using-setup-keys' },
|
||||
{ title: 'Browser Client', href: '/manage/peers/browser-client' },
|
||||
{ title: 'SSH', href: '/manage/peers/ssh' },
|
||||
{ title: 'Lazy Connections', href: '/manage/peers/lazy-connection'},
|
||||
{
|
||||
title: 'Access Infrastructure',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{
|
||||
title: 'Access Remote Webserver',
|
||||
href: '/manage/peers/access-infrastructure/secure-remote-webserver-access'
|
||||
},
|
||||
{
|
||||
title: 'Add Servers to the Network',
|
||||
href: '/manage/peers/access-infrastructure/setup-keys-add-servers-to-network'
|
||||
},
|
||||
{
|
||||
title: 'Access from Kubernetes',
|
||||
href: '/manage/peers/access-infrastructure/access-internal-resources-from-autoscaled-environments'
|
||||
},
|
||||
{
|
||||
title: 'Peer Approval for Remote Access',
|
||||
href: '/manage/peers/access-infrastructure/peer-approval-for-remote-worker-access'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Connect Site-to-Site',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{
|
||||
title: 'Simplify Workload Migrations',
|
||||
href: '/manage/peers/site-to-site/db-workload-migration'
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Access Control',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Groups & Policies', href: '/manage/access-control' },
|
||||
{ title: 'Manage Access', href: '/manage/access-control/manage-network-access' },
|
||||
{
|
||||
title: 'Posture Checks',
|
||||
href: '/manage/access-control/posture-checks',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Disable route when in the office', href: '/manage/access-control/posture-checks/connecting-from-the-office' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Integrate MDM & EDR',
|
||||
href: '/manage/access-control/endpoint-detection-and-response',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'CrowdStrike Falcon', href: '/manage/access-control/endpoint-detection-and-response/crowdstrike-edr' },
|
||||
{ title: 'Microsoft Intune', href: '/manage/access-control/endpoint-detection-and-response/intune-mdm' },
|
||||
{ title: 'SentinelOne Singularity', href: '/manage/access-control/endpoint-detection-and-response/sentinelone-edr' },
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Networks',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Concept', href: '/manage/networks' },
|
||||
{ title: 'Route Traffic to Multiple IP resources', href: '/manage/networks/routing-traffic-to-multiple-resources' },
|
||||
{ title: 'Access Restricted Website Domain Resources', href: '/manage/networks/accessing-restricted-domain-resources' },
|
||||
{ title: 'Access Entire Domains Within Networks', href: '/manage/networks/accessing-entire-domains-within-networks' },
|
||||
{
|
||||
title: 'Homelab',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{ title: 'Access Home Network', href: '/manage/networks/homelab/access-home-network' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Network Routes',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Route Traffic to Private Networks', href: '/manage/network-routes/routing-traffic-to-private-networks' },
|
||||
{ title: 'Configure Default Routes for Internet Traffic', href: '/manage/network-routes/configuring-default-routes-for-internet-traffic' },
|
||||
{ title: 'Configure Routes with Access control', href: '/manage/network-routes/configuring-routes-with-access-control' },
|
||||
{ title: 'Resolve Overlapping Routes', href: '/manage/network-routes/resolve-overlapping-routes' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'DNS',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Manage DNS in Your Network', href: '/manage/dns' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Team',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Add Users to Your Network', href: '/manage/team/add-users-to-your-network' },
|
||||
{ title: 'Approve Users', href: '/manage/team/approve-users' },
|
||||
{
|
||||
title: 'Provision Users & Groups',
|
||||
href: '/manage/team/idp-sync',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Microsoft Entra ID (API)', href: '/manage/team/idp-sync/microsoft-entra-id-sync' },
|
||||
{ title: 'Microsoft Entra ID (SCIM)', href: '/manage/team/idp-sync/microsoft-entra-id-scim-sync' },
|
||||
{ title: 'Okta', href: '/manage/team/idp-sync/okta-sync' },
|
||||
{ title: 'Google Workspace', href: '/manage/team/idp-sync/google-workspace-sync'},
|
||||
{ title: 'JumpCloud', href: '/manage/team/idp-sync/jumpcloud-sync'},
|
||||
{ title: 'Keycloak', href: '/manage/team/idp-sync/keycloak-sync'},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Auto-Offboard Users',
|
||||
href: '/manage/team/auto-offboard-users',
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
title: 'Single Sign-On',
|
||||
href: '/manage/team/single-sign-on',
|
||||
isOpen: false,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Activity',
|
||||
links: [
|
||||
{ title: 'Audit Events Logging', href: '/manage/activity' },
|
||||
{ title: 'Traffic Events Logging', href: '/manage/activity/traffic-events-logging' },
|
||||
{
|
||||
title: 'Stream Activity Events',
|
||||
href: '/manage/activity/event-streaming',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Datadog', href: '/manage/activity/event-streaming/datadog' },
|
||||
{ title: 'Amazon S3', href: '/manage/activity/event-streaming/amazon-s3' },
|
||||
{ title: 'Amazon Firehose', href: '/manage/activity/event-streaming/amazon-firehose'},
|
||||
{ title: 'SentinelOne Data Lake', href: '/manage/activity/event-streaming/sentinelone-data-lake'},
|
||||
{ title: 'Generic HTTP', href: '/manage/activity/event-streaming/generic-http'},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{title: 'Authentication', href: '/manage/settings/enforce-periodic-user-authentication' },
|
||||
{title: 'Multi-Factor Authentication', href: '/manage/settings/multi-factor-authentication' },
|
||||
{title: 'Delete Account', href: '/manage/settings/delete-account' },
|
||||
{title: 'Plans and Billing', href: '/manage/settings/plans-and-billing' }
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Integrations',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{title: 'Enable Post Quantum Cryptography', href: '/manage/integrations/enable-post-quantum-cryptography' },
|
||||
{
|
||||
title: 'MDM for Deployment',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{title: 'Deploy with Jamf Pro', href: '/manage/integrations/mdm-deployment/jamf-pro-netbird-integration' },
|
||||
{title: 'Deploy with Kandji', href: '/manage/integrations/mdm-deployment/kandji-netbird-integration' },
|
||||
{title: 'Deploy with Intune', href: '/manage/integrations/mdm-deployment/intune-netbird-integration' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Kubernetes',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{title: 'Operator', href: '/manage/integrations/kubernetes' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
title: 'Peers',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Add Peers', href: '/manage/peers/add-machines-to-your-network' },
|
||||
{ title: 'Approve Peers', href: '/manage/peers/approve-peers' },
|
||||
{ title: 'Setup Keys', href: '/manage/peers/register-machines-using-setup-keys' },
|
||||
{ title: 'Browser Client', href: '/manage/peers/browser-client' },
|
||||
{ title: 'SSH', href: '/manage/peers/ssh' },
|
||||
{ title: 'Lazy Connections', href: '/manage/peers/lazy-connection' },
|
||||
{
|
||||
title: 'Access Infrastructure',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{
|
||||
title: 'Access Remote Webserver',
|
||||
href: '/manage/peers/access-infrastructure/secure-remote-webserver-access'
|
||||
},
|
||||
{
|
||||
title: 'Add Servers to the Network',
|
||||
href: '/manage/peers/access-infrastructure/setup-keys-add-servers-to-network'
|
||||
},
|
||||
{
|
||||
title: 'Access from Kubernetes',
|
||||
href: '/manage/peers/access-infrastructure/access-internal-resources-from-autoscaled-environments'
|
||||
},
|
||||
{
|
||||
title: 'Peer Approval for Remote Access',
|
||||
href: '/manage/peers/access-infrastructure/peer-approval-for-remote-worker-access'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Connect Site-to-Site',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{
|
||||
title: 'Simplify Workload Migrations',
|
||||
href: '/manage/peers/site-to-site/db-workload-migration'
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Access Control',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Groups & Policies', href: '/manage/access-control' },
|
||||
{ title: 'Manage Access', href: '/manage/access-control/manage-network-access' },
|
||||
{
|
||||
title: 'Posture Checks',
|
||||
href: '/manage/access-control/posture-checks',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Disable route when in the office', href: '/manage/access-control/posture-checks/connecting-from-the-office' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Integrate MDM & EDR',
|
||||
href: '/manage/access-control/endpoint-detection-and-response',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'CrowdStrike Falcon', href: '/manage/access-control/endpoint-detection-and-response/crowdstrike-edr' },
|
||||
{ title: 'Microsoft Intune', href: '/manage/access-control/endpoint-detection-and-response/intune-mdm' },
|
||||
{ title: 'SentinelOne Singularity', href: '/manage/access-control/endpoint-detection-and-response/sentinelone-edr' },
|
||||
{ title: 'Huntress', href: '/manage/access-control/endpoint-detection-and-response/huntress-edr' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Networks',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Concept', href: '/manage/networks' },
|
||||
{ title: 'Route Traffic to Multiple IP resources', href: '/manage/networks/routing-traffic-to-multiple-resources' },
|
||||
{ title: 'Access Restricted Website Domain Resources', href: '/manage/networks/accessing-restricted-domain-resources' },
|
||||
{ title: 'Access Entire Domains Within Networks', href: '/manage/networks/accessing-entire-domains-within-networks' },
|
||||
{
|
||||
title: 'Homelab',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{ title: 'Access Home Network', href: '/manage/networks/homelab/access-home-network' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Network Routes',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Route Traffic to Private Networks', href: '/manage/network-routes/routing-traffic-to-private-networks' },
|
||||
{ title: 'Configure Default Routes for Internet Traffic', href: '/manage/network-routes/configuring-default-routes-for-internet-traffic' },
|
||||
{ title: 'Configure Routes with Access control', href: '/manage/network-routes/configuring-routes-with-access-control' },
|
||||
{ title: 'Resolve Overlapping Routes', href: '/manage/network-routes/resolve-overlapping-routes' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'DNS',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Manage DNS in Your Network', href: '/manage/dns' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Team',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Add Users to Your Network', href: '/manage/team/add-users-to-your-network' },
|
||||
{ title: 'Approve Users', href: '/manage/team/approve-users' },
|
||||
{
|
||||
title: 'Provision Users & Groups',
|
||||
href: '/manage/team/idp-sync',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Microsoft Entra ID (API)', href: '/manage/team/idp-sync/microsoft-entra-id-sync' },
|
||||
{ title: 'Microsoft Entra ID (SCIM)', href: '/manage/team/idp-sync/microsoft-entra-id-scim-sync' },
|
||||
{ title: 'Okta', href: '/manage/team/idp-sync/okta-sync' },
|
||||
{ title: 'Google Workspace', href: '/manage/team/idp-sync/google-workspace-sync' },
|
||||
{ title: 'JumpCloud', href: '/manage/team/idp-sync/jumpcloud-sync' },
|
||||
{ title: 'Keycloak', href: '/manage/team/idp-sync/keycloak-sync' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Auto-Offboard Users',
|
||||
href: '/manage/team/auto-offboard-users',
|
||||
isOpen: false,
|
||||
},
|
||||
{
|
||||
title: 'Single Sign-On',
|
||||
href: '/manage/team/single-sign-on',
|
||||
isOpen: false,
|
||||
// links: [
|
||||
// { title: 'Authentik', href: '/manage/team/single-sign-on/authentik' },
|
||||
// { title: 'Keycloak', href: '/manage/team/single-sign-on/keycloak' },
|
||||
// { title: 'Auth0', href: '/manage/team/single-sign-on/auth0' },
|
||||
// { title: 'JumpCloud', href: '/manage/team/single-sign-on/jumpcloud' },
|
||||
// ]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Activity',
|
||||
links: [
|
||||
{ title: 'Audit Events Logging', href: '/manage/activity' },
|
||||
{ title: 'Traffic Events Logging', href: '/manage/activity/traffic-events-logging' },
|
||||
{
|
||||
title: 'Stream Activity Events',
|
||||
href: '/manage/activity/event-streaming',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Datadog', href: '/manage/activity/event-streaming/datadog' },
|
||||
{ title: 'Amazon S3', href: '/manage/activity/event-streaming/amazon-s3' },
|
||||
{ title: 'Amazon Firehose', href: '/manage/activity/event-streaming/amazon-firehose' },
|
||||
{ title: 'SentinelOne Data Lake', href: '/manage/activity/event-streaming/sentinelone-data-lake' },
|
||||
{ title: 'Generic HTTP', href: '/manage/activity/event-streaming/generic-http' },
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Authentication', href: '/manage/settings/enforce-periodic-user-authentication' },
|
||||
{ title: 'Multi-Factor Authentication', href: '/manage/settings/multi-factor-authentication' },
|
||||
{ title: 'Delete Account', href: '/manage/settings/delete-account' },
|
||||
{ title: 'Plans and Billing', href: '/manage/settings/plans-and-billing' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Integrations',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Enable Post Quantum Cryptography', href: '/manage/integrations/enable-post-quantum-cryptography' },
|
||||
{
|
||||
title: 'MDM for Deployment',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{ title: 'Deploy with Jamf Pro', href: '/manage/integrations/mdm-deployment/jamf-pro-netbird-integration' },
|
||||
{ title: 'Deploy with Kandji', href: '/manage/integrations/mdm-deployment/kandji-netbird-integration' },
|
||||
{ title: 'Deploy with Intune', href: '/manage/integrations/mdm-deployment/intune-netbird-integration' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Kubernetes',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{ title: 'Operator', href: '/manage/integrations/kubernetes' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Public API',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Access Public API', href: '/manage/public-api' },
|
||||
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'For Partners',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Managed Service Providers', href: '/manage/for-partners/msp-portal' },
|
||||
{ title: 'Acronis NetBird integration', href: '/manage/for-partners/acronis-integration' },
|
||||
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
title: 'CLIENT',
|
||||
links: [
|
||||
{ title: 'Profiles', href: '/client/profiles' },
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
title: 'USE CASES',
|
||||
links: [
|
||||
{ title: 'Site-to-Site and Site-to-VPN', href: '/use-cases/setup-site-to-site-access' },
|
||||
{ title: 'Serverless and NetBird', href: '/use-cases/netbird-on-faas' },
|
||||
{ title: 'Routing peers and Kubernetes', href: '/use-cases/routing-peers-and-kubernetes'},
|
||||
{ title: 'NetBird Client on AWS ECS', href: '/use-cases/examples'},
|
||||
{ title: 'NetBird on Mikrotik Router', href: '/use-cases/client-on-mikrotik-router' },
|
||||
{ title: 'Distributed AI on Kubernetes', href: '/use-cases/distributed-multi-cloud-ai-argocd-microk8s-vllm' },
|
||||
{ title: 'Self-hosted vs. Cloud-hosted NetBird', href: '/selfhosted/self-hosted-vs-cloud-netbird' },
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
title: 'SELF-HOST NETBIRD',
|
||||
links: [
|
||||
{ title: 'Quickstart guide', href: '/selfhosted/selfhosted-quickstart' },
|
||||
{ title: 'Advanced guide', href: '/selfhosted/selfhosted-guide' },
|
||||
{ title: 'Management SQLite Store', href: '/selfhosted/sqlite-store'},
|
||||
{ title: 'Management Postgres Store', href: '/selfhosted/postgres-store'},
|
||||
{ title: 'Activity Events Postgres Store', href: '/selfhosted/activity-postgres-store'},
|
||||
{ title: 'Supported IdPs', href: '/selfhosted/identity-providers' },
|
||||
{ title: 'Management geolocation', href: '/selfhosted/geo-support' },
|
||||
{ title: 'Troubleshooting', href: '/selfhosted/troubleshooting' },
|
||||
],
|
||||
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
title: 'GET MORE HELP',
|
||||
links: [
|
||||
{ title: 'Troubleshooting client issues', href: '/help/troubleshooting-client' },
|
||||
{ title: 'Report bugs and issues', href: '/help/report-bug-issues' },
|
||||
|
||||
],
|
||||
|
||||
|
||||
title: 'CLIENT',
|
||||
links: [
|
||||
{ title: 'Profiles', href: '/client/profiles' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'USE CASES',
|
||||
links: [
|
||||
{ title: 'Site-to-Site and Site-to-VPN', href: '/use-cases/setup-site-to-site-access' },
|
||||
{ title: 'Serverless and NetBird', href: '/use-cases/netbird-on-faas' },
|
||||
{ title: 'Routing peers and Kubernetes', href: '/use-cases/routing-peers-and-kubernetes' },
|
||||
{ title: 'NetBird Client on AWS ECS', href: '/use-cases/examples' },
|
||||
{ title: 'NetBird on Mikrotik Router', href: '/use-cases/client-on-mikrotik-router' },
|
||||
{ title: 'Distributed AI on Kubernetes', href: '/use-cases/distributed-multi-cloud-ai-argocd-microk8s-vllm' },
|
||||
{ title: 'Self-hosted vs. Cloud-hosted NetBird', href: '/selfhosted/self-hosted-vs-cloud-netbird' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'SELF-HOST NETBIRD',
|
||||
links: [
|
||||
{ title: 'Quickstart guide', href: '/selfhosted/selfhosted-quickstart' },
|
||||
{ title: 'Advanced guide', href: '/selfhosted/selfhosted-guide' },
|
||||
{ title: 'Management SQLite Store', href: '/selfhosted/sqlite-store' },
|
||||
{ title: 'Management Postgres Store', href: '/selfhosted/postgres-store' },
|
||||
{ title: 'Activity Events Postgres Store', href: '/selfhosted/activity-postgres-store' },
|
||||
{
|
||||
title: 'Supported IdPs',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Using IdPs on Self-Hosted', href: '/selfhosted/identity-providers' },
|
||||
{
|
||||
title: 'Self-hosted IdPs',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{ title: 'Zitadel', href: '/selfhosted/identity-providers/zitadel' },
|
||||
{ title: 'Authentik', href: '/selfhosted/identity-providers/authentik' },
|
||||
{ title: 'Keycloak', href: '/selfhosted/identity-providers/keycloak' },
|
||||
{ title: 'PocketID', href: '/selfhosted/identity-providers/pocketid' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Managed IdPs',
|
||||
isOpen: true,
|
||||
links: [
|
||||
{ title: 'Entra ID', href: '/selfhosted/identity-providers/managed/microsoft-entra-id' },
|
||||
{ title: 'Okta', href: '/selfhosted/identity-providers/managed/okta' },
|
||||
{ title: 'Google Workspace', href: '/selfhosted/identity-providers/managed/google-workspace' },
|
||||
{ title: 'JumpCloud', href: '/selfhosted/identity-providers/managed/jumpcloud' },
|
||||
{ title: 'Keycloak', href: '/selfhosted/identity-providers/managed/keycloak' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{ title: 'Management geolocation', href: '/selfhosted/geo-support' },
|
||||
{ title: 'Troubleshooting', href: '/selfhosted/troubleshooting' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'GET MORE HELP',
|
||||
links: [
|
||||
{ title: 'Troubleshooting client issues', href: '/help/troubleshooting-client' },
|
||||
{ title: 'Report bugs and issues', href: '/help/report-bug-issues' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
]
|
||||
export function NavigationDocs({ className }) {
|
||||
return (
|
||||
<nav className={className}>
|
||||
<ul role="list">
|
||||
<TopLevelNavItem href="https://netbird.io/">Home</TopLevelNavItem>
|
||||
<TopLevelNavItem href="/">Docs</TopLevelNavItem>
|
||||
<TopLevelNavItem href="/api">API</TopLevelNavItem>
|
||||
<TopLevelNavItem href="https://netbird.io/knowledge-hub/">Learn</TopLevelNavItem>
|
||||
<TopLevelNavItem href="https://github.com/netbirdio/netbird">Github</TopLevelNavItem>
|
||||
<TopLevelNavItem href="/slack-url">Support</TopLevelNavItem>
|
||||
{docsNavigation.map((group, groupIndex) => (
|
||||
<NavigationStateProvider key={group.title} index={groupIndex}>
|
||||
<NavigationGroup
|
||||
group={group}
|
||||
index={groupIndex}
|
||||
className={groupIndex === 0 && 'md:mt-0'}
|
||||
/>
|
||||
</NavigationStateProvider>
|
||||
))}
|
||||
<li className="sticky bottom-0 z-10 mt-6 min-[416px]:hidden">
|
||||
<Button href="https://app.netbird.io/" variant="filled" className="w-full">
|
||||
Sign in
|
||||
</Button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export function NavigationDocs({className}) {
|
||||
return (
|
||||
<nav className={className}>
|
||||
<ul role="list">
|
||||
<TopLevelNavItem href="https://netbird.io/">Home</TopLevelNavItem>
|
||||
<TopLevelNavItem href="/">Docs</TopLevelNavItem>
|
||||
<TopLevelNavItem href="/api">API</TopLevelNavItem>
|
||||
<TopLevelNavItem href="https://netbird.io/knowledge-hub/">Learn</TopLevelNavItem>
|
||||
<TopLevelNavItem href="https://github.com/netbirdio/netbird">Github</TopLevelNavItem>
|
||||
<TopLevelNavItem href="/slack-url">Support</TopLevelNavItem>
|
||||
{docsNavigation.map((group, groupIndex) => (
|
||||
<NavigationStateProvider key={group.title} index={groupIndex}>
|
||||
<NavigationGroup
|
||||
group={group}
|
||||
index={groupIndex}
|
||||
className={groupIndex === 0 && 'md:mt-0'}
|
||||
/>
|
||||
</NavigationStateProvider>
|
||||
))}
|
||||
<li className="sticky bottom-0 z-10 mt-6 min-[416px]:hidden">
|
||||
<Button href="https://app.netbird.io/" variant="filled" className="w-full">
|
||||
Sign in
|
||||
</Button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const findActiveGroupIndex = (group, pathname) => {
|
||||
let activeIndex = -1;
|
||||
const findActiveGroupIndex = (group, pathname) => {
|
||||
let activeIndex = -1
|
||||
group.links.forEach((link, index) => {
|
||||
if (link.href === pathname) {
|
||||
activeIndex = index;
|
||||
activeIndex = index
|
||||
} else if (link.links) {
|
||||
const childIndex = findActiveGroupIndex(link, pathname);
|
||||
const childIndex = findActiveGroupIndex(link, pathname)
|
||||
if (childIndex !== -1) {
|
||||
activeIndex = index;
|
||||
activeIndex = index
|
||||
}
|
||||
}
|
||||
});
|
||||
return activeIndex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function NavigationGroup({ group, className, hasChildren }) {
|
||||
})
|
||||
return activeIndex
|
||||
}
|
||||
|
||||
function NavigationGroup({ group, className, hasChildren }) {
|
||||
let router = useRouter()
|
||||
let isActiveGroup = findActiveGroupIndex(group, router.pathname) !== -1;
|
||||
const [isOpen, setIsOpen] = useState(group.isOpen ? group.isOpen :!hasChildren);
|
||||
const [, setActiveHighlight] = useNavigationState();
|
||||
|
||||
let isActiveGroup = findActiveGroupIndex(group, router.pathname) !== -1
|
||||
const [isOpen, setIsOpen] = useState(group.isOpen ? group.isOpen : !hasChildren)
|
||||
const [, setActiveHighlight] = useNavigationState()
|
||||
|
||||
return (
|
||||
<li className={clsx('relative', className, hasChildren ? "" : "mt-6")}>
|
||||
<li className={clsx('relative', className, hasChildren ? '' : 'mt-6')}>
|
||||
<motion.h2
|
||||
// layout={"size"}
|
||||
className={clsx(
|
||||
"flex justify-between items-center gap-2 group",
|
||||
hasChildren ? "text-zinc-700 select-none py-1 pr-3 hover:text-zinc-900 dark:text-zinc-300 font-medium dark:hover:text-white text-sm cursor-pointer" : "text-xs font-semibold text-zinc-900 dark:text-white"
|
||||
)}
|
||||
'flex justify-between items-center gap-2 group',
|
||||
hasChildren ? 'text-zinc-700 select-none py-1 pr-3 hover:text-zinc-900 dark:text-zinc-300 font-medium dark:hover:text-white text-sm cursor-pointer' : 'text-xs font-semibold text-zinc-900 dark:text-white'
|
||||
)}
|
||||
onClick={() => {
|
||||
setIsOpen(!isOpen)
|
||||
if(!isOpen) {
|
||||
if(!isActiveGroup) router.push(group.links[0].href)
|
||||
if (!isOpen) {
|
||||
if (!isActiveGroup) router.push(group.links[0].href)
|
||||
setActiveHighlight()
|
||||
}else {
|
||||
} else {
|
||||
setActiveHighlight(group.title)
|
||||
}
|
||||
}}
|
||||
data-nb-link={group.title}
|
||||
data-nb-active={hasChildren && isActiveGroup ? "1" : "0"}
|
||||
data-nb-active={hasChildren && isActiveGroup ? '1' : '0'}
|
||||
>
|
||||
{group.title}
|
||||
{hasChildren && <ChevronDownIcon className={clsx("fill-zinc-700 group-hover:fill-zinc-900 dark:fill-zinc-300 dark:group-hover:fill-white","transition", isOpen ? "transform rotate-180" : "")} size={10} />}
|
||||
{hasChildren && <ChevronDownIcon className={clsx('fill-zinc-700 group-hover:fill-zinc-900 dark:fill-zinc-300 dark:group-hover:fill-white', 'transition', isOpen ? 'transform rotate-180' : '')} size={10} />}
|
||||
</motion.h2>
|
||||
<div className={clsx("relative", hasChildren ? "" : "mt-3 pl-2")}>
|
||||
<div className={clsx('relative', hasChildren ? '' : 'mt-3 pl-2')}>
|
||||
{!hasChildren &&
|
||||
<>
|
||||
<AnimatePresence >
|
||||
<AnimatePresence>
|
||||
{isActiveGroup && (
|
||||
<VisibleSectionHighlight group={group} pathname={router.pathname} />
|
||||
)}
|
||||
@@ -412,14 +421,13 @@ export const docsNavigation = [
|
||||
/>
|
||||
<AnimatePresence initial={false}>
|
||||
{isActiveGroup && (
|
||||
<ActivePageMarker group={group} pathname={router.pathname}/>
|
||||
<ActivePageMarker group={group} pathname={router.pathname} />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
<AnimatePresence mode={"wait"} initial={false}>
|
||||
|
||||
<AnimatePresence mode={'wait'} initial={false}>
|
||||
{isOpen && <motion.ul
|
||||
role="list"
|
||||
initial={{ opacity: 0 }}
|
||||
@@ -432,21 +440,19 @@ export const docsNavigation = [
|
||||
transition: { duration: 0.15 },
|
||||
}}
|
||||
className="border-l border-transparent">
|
||||
{group.links.map((link) => {
|
||||
return link.href ?
|
||||
<motion.li key={link.href} className="relative">
|
||||
<NavLink href={link.href} active={link.href === router.pathname} links={link.links}>
|
||||
{link.title}
|
||||
</NavLink>
|
||||
</motion.li>
|
||||
:
|
||||
<NavigationGroup className={"ml-4"} key={link.title + isOpen} group={link} hasChildren={true} />
|
||||
})}
|
||||
{group.links.map((link) => {
|
||||
return link.href ?
|
||||
<motion.li key={link.href} className="relative">
|
||||
<NavLink href={link.href} active={link.href === router.pathname} links={link.links}>
|
||||
{link.title}
|
||||
</NavLink>
|
||||
</motion.li>
|
||||
:
|
||||
<NavigationGroup className={'ml-4'} key={link.title + isOpen} group={link} hasChildren={true} />
|
||||
})}
|
||||
</motion.ul>}
|
||||
|
||||
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
}
|
||||
98
src/pages/how-to/huntress-edr.mdx
Normal file
@@ -0,0 +1,98 @@
|
||||
# Restrict Network Access with Huntress EDR
|
||||
|
||||
[Huntress](https://www.huntress.com/) is a managed detection and response (MDR) platform designed for IT service providers and enterprises to protect endpoints from cyber threats. The Huntress agent continuously monitors endpoints, collecting security telemetry including Windows Defender status, firewall configuration, and policy compliance, which can be used to enforce network access controls based on device security posture.
|
||||
|
||||
The integration of NetBird with Huntress provides network security by ensuring only devices that meet your defined security standards can access the protected network. This approach allows administrators to enforce access restrictions based on critical Windows security settings such as Defender health status, antivirus definitions, firewall state, and policy compliance, ensuring only properly secured endpoints have access to network resources via NetBird.
|
||||
|
||||
In this guide, you'll learn how to integrate NetBird with Huntress and configure access controls to allow only compliant devices onto your network.
|
||||
|
||||
<Note>
|
||||
TLDR: Devices that fail to meet Huntress security requirements (Windows Defender health, firewall status, or policy compliance) will automatically lose network access. Once a device meets all compliance criteria, access is restored.
|
||||
</Note>
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start creating and configuring a Huntress integration, ensure that you have the following:
|
||||
- A Huntress account with the permissions to create and manage API keys.
|
||||
If you don't have the required permissions, ask your Huntress administrator to grant them to you.
|
||||
|
||||
## Create a Huntress API Key
|
||||
|
||||
- Navigate to your Huntress Management Console
|
||||
- Go to **Settings** » **API Credentials**
|
||||
- Click **Create API Credential**
|
||||
- Fill in the form:
|
||||
- **Name**: `NetBird Integration`
|
||||
- **Description**: `API key for NetBird EDR integration` (optional)
|
||||
- Click **Create**
|
||||
- Copy the generated API key and secret immediately (they will only be displayed once)
|
||||
- Note your Huntress organization key from the console
|
||||
|
||||
<Note>
|
||||
Treat the API credentials securely and store them safely. You will need both the API key and secret for the NetBird integration configuration.
|
||||
</Note>
|
||||
|
||||
## Configure a Huntress Integration in NetBird
|
||||
|
||||
- Navigate to the [Integrations » EDR](https://app.netbird.io/integrations?tab=edr) tab in the NetBird dashboard
|
||||
- Click **Connect Huntress** to start the configuration wizard
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/getting-started.png" alt="Huntress integration getting started" className="imagewrapper-big"/>
|
||||
</p>
|
||||
- Click the **Get Started** button to initiate the integration process
|
||||
- Enter your Huntress organization key and click **Continue**
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/console-config.png" alt="Huntress console configuration" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
- Enter the API key and secret you created in the previous step and click **Continue** to verify the connection
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/api-config.png" alt="Huntress API configuration" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
- Select the **groups** you want to apply the integration to and click **Connect**
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/group-config.png" alt="Huntress group configuration" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
|
||||
<Note>
|
||||
The EDR check will apply only to peers in the selected groups and will require a running Huntress agent.
|
||||
You can also use groups [synchronized from your Identity Provider (IdP)](/how-to/idp-sync).
|
||||
</Note>
|
||||
|
||||
- Configure the compliance criteria that devices must meet to access your network. These security requirements ensure only healthy, properly configured devices can connect. Select the criteria that align with your organization's security policies:
|
||||
- **Defender Policy Status**: Requires Windows Defender policy status to be compliant. Default is set to `Compliant`.
|
||||
- **Defender Status**: Requires Windows Defender to be in a healthy state. Default is set to `Healthy`.
|
||||
- **Defender Substatus**: Requires Windows Defender to be up to date with the latest definitions. Default is set to `Up to date`.
|
||||
- **Firewall Status**: Requires the device firewall to be enabled. Can be set to check if firewall is `Enabled` or `Disabled`. Default is to require `Enabled`.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/compliance-config.png" alt="edr-integrations" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
|
||||
- Configure the **Huntress Sync Window** (default is 24 hours). This setting determines which devices NetBird will consider for network access based on their recent activity in Huntress. Only devices that have been active and reporting to Huntress within this time window will be synchronized. These devices must then also meet the configured compliance criteria to gain network access.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/sync-config.png" alt="edr-integrations" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
- Click **Connect** to complete the integration setup
|
||||
|
||||
- Only peers that have the Huntress agent installed and meet all the configured compliance criteria will be granted access to the network.
|
||||
Peers without the Huntress agent or those that don't meet the compliance requirements will appear with an `Approval required` mark in the peers list and won't be able to access
|
||||
the network until they have the agent installed and satisfy all the specified security requirements.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/how-to-guides/endpoint-detection-and-response/huntress/edr-approval-required.png" alt="edr-approval-required" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
|
||||
<Note>
|
||||
NetBird matches the Huntress agent to the peer using the Serial Number of the device. You must ensure that each of your devices has a unique serial number.
|
||||
</Note>
|
||||