diff --git a/src/components/NavigationDocs.jsx b/src/components/NavigationDocs.jsx
index 5a70bc3e..1b87ec11 100644
--- a/src/components/NavigationDocs.jsx
+++ b/src/components/NavigationDocs.jsx
@@ -904,6 +904,7 @@ export const docsNavigation = [
title: 'CLIENT',
links: [
{ title: 'Desktop App', href: '/client/desktop-app' },
+ { title: 'nblink', href: '/client/nblink' },
{ title: 'Profiles', href: '/client/profiles' },
{ title: 'gRPC Daemon Socket', href: '/client/grpc-socket' },
{ title: 'HTTP/JSON Daemon Socket', href: '/client/json-socket' },
diff --git a/src/pages/client/nblink.mdx b/src/pages/client/nblink.mdx
new file mode 100644
index 00000000..00e85764
--- /dev/null
+++ b/src/pages/client/nblink.mdx
@@ -0,0 +1,247 @@
+import { Note, Warning } from '@/components/mdx'
+
+export const description =
+ 'Forward local ports into your NetBird network from an unprivileged process, without installing the agent or granting root.'
+
+# nblink
+
+`nblink` forwards local ports into your NetBird network from an ordinary,
+unprivileged process. It runs the client in userspace mode, so there is no TUN
+device to create and no root to grant.
+
+That makes it useful where the regular agent cannot run:
+
+- Managed laptops where you cannot install software that needs administrator rights.
+- Rootless containers, including OpenShift and Podman.
+- Short-lived environments such as CI jobs, where installing an agent is not worth it.
+
+Names on the upstream side of a forward are resolved inside the tunnel, so
+`/etc/resolv.conf` is never modified.
+
+
+ `nblink` forwards HTTP. Support for raw TCP, UDP and SOCKS5 is planned, and
+ the way a forward is written will not change when they arrive.
+
+
+## Use cases
+
+### An MCP server or local AI agent reaching an internal API
+
+AI agents increasingly run in containers or restricted sandboxes where
+installing a client is not an option, and the consumer is code rather than a
+person, so opening a browser is not a substitute.
+
+```shell
+nblink --forward 'http://3000=https://tickets.internal' --state-dir ~/.nblink
+```
+
+Point the MCP server at `http://localhost:3000`. The agent carries a real peer
+identity, so what it can reach is decided by your policies rather than by
+whatever the agent was told to do.
+
+### Agent Network access without installing a client
+
+An [Agent Network](/agent-network) endpoint only answers when you are connected
+to your network and authenticated through your IdP, which normally means
+installing the client and therefore having root.
+
+```shell
+nblink --forward 'http://8080=https://mirror.netbird.ai'
+```
+
+Set the agent's base URL to `http://localhost:8080`. It still gets identity,
+spending limits and the models you approved, and no API key is handed to the
+agent itself.
+
+### A sidecar for an app you cannot modify
+
+A vendor or legacy application hardcodes an HTTP endpoint and ignores proxy
+settings, so pointing it somewhere else is not possible. Running `nblink`
+beside it gives it `localhost:8080` without touching the application, on
+platforms that forbid privileged containers and assign an arbitrary UID at run
+time.
+
+## Install
+
+Download the archive for your platform from the
+[releases page](https://github.com/netbirdio/netbird/releases), extract it, and
+run the binary. There is no installer and no service to register.
+
+```shell
+tar -xzf nblink__linux_amd64.tar.gz
+./nblink --help
+```
+
+## Forward a port
+
+A forward is a single argument, and the flag repeats:
+
+```shell
+nblink --forward 'http://8080=https://grafana.internal'
+```
+
+The scheme on the left selects the listener type. The right side is the
+upstream reached over your network. Giving only a port binds loopback, so the
+command above listens on `127.0.0.1:8080`.
+
+With no setup key, `nblink` opens your browser to log in. It always prints the
+login URL as well, so the same command works over SSH.
+
+Forward several services from one session and one login:
+
+```shell
+nblink --forward 'http://8080=https://grafana.internal' \
+ --forward 'http://9090=https://prometheus.internal'
+```
+
+Use `0` as the port to let the operating system pick a free one. The address
+actually bound is printed when the forward starts.
+
+Check a configuration without connecting to anything:
+
+```shell
+nblink --forward 'http://8080=https://grafana.internal' --check
+```
+
+## Run without a browser
+
+Pass a [setup key](/manage/peers/register-machines-using-setup-keys) to log in
+without any interaction:
+
+```shell
+nblink --forward 'http://8080=https://grafana.internal' --setup-key "$NB_SETUP_KEY"
+```
+
+## Run in a container
+
+Every flag has a matching `NB_`-prefixed environment variable, which is how the
+image is configured. `NB_FORWARD` accepts a comma separated list.
+
+```shell
+docker run --rm -p 127.0.0.1:8080:8080 \
+ --mount type=bind,src="$(pwd)/nb_setup_key",dst=/run/secrets/nb_setup_key,readonly \
+ -e NB_SETUP_KEY=file:/run/secrets/nb_setup_key \
+ -e NB_FORWARD='http://0.0.0.0:8080=https://grafana.internal' \
+ -e NB_ALLOW_PUBLIC_BIND=true \
+ netbirdio/nblink
+```
+
+The image needs no `--privileged`, no `--cap-add NET_ADMIN`, no
+`--device /dev/net/tun` and no host networking. It runs as a non-root user and
+works on platforms that assign an arbitrary UID at run time.
+
+Inside a container the listener has to bind `0.0.0.0`, because a published
+port arrives on the container's own interface rather than its loopback. That
+still requires `NB_ALLOW_PUBLIC_BIND`, so exposing a forward is always
+something you wrote down.
+
+
+ Publish the port on the host's loopback, as above. A bare `-p 8080:8080`
+ publishes it on every host interface, and anything that can reach the host
+ can then use the forward under the peer's identity. Publish on another
+ address only when the network around the host restricts who can reach it.
+
+
+A forward on a public address accepts requests addressed to `localhost` or to
+an IP address. A name that other machines use to reach it, such as a DNS name
+or a Kubernetes Service name, has to be listed with `--allowed-host`
+(`NB_ALLOWED_HOST`); an unlisted name is answered with `421`. See
+[Access control](#access-control) for what listing a name trusts.
+
+
+ The key file must exist before the run and be readable by the container user,
+ UID 65532 in group 0. A bind mount keeps the host file's owner and mode, so a
+ root-owned key written with the usual `chmod 600` is not readable and startup
+ fails with `permission denied`. Either give the file to that UID
+ (`chown 65532`) or keep it mode `640` in group 0 (`chgrp 0`). If the source
+ path does not exist, `--mount` refuses to start the container; the older `-v`
+ form creates a directory there instead.
+
+
+The image keeps its state in memory, so it runs on a read-only root filesystem
+and each start registers a new peer. To keep one identity across restarts, set
+`NB_STATE_DIR` and mount a writable volume there:
+
+```shell
+docker run --rm --read-only -p 127.0.0.1:8080:8080 \
+ -v nblink-state:/var/lib/nblink -e NB_STATE_DIR=/var/lib/nblink \
+ ...
+```
+
+Without a state directory, use an ephemeral setup key so the peers left behind
+by earlier starts are removed once they go offline.
+
+A kept identity is not yet a kept login. Without a setup key every start runs
+the browser flow, even when the peer's session is still valid. Give a restart
+that has to be unattended a setup key.
+
+
+ A value given as `file:/path` is read from that file. Prefer it for setup
+ keys in containers, so the secret is not visible to anything that can read
+ the process environment.
+
+
+## Configuration
+
+| Flag | Environment variable | Default | Description |
+| --- | --- | --- | --- |
+| `--forward` | `NB_FORWARD` | | Forward spec, repeatable. Comma separated in the environment. |
+| `--setup-key` | `NB_SETUP_KEY` | | Log in without a browser. Accepts a `file:` prefix. |
+| `--management-url` | `NB_MANAGEMENT_URL` | NetBird cloud | Management server URL. |
+| `--hostname` | `NB_HOSTNAME` | host name | Peer name in your network. |
+| `--state-dir` | `NB_STATE_DIR` | memory | Directory for identity and state. |
+| `--log-level` | `NB_LOG_LEVEL` | `info` | Log level. |
+| `--allow-public-bind` | `NB_ALLOW_PUBLIC_BIND` | `false` | Required to bind an address other than loopback. |
+| `--allowed-host` | `NB_ALLOWED_HOST` | | Name a request may arrive under, beyond loopback names and addresses. Repeatable. Comma separated in the environment. |
+| `--no-browser` | `NB_NO_BROWSER` | `false` | Print the login URL instead of opening a browser. |
+| `--check` | `NB_CHECK` | `false` | Validate the configuration, print the forwards and exit. |
+
+## Access control
+
+A peer created by `nblink` is a peer like any other. It appears in your peer
+list and reaches only what your
+[access control policies](/manage/access-control) allow.
+
+`nblink` only dials out. It refuses inbound connections and does not reach the
+network of the machine it runs on, so the peer cannot be used as a way into
+that machine.
+
+A loopback forward answers only requests whose `Host` names the loopback
+interface or a name listed with `--allowed-host`, and refuses any request a
+browser marks as belonging to another page, through either a cross-origin
+`Origin` or a cross-site `Sec-Fetch-Site`.
+A web page you visit can point its own hostname at `127.0.0.1` or embed the
+address directly, and without those checks your browser could reach the
+upstream through the listener under your identity. Ordinary callers send
+neither header and are unaffected.
+
+A browser too old to send `Sec-Fetch-Site`, which browsers have sent since
+2020, can still reach a loopback forward with an embedded no-cors GET.
+
+A forward on a public address applies the same checks and also accepts any IP
+address in `Host`, since a page cannot rebind an address it does not control.
+
+A name listed with `--allowed-host` is trusted rather than merely permitted,
+and the list applies to every forward in the process, loopback ones included.
+`Host` is the one signal a rebound page cannot forge, and listing a name gives
+that up for it: a page served on that name can resolve it to the listener and
+send a matching `Host` and `Origin`. List only names you control, and prefer a
+fully qualified one, since a single-label name can be answered by anything on
+the local network.
+
+
+ Forwards bind `127.0.0.1` unless you pass `--allow-public-bind`. A forward on
+ a public address lets anything that can reach the port use your network, so
+ enable it only when the surrounding environment restricts access.
+
+
+## Limits
+
+Userspace mode carries TCP, UDP and ping only. An `nblink` peer cannot:
+
+- act as a [routing peer](/manage/networks/how-routing-peers-work) or an exit node,
+- take over system DNS for the machine,
+- bind privileged ports below 1024.
+
+If you need any of those, install the
+[NetBird client](/get-started/install) instead.