From cb03de89ee5327404e2248c2af0da494b3e911cd Mon Sep 17 00:00:00 2001 From: jnfrati Date: Tue, 7 Jul 2026 11:23:54 +0200 Subject: [PATCH] docs: add documentation for admin cli --- src/components/NavigationDocs.jsx | 4 + .../identity-providers/enable-local-mfa.mdx | 4 + .../selfhosted/identity-providers/local.mdx | 4 + .../selfhosted/maintenance/admin-cli.mdx | 213 ++++++++++++++++++ .../scaling/multiple-proxy-instances.mdx | 40 ++-- .../migration/enable-reverse-proxy.mdx | 34 +-- 6 files changed, 265 insertions(+), 34 deletions(-) create mode 100644 src/pages/selfhosted/maintenance/admin-cli.mdx diff --git a/src/components/NavigationDocs.jsx b/src/components/NavigationDocs.jsx index e08444aa1..f6d5f007a 100644 --- a/src/components/NavigationDocs.jsx +++ b/src/components/NavigationDocs.jsx @@ -553,6 +553,10 @@ export const docsNavigation = [ title: 'Environment Variables', href: '/selfhosted/environment-variables', }, + { + title: 'Admin CLI', + href: '/selfhosted/maintenance/admin-cli', + }, { title: 'Scaling Your Deployment', href: '/selfhosted/maintenance/scaling/scaling-your-self-hosted-deployment', diff --git a/src/pages/selfhosted/identity-providers/enable-local-mfa.mdx b/src/pages/selfhosted/identity-providers/enable-local-mfa.mdx index 30161a04a..1abf175a8 100644 --- a/src/pages/selfhosted/identity-providers/enable-local-mfa.mdx +++ b/src/pages/selfhosted/identity-providers/enable-local-mfa.mdx @@ -27,6 +27,10 @@ MFA enforcement applies only to local users authenticated through the embedded I Once enabled, all local users will be prompted to set up TOTP on their next login. + +Server administrators can also manage local MFA from the command line with `admin mfa status`, `admin mfa enable`, and `admin mfa disable`. See the [self-hosted admin CLI](/selfhosted/maintenance/admin-cli#manage-local-mfa) reference. + + ## User experience ### First login after MFA is enabled diff --git a/src/pages/selfhosted/identity-providers/local.mdx b/src/pages/selfhosted/identity-providers/local.mdx index b24e950cc..e05d16e6e 100644 --- a/src/pages/selfhosted/identity-providers/local.mdx +++ b/src/pages/selfhosted/identity-providers/local.mdx @@ -233,6 +233,10 @@ This feature is available when: Users authenticated through SSO/OIDC providers will not see this option. + +If a local user cannot sign in, a server administrator can reset the password from the server with `admin user change-password`. See the [self-hosted admin CLI](/selfhosted/maintenance/admin-cli#change-a-local-users-password) reference. + + How to Use: 1. Click your avatar in the top-right corner of the dashboard diff --git a/src/pages/selfhosted/maintenance/admin-cli.mdx b/src/pages/selfhosted/maintenance/admin-cli.mdx new file mode 100644 index 000000000..cf8e68778 --- /dev/null +++ b/src/pages/selfhosted/maintenance/admin-cli.mdx @@ -0,0 +1,213 @@ +import {Note, Warning} from "@/components/mdx"; + +export const description = + "Use the NetBird self-hosted admin CLI to manage local users, local MFA, proxy access tokens, and reverse proxy state."; + +# Self-hosted admin CLI + +The self-hosted admin CLI provides maintenance commands that run directly against the NetBird Management data store and, for local user operations, the embedded IdP store. Use it when you need to repair or administer a self-hosted control plane from the server rather than through the Dashboard or public API. + +You can use the admin CLI to: + +- Change passwords for local embedded IdP users +- Reset a local user's MFA enrollment +- Enable, disable, or check local MFA +- Create, list, and revoke reverse proxy access tokens +- Force-mark reverse proxy instances as disconnected after an unclean shutdown + + +Back up your NetBird configuration and data stores before running commands that change state. Run the command from the same NetBird version as the server. After an upgrade, start the server once before using the admin CLI so database migrations and embedded IdP clients are initialized. + + +## Prerequisites + +- Access to the host or container that runs the Management service +- The Management configuration file path +- For local user and MFA commands, a self-hosted deployment using the [embedded IdP](/selfhosted/identity-providers/local) +- For local MFA commands, a single-account embedded IdP deployment + + +The admin CLI is for self-hosted deployments. It does not manage users in external identity providers such as Google Workspace, Microsoft Entra ID, Okta, or Keycloak. + + +## Choose the command prefix + +Use the prefix that matches your deployment type, then append one of the admin subcommands shown below. + +### Combined container + +New installations created with `getting-started.sh` use the combined `netbird-server` container and `config.yaml`. + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin +``` + +If you run the binary directly on the host, use the host path to `config.yaml` instead: + +```bash +netbird-server --config ./config.yaml admin +``` + +### Older multi-container setup + +Older deployments use a separate `netbird-mgmt` binary and `management.json`. + +```bash +docker exec -it netbird-management \ + /go/bin/netbird-mgmt admin --config /etc/netbird/management.json +``` + +If your SQLite `store.db` or default `idp.db` is in a non-default data directory, add `--datadir`: + +```bash +docker exec -it netbird-management \ + /go/bin/netbird-mgmt admin --config /etc/netbird/management.json --datadir /var/lib/netbird +``` + +## Change a local user's password + +Use `admin user change-password` with either `--email` or `--user-id`. + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin user change-password \ + --email user@example.com \ + --password-file /run/secrets/new-netbird-password +``` + +To avoid storing the password in shell history, read it from standard input: + +```bash +printf '%s\n' 'NewPass1!' | docker exec -i netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin user change-password \ + --email user@example.com \ + --password-file - +``` + +The new password must be at least eight characters and include at least one digit, one uppercase letter, and one special character. + + +The command also removes the user's active local authentication session, so the user must sign in again with the new password. + + +## Reset a local user's MFA enrollment + +Use `admin user reset-mfa` when a local user loses access to their authenticator app or needs to enroll again. + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin user reset-mfa \ + --email user@example.com +``` + +You can also select the user by ID: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin user reset-mfa \ + --user-id +``` + +The command clears the user's stored TOTP and WebAuthn enrollment for the local connector and removes the active local authentication session. If local MFA remains enabled, the user is prompted to enroll again at the next login. + +## Manage local MFA + +Local MFA applies to all users who authenticate with the embedded IdP local username/password connector. It does not affect users who sign in through external IdPs. + +Check the current state: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin mfa status +``` + +Enable local MFA: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin mfa enable +``` + +Disable local MFA: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin mfa disable +``` + + +Disabling local MFA removes the login requirement but does not delete users' stored MFA enrollments. If you enable MFA again, previously enrolled users are asked for the same authenticator unless you reset their enrollment with `admin user reset-mfa`. + + +## Manage proxy access tokens + +Reverse proxy instances authenticate to Management with proxy access tokens. The plain token is shown only once when created. + +Create a token: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token create \ + --name "proxy-server-1" \ + --expires-in 365d +``` + +`--expires-in` accepts Go duration values such as `24h` or `1h30m`, plus day values such as `30d` or `365d`. Leave it empty for no expiration. + +List tokens: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token list +``` + +Revoke a token by ID: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token revoke +``` + + +Older `netbird-server token ...` and `netbird-mgmt token ...` commands are deprecated. Use `admin token ...` for new automation. + + +## Repair reverse proxy connection state + +Use `admin proxy disconnect-all` to force-mark every registered reverse proxy instance as disconnected. This is useful after an unclean Management server shutdown when stale proxy sessions remain stored as connected. + +Preview the change first: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin proxy disconnect-all --dry-run +``` + +Apply the repair with an interactive confirmation prompt: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin proxy disconnect-all +``` + +For non-interactive maintenance automation, use `--force`: + +```bash +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin proxy disconnect-all --force +``` + + +Run this command during a maintenance window. It changes stored reverse proxy state for every non-disconnected proxy instance. Live proxies may stay hidden until their next heartbeat or reconnect. + + +## Troubleshooting + +| Error or warning | What to do | +|------------------|------------| +| `admin commands require the embedded IdP to be enabled` | Local user and MFA commands only work with the embedded IdP. Manage external IdP users in that provider. | +| `no local users exist in the embedded IdP storage` | Check that the server has started at least once and that `--config` or `--datadir` points to the correct data directory. | +| `embedded IdP client not found` | Start the Management server once with this configuration, then run the command again. | +| `expected exactly one account` | The local MFA CLI supports only single-account embedded IdP deployments. | +| `Warning: audit events will not be recorded` | The command can still run, but the activity event store could not be opened. Check the data store encryption key and activity store configuration. | diff --git a/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx b/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx index 7ebbec475..924626d51 100644 --- a/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx +++ b/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx @@ -93,36 +93,40 @@ Generate a token for each instance. The command differs depending on whether you **Combined container** (`netbirdio/netbird-server`): ```bash -docker exec -it netbird-server /go/bin/netbird-server token create \ - --name "proxy-server-1" --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token create \ + --name "proxy-server-1" -docker exec -it netbird-server /go/bin/netbird-server token create \ - --name "proxy-server-2" --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token create \ + --name "proxy-server-2" ``` **Multi-container** (separate `netbirdio/management` image): ```bash -docker exec -it netbird-management /go/bin/netbird-mgmt token create --name "proxy-server-1" -docker exec -it netbird-management /go/bin/netbird-mgmt token create --name "proxy-server-2" +docker exec -it netbird-management \ + /go/bin/netbird-mgmt admin token create --name "proxy-server-1" +docker exec -it netbird-management \ + /go/bin/netbird-mgmt admin token create --name "proxy-server-2" ``` Use a descriptive `--name` for each token so you can identify which instance it belongs to when listing or revoking tokens: ```bash # List all tokens (combined container) -docker exec -it netbird-server /go/bin/netbird-server token list \ - --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token list # List all tokens (multi-container) -docker exec -it netbird-management /go/bin/netbird-mgmt token list +docker exec -it netbird-management /go/bin/netbird-mgmt admin token list # Revoke a specific instance's token (combined container) -docker exec -it netbird-server /go/bin/netbird-server token revoke \ - --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token revoke # Revoke a specific instance's token (multi-container) -docker exec -it netbird-management /go/bin/netbird-mgmt token revoke +docker exec -it netbird-management /go/bin/netbird-mgmt admin token revoke ``` @@ -321,14 +325,14 @@ To gracefully remove a proxy instance from the cluster: docker compose down # Revoke its token on the management server (combined container) -docker exec -it netbird-server /go/bin/netbird-server token list \ - --config /config.yaml -docker exec -it netbird-server /go/bin/netbird-server token revoke \ - --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token list +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token revoke # Revoke its token on the management server (multi-container) -docker exec -it netbird-management /go/bin/netbird-mgmt token list -docker exec -it netbird-management /go/bin/netbird-mgmt token revoke +docker exec -it netbird-management /go/bin/netbird-mgmt admin token list +docker exec -it netbird-management /go/bin/netbird-mgmt admin token revoke ``` After stopping the instance, update your DNS records to remove the server's IP address so clients are no longer directed to it. diff --git a/src/pages/selfhosted/migration/enable-reverse-proxy.mdx b/src/pages/selfhosted/migration/enable-reverse-proxy.mdx index d812417c6..61781360c 100644 --- a/src/pages/selfhosted/migration/enable-reverse-proxy.mdx +++ b/src/pages/selfhosted/migration/enable-reverse-proxy.mdx @@ -70,14 +70,16 @@ The proxy authenticates with the management server using an access token. Genera **Combined container** (`netbirdio/netbird-server`): ```bash -docker exec -it netbird-server /go/bin/netbird-server token create \ - --name "my-proxy" --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token create \ + --name "my-proxy" ``` **Multi-container** (separate `netbirdio/management` image): ```bash -docker exec -it netbird-management /go/bin/netbird-mgmt token create --name "my-proxy" +docker exec -it netbird-management \ + /go/bin/netbird-mgmt admin token create --name "my-proxy" ``` This outputs a token in the format `nbx_...` (40 characters). **Save the token immediately** - it is only displayed once. The management server stores only a SHA-256 hash. @@ -86,18 +88,18 @@ You can manage tokens later with: ```bash # List all tokens (combined container) -docker exec -it netbird-server /go/bin/netbird-server token list \ - --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token list # List all tokens (multi-container) -docker exec -it netbird-management /go/bin/netbird-mgmt token list +docker exec -it netbird-management /go/bin/netbird-mgmt admin token list # Revoke a token by ID (combined container) -docker exec -it netbird-server /go/bin/netbird-server token revoke \ - --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token revoke # Revoke a token by ID (multi-container) -docker exec -it netbird-management /go/bin/netbird-mgmt token revoke +docker exec -it netbird-management /go/bin/netbird-mgmt admin token revoke ``` ### Step 3: Add the proxy service to docker-compose.yml @@ -578,7 +580,7 @@ The proxy is configured entirely through environment variables (each one maps to | Variable | Required | Description | Default | |----------|----------|-------------|---------| -| `NB_PROXY_TOKEN` | Yes | Access token generated via `netbird-server token create` (combined) or `netbird-mgmt token create` (multi-container). The proxy refuses to start without it. | - | +| `NB_PROXY_TOKEN` | Yes | Access token generated via `netbird-server admin token create` (combined) or `netbird-mgmt admin token create` (multi-container). The proxy refuses to start without it. | - | | `NB_PROXY_DOMAIN` | Yes | Base domain for this proxy instance (e.g., `proxy.example.com` or `netbird.example.com`). Determines the domain available for services. | - | | `NB_PROXY_MANAGEMENT_ADDRESS` | No | URL of your NetBird management server. The proxy connects via gRPC to register itself. | `https://api.netbird.io:443` | | `NB_PROXY_ADDRESS` | No | Address the proxy listens on. | `:8443` (Docker), `:443` (binary) | @@ -709,14 +711,14 @@ You can also revoke the proxy token to prevent the proxy from reconnecting: ```bash # Combined container -docker exec -it netbird-server /go/bin/netbird-server token list \ - --config /config.yaml -docker exec -it netbird-server /go/bin/netbird-server token revoke \ - --config /config.yaml +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token list +docker exec -it netbird-server \ + /go/bin/netbird-server --config /etc/netbird/config.yaml admin token revoke # Multi-container -docker exec -it netbird-management /go/bin/netbird-mgmt token list -docker exec -it netbird-management /go/bin/netbird-mgmt token revoke +docker exec -it netbird-management /go/bin/netbird-mgmt admin token list +docker exec -it netbird-management /go/bin/netbird-mgmt admin token revoke ``` ## Additional resources