> For the complete documentation index, see [llms.txt](https://docs.bosonnetwork.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bosonnetwork.io/core-concepts/services/active-proxy.md).

# Active Proxy

The **Active Proxy** is a Boson Layer-2 service that solves the NAT traversal problem: it gives any private or firewalled service a stable, publicly reachable TCP endpoint without port forwarding, a static IP, or a VPN.

The mechanism is a *reverse* tunnel. The client - running next to the service you want to expose (an HTTP server, an SSH daemon, a game server) - opens a single **outbound** encrypted connection to the super node, so no inbound firewall rules are needed on the client side. The super node allocates a public TCP port (and optionally a DNS name), accepts external connections on it, and relays their bytes back through the tunnel to the client, which bridges them to the local upstream service. To the outside world the service appears to be hosted at the super node's public address.

***

## Features

* **NAT traversal** - the client initiates all connections outbound; no inbound firewall rules or port forwarding are required on the client side.
* **Dynamic port allocation** - the super node assigns a public TCP port from a configurable range (`portMappingRange`) when the client authenticates, and returns the allocated endpoint over the control tunnel.
* **Encrypted tunnel** - the control channel and all proxied data are encrypted with [NaCl CryptoBox](https://nacl.cr.yp.to/box.html) (X25519 key exchange + XSalsa20-Poly1305); the transport is plain TCP, with encryption at the application layer.
* **DHT-based discovery** - the service announces itself as a peer using a `tcp://` endpoint so clients locate it via `FIND_PEER` with no hard-coded address.
* **Optional name access** - when the operator configures it and the user's plan includes it, a session is reachable by name, over HTTPS, instead of by address and port.
* **Multi-device and multi-connection** - a single user can attach from multiple devices, each with its own session, and each session supports a configurable pool of concurrent proxy connections.

***

## Architecture

```
  External User
       │  TCP connect to public endpoint (ip:port or DNS name)
       ▼
 ┌───────────────────────────────────┐
 │  Active Proxy Super Node          │  ← public IP
 │  Port mapping range: configurable │
 └───────────────────────────────────┘
       │  Encrypted TCP tunnel (NaCl CryptoBox)
       │  AUTH → ATTACH → PING/DATA/CONNECT
       ▼
 ┌──────────────────────────────────┐
 │  ActiveProxyClient (device)      │  ← any network, behind NAT
 └──────────────────────────────────┘
       │  plain TCP
       ▼
 ┌───────────────────┐
 │  Upstream service │  e.g. HTTP, SSH
 └───────────────────┘
```

***

## Configuration

The service type is `io.bosonnetwork.activeproxy`. As shipped:

```yaml
host: 0.0.0.0
port: 9090

peer:
  endpoint: tcp://node.example.com:9090

portMappingRange: "10000-10099, 32768-65535"

limits:
  user:
    connections: 8
    maxConnections: 64
    devices: 1
    maxDevices: 16
```

The control port does not use TLS; the protocol encrypts its own traffic. Keep `portMappingRange` clear of the system's ephemeral port range. See [Configuring Services](/configure-a-node/services-config.md#active-proxy) and the [Configuration Reference](/reference/configuration.md#active-proxy).

***

## Wire protocol

Active Proxy uses a binary packet protocol over plain TCP. After the authentication handshake, all bytes are encrypted with **NaCl CryptoBox** (X25519 key exchange + XSalsa20-Poly1305).

### Packet format

Each packet: `[type byte] [length: 2 bytes big-endian] [payload bytes]`

The type byte is chosen **randomly within the range** for each packet, obscuring traffic patterns from passive observers.

### Packet type ranges

| Packet type  | Byte range      | ACK byte range                    | Description                                       |
| ------------ | --------------- | --------------------------------- | ------------------------------------------------- |
| `AUTH`       | `0x00` - `0x07` | `AUTH_ACK`: `0x80` - `0x87`       | Client authentication credential                  |
| `ATTACH`     | `0x08` - `0x0F` | `ATTACH_ACK`: `0x88` - `0x8F`     | Register upstream service, claim connection slots |
| `PING`       | `0x10` - `0x1F` | `PING_ACK`: `0x90` - `0x9F`       | Keepalive                                         |
| `CONNECT`    | `0x20` - `0x2F` | `CONNECT_ACK`: `0xA0` - `0xAF`    | Notification of an incoming external connection   |
| `DISCONNECT` | `0x30` - `0x3F` | `DISCONNECT_ACK`: `0xB0` - `0xBF` | Connection teardown                               |
| `DATA`       | `0x40` - `0x6F` | -                                 | Proxied byte stream                               |
| `ERROR`      | `0x70` - `0x7F` | -                                 | Protocol error                                    |

ACK bytes set bit `0x80`. The lower 7 bits identify the base type using the same range as the corresponding request.

### Handshake sequence

1. **CHALLENGE**: server sends its ephemeral CryptoBox public key as the first raw bytes (no type byte).
2. **AUTH**: client sends its authentication credential (user ID, device ID, Ed25519 signatures) encrypted with the session key derived from the challenge.
3. **AUTH\_ACK**: server confirms authentication and sends the allocated public endpoint (`ip:port`, and optionally DNS name if `nameAccess` is enabled).
4. **ATTACH**: client registers its upstream service host/port and requests connection slots.
5. **ATTACH\_ACK**: server confirms the attachment.

After ATTACH\_ACK, the tunnel is live.

### Data relay

When an external TCP connection arrives at the super node's public port:

1. Server sends `CONNECT` to the client with a connection ID.
2. Client sends `CONNECT_ACK`, opens a new TCP connection to the local upstream service, and bridges the two streams.
3. Data flows as `DATA` packets in both directions until either side sends `DISCONNECT`.

### Keepalive

The client sends `PING` packets periodically. The server responds with `PING_ACK`. If the server does not receive a `PING` within the expected interval, it closes the tunnel.

***

## Port allocation

The service allocates public TCP ports from `portMappingRange`. Each authenticated client session gets one port. When the client disconnects or the session expires, the port is released.

For a small number of simultaneous clients, a narrow range (e.g. `10000-10099`) is sufficient. Large deployments should use a wider range or multiple ranges separated by commas.

***

## Name access

With name access, a session is reachable at `<device id>.<domain>` instead of the super node's address and a port. The operator configures a `nameAccess` block - `supernode`, which pairs with nginx and wildcard DNS, or `ddns`, which writes records to an authoritative name server - and a plan must include the `nameAccess` feature. The client asks for it, and needs an `http` upstream. See [Active Proxy Name Access](/configure-a-node/name-access.md).

***

## What to read next

* [Build Apps: Active Proxy Client](/build-applications/services/active-proxy-client.md)
* [Operate: Services Configuration](/configure-a-node/services-config.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bosonnetwork.io/core-concepts/services/active-proxy.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
