> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensorlake.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Networking

> Route internet traffic into sandbox applications and control outbound internet access

Sandboxes support two networking features:

1. Routing internet traffic into services running inside a sandbox through `*.sandbox.tensorlake.ai`
2. Restricting the sandbox's own outbound internet access

## Sandbox Public URL

Every running sandbox is reachable through the sandbox proxy domain.

* `https://<sandbox-id-or-name>.sandbox.tensorlake.ai` routes to the sandbox management API on port `9501`
* `https://<port>-<sandbox-id-or-name>.sandbox.tensorlake.ai` routes to a user service listening on `<port>` inside the sandbox

The proxy preserves the request path and query string, supports WebSocket upgrades, and forwards gRPC over HTTP/2.

The hostname can use either the sandbox ID or a sandbox name. The proxy resolves names to the sandbox's canonical ID before forwarding the request.

If you fetch sandbox details over the HTTP API, the returned `sandbox_url` is the management URL on port `9501`.

## Route Traffic Into Sandbox Apps

There are two access modes for internet-facing sandbox traffic:

1. `Authenticated requests`: the caller sends TensorLake auth credentials, and the proxy authorizes the request before forwarding it.
2. `Unauthenticated requests`: the sandbox owner explicitly makes selected user ports public, and the proxy skips auth for those user ports.

### Expose a User Port

Port `9501` is the built-in management API and is always routable through the bare sandbox hostname.

For any other port, the proxy only forwards requests if that port is listed in `exposed_ports`.

<Note>
  `allow_unauthenticated_access` does not expose a port by itself. User ports still have to be present in `exposed_ports`.
</Note>

#### Authenticated-Only Exposure with the HTTP API

Use this when a port should be routable from the internet but still require TensorLake auth on every request.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import Sandbox


    sandbox = client.expose_ports(
        "my-env",
        [8080],
        allow_unauthenticated_access=False,
    )

    print(sandbox.exposed_ports)

    sandbox = client.unexpose_ports("my-env", [8080])
    print(sandbox.exposed_ports)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sandbox = await client.exposePorts(
      "my-env",
      [8080],
      { allowUnauthenticatedAccess: false },
    );

    console.log(sandbox.exposedPorts);

    const updated = await client.unexposePorts("my-env", [8080]);
    console.log(updated.exposedPorts);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X PATCH https://api.tensorlake.ai/sandboxes/<sandbox-id-or-name> \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "allow_unauthenticated_access": false,
        "exposed_ports": [8080]
      }'

    curl -X PATCH https://api.tensorlake.ai/sandboxes/<sandbox-id-or-name> \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "allow_unauthenticated_access": false,
        "exposed_ports": []
      }'
    ```
  </Tab>
</Tabs>

#### Unauthenticated Public Internet Access with the CLI

Use this when you want anyone on the internet to be able to reach a sandbox app without TensorLake credentials. Common cases include webhook receivers, demo apps, public APIs, browser clients, and temporary preview environments.

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    tl sbx port expose <sandbox-id-or-name> 8080
    tl sbx port ls <sandbox-id-or-name>
    tl sbx port rm <sandbox-id-or-name> 8080
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import Sandbox


    sandbox = client.expose_ports(
        "my-public-sandbox",
        [8080],
        allow_unauthenticated_access=True,
    )

    print(sandbox.allow_unauthenticated_access, sandbox.exposed_ports)

    sandbox = client.unexpose_ports("my-public-sandbox", [8080])
    print(sandbox.allow_unauthenticated_access, sandbox.exposed_ports)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sandbox = await client.exposePorts(
      "my-public-sandbox",
      [8080],
      { allowUnauthenticatedAccess: true },
    );

    console.log(sandbox.allowUnauthenticatedAccess, sandbox.exposedPorts);

    const updated = await client.unexposePorts("my-public-sandbox", [8080]);
    console.log(updated.allowUnauthenticatedAccess, updated.exposedPorts);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X PATCH https://api.tensorlake.ai/sandboxes/<sandbox-id-or-name> \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "allow_unauthenticated_access": true,
        "exposed_ports": [8080]
      }'

    curl -X PATCH https://api.tensorlake.ai/sandboxes/<sandbox-id-or-name> \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "allow_unauthenticated_access": false,
        "exposed_ports": []
      }'
    ```
  </Tab>
</Tabs>

The CLI `port expose` workflow sets both:

* `exposed_ports`
* `allow_unauthenticated_access=true`

So traffic to that user port becomes publicly reachable from the internet without TensorLake auth.

### Authenticated Requests

Authenticated routing is the default model for sandbox access.

* The management URL on port `9501` always requires auth
* User ports can also require auth when they are exposed but `allow_unauthenticated_access=false`

Verified against `sandbox-proxy`, the proxy accepts these auth modes:

* API key: `Authorization: Bearer <api-key>`
* Personal access token: `Authorization: Bearer tl_pat...` plus `X-Forwarded-Organization-Id` and `X-Forwarded-Project-Id`
* Session cookie: `tl.session_token` or legacy `tl-session`, plus the same forwarded organization/project context

For browser WebSocket clients that cannot set custom `X-Forwarded-*` headers, the proxy also accepts `organizationId` and `projectId` in the query string.

<Tabs>
  <Tab title="API Key">
    ```bash theme={null}
    curl https://8080-<sandbox-id-or-name>.sandbox.tensorlake.ai/health \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY"
    ```
  </Tab>

  <Tab title="PAT">
    ```bash theme={null}
    curl https://8080-<sandbox-id-or-name>.sandbox.tensorlake.ai/health \
      -H "Authorization: Bearer $TENSORLAKE_PAT" \
      -H "X-Forwarded-Organization-Id: $TENSORLAKE_ORGANIZATION_ID" \
      -H "X-Forwarded-Project-Id: $TENSORLAKE_PROJECT_ID"
    ```
  </Tab>

  <Tab title="Cookie">
    ```bash theme={null}
    curl https://8080-<sandbox-id-or-name>.sandbox.tensorlake.ai/health \
      -H "Cookie: tl.session_token=$TENSORLAKE_SESSION_TOKEN" \
      -H "X-Forwarded-Organization-Id: $TENSORLAKE_ORGANIZATION_ID" \
      -H "X-Forwarded-Project-Id: $TENSORLAKE_PROJECT_ID"
    ```
  </Tab>
</Tabs>

You can use the same authenticated routing model for HTTP, gRPC, and WebSocket services:

```bash theme={null}
# HTTP
curl https://8080-<sandbox-id-or-name>.sandbox.tensorlake.ai/health \
  -H "Authorization: Bearer $TENSORLAKE_API_KEY"

# gRPC
grpcurl \
  -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
  50051-<sandbox-id-or-name>.sandbox.tensorlake.ai:443 \
  list

# WebSocket
wscat \
  -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
  -c "wss://3000-<sandbox-id-or-name>.sandbox.tensorlake.ai/socket"
```

```typescript theme={null}
const response = await fetch(
  "https://8080-my-env.sandbox.tensorlake.ai/health",
  {
    headers: {
      Authorization: `Bearer ${process.env.TENSORLAKE_API_KEY}`,
    },
  },
);

console.log(await response.text());
```

### Unauthenticated Requests

To make a user port public on the internet, both of these conditions must be true:

* the port is in `exposed_ports`
* `allow_unauthenticated_access=true`

When those are set, the proxy skips TensorLake auth for that user port.

```bash theme={null}
curl -X PATCH https://api.tensorlake.ai/sandboxes/<sandbox-id-or-name> \
  -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "allow_unauthenticated_access": true,
    "exposed_ports": [8080]
  }'
```

After that, requests to the exposed user port can omit auth entirely:

```bash theme={null}
curl https://8080-<sandbox-id-or-name>.sandbox.tensorlake.ai/health
```

```typescript theme={null}
const response = await fetch(
  "https://8080-my-public-sandbox.sandbox.tensorlake.ai/health",
);

console.log(await response.text());
```

<Note>
  Unauthenticated access only applies to user ports. The management API on port `9501` never becomes public.
</Note>

<Note>
  If a named sandbox is suspended, the proxy can auto-resume it when a request arrives for an exposed port.
</Note>

## Outbound Internet Access

By default, sandboxes have outbound internet access enabled. Disable it for untrusted code:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import Sandbox


    sandbox = Sandbox.create(
        allow_internet_access=False
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sandbox = await Sandbox.create({
      allowInternetAccess: false,
    });

    console.log(sandbox.sandboxId);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X POST https://api.tensorlake.ai/sandboxes \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "network": {"allow_internet_access": false}
      }'
    ```
  </Tab>

  <Tab title="CLI">
    Not supported in the CLI.
  </Tab>
</Tabs>

In a verified public-cloud test, a sandbox created with `allow_internet_access=False` failed DNS resolution for `https://example.com`, confirming that outbound internet access was disabled.

## Allow Specific Destinations

Use `allow_out` when you want a sandbox to reach only selected destinations.

* `allow_out` rules are evaluated before `deny_out`
* when `allow_internet_access=false`, `allow_out` acts as an explicit outbound allowlist
* values should be destination IPs or CIDR ranges

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create(
        allow_internet_access=False,
        allow_out=["10.0.0.0/8", "8.8.8.8"],
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sandbox = await Sandbox.create({
      allowInternetAccess: false,
      allowOut: ["10.0.0.0/8", "8.8.8.8"],
    });

    console.log(sandbox.sandboxId);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X POST https://api.tensorlake.ai/sandboxes \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "network": {
          "allow_internet_access": false,
          "allow_out": ["10.0.0.0/8", "8.8.8.8"]
        }
      }'
    ```
  </Tab>

  <Tab title="CLI">
    Not supported in the CLI.
  </Tab>
</Tabs>

## Block Specific Destinations

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create(
        deny_out=["example.com"]
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sandbox = await Sandbox.create({
      denyOut: ["example.com"],
    });

    console.log(sandbox.sandboxId);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X POST https://api.tensorlake.ai/sandboxes \
      -H "Authorization: Bearer $TENSORLAKE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "network": {"deny_out": ["example.com"]}
      }'
    ```
  </Tab>

  <Tab title="CLI">
    Not supported in the CLI.
  </Tab>
</Tabs>

In a verified public-cloud request, `deny_out=["example.com"]` blocked `https://example.com` while `https://api.openai.com/v1/models` still returned `401`, confirming outbound connectivity was still available for destinations that were not denied.

## Network Configuration Summary

| Parameter                      | Type                | Default | Description                                                               |
| ------------------------------ | ------------------- | ------- | ------------------------------------------------------------------------- |
| `allow_internet_access`        | `bool`              | `true`  | Enable or disable all outbound internet access                            |
| `allow_out`                    | `list[str]`         | `[]`    | Explicitly allowed outbound destinations. Evaluated before `deny_out`     |
| `deny_out`                     | `list[str]`         | `[]`    | Denied outbound destinations                                              |
| `exposed_ports`                | `list[int] \| null` | `null`  | User ports that the sandbox proxy is allowed to route to                  |
| `allow_unauthenticated_access` | `bool`              | `false` | Skip TensorLake auth for exposed user ports. Never applies to port `9501` |
