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

# Tailscale Subnet Router Quick Start

> Reach an Edge Compute function from a Tailscale network through a Network, the user's virtual routing and forwarding (VRF) domain in Telnyx.

## Prerequisites

* Admin access to the tailnet, to edit its policy file, generate an auth key, and approve routes.
* A function project and the `telnyx-edge` CLI, as in the [Edge Compute Quick Start](/docs/edge-compute/quickstart).
* A region that offers Tailscale Subnet Routers. `GET /v2/network_coverage?filter[available_services][contains]=tailscale_subnet_router` lists them. A location's `location.code`, such as `ashburn-va`, is the `region_code` to use.

## Create a *Network* and a WireGuard Interface

Create a [*Network*](/docs/network/overview) and a WireGuard Interface in the router's region, as in the [WireGuard Interfaces Quick Start](/docs/network/wireguard-interfaces/quick-start). The interface's `server_ip_address` is `172.27.0.1/24` here, so its subnet is `172.27.0.0/24`. Wait until the interface is `provisioned`, about three minutes.

## Prepare the Tailnet

In the [tailnet policy file](https://tailscale.com/docs/features/access-control/acls), define the [tag](https://tailscale.com/docs/features/tags) the router carries. Let the tag advertise the interface's subnet with [`autoApprovers`](https://tailscale.com/docs/reference/syntax/policy-file#autoapprovers), and let members reach it with an [access rule](https://tailscale.com/docs/features/subnet-routers#add-access-rules-for-the-advertised-subnet-routes). The auto-approver approves the route as soon as the router advertises it. Without one, approve the route in the admin console later.

```json theme={null}
{
  "tagOwners": {
    "tag:telnyx": ["autogroup:admin"]
  },
  "autoApprovers": {
    "routes": {
      "172.27.0.0/24": ["tag:telnyx"]
    }
  },
  "grants": [
    {
      "src": ["autogroup:member"],
      "dst": ["172.27.0.0/24"],
      "ip": ["*"]
    }
  ]
}
```

Then generate an [auth key](https://tailscale.com/docs/features/access-control/auth-keys) under **Settings**, **Keys**. Make it pre-approved and tagged `tag:telnyx`, and not ephemeral. A single-use key enrolls one router, and a reusable key enrolls several.

![The Generate auth key dialog in the Tailscale admin console](https://mintcdn.com/telnyx/bKPfJi1ncDCb37mt/assets/images/tailscale-subnet-router-generate-auth-key.png?fit=max\&auto=format\&n=bKPfJi1ncDCb37mt\&q=85\&s=87c7903f620ca1301457cecbd1a53cec)

Tailscale [disables key expiry](https://tailscale.com/docs/features/tags#key-expiry) for tagged machines. An untagged router's key expires after 180 days by default, and the router then stops working. **Disable key expiry** in the machine's menu prevents that.

## Create the Router

Send [`POST /v2/tailscale_subnet_routers`](/api-reference/tailscale-subnet-routers/create-a-tailscale-subnet-router) with the interface's *Network* and subnet:

```json theme={null}
{
  "name": "tailnet-ashburn",
  "network_id": "54236b77-9b41-4e5c-be36-7dc7790ba5a0",
  "region_code": "ashburn-va",
  "advertised_routes": ["172.27.0.0/24"],
  "auth_key": "tskey-auth-<key>"
}
```

> [!WARNING]
>
> A router cannot move to another *Network*, region, or tailnet. Confirm `network_id`, `region_code`, and the key's tailnet before sending the request.

The response returns `status: provisioning` and the router's `customer_address`. Traffic from devices behind the router enters the *Network* from that address.

```json theme={null}
{
  "data": {
    "id": "837c5e7f-0ea6-491b-a0e0-192c3df58cf9",
    "status": "provisioning",
    "customer_address": "172.27.254.1",
    ...
  }
}
```

## Wait for Enrollment

Poll [`GET /v2/tailscale_subnet_routers/{id}`](/api-reference/tailscale-subnet-routers/retrieve-a-tailscale-subnet-router) until `status` is `provisioned`. This takes several minutes. `device_id`, `tailnet_name`, and `tailscale_ips` then describe the router's machine:

```json theme={null}
{
  "data": {
    "id": "837c5e7f-0ea6-491b-a0e0-192c3df58cf9",
    "status": "provisioned",
    "device_id": "n6EiPn67VE11CNTRL",
    "tailnet_name": "acme.example",
    "tailscale_ips": ["100.96.104.127", "fd7a:115c:a1e0::6637:6881"],
    ...
  }
}
```

The machine's name is `ts` plus the first eight characters of the router's `id`, `ts837c5e7f` here.

A `failed` status means enrollment did not complete, for example because the tailnet rejected the key. Retry with [`PATCH /v2/tailscale_subnet_routers/{id}`](/api-reference/tailscale-subnet-routers/update-a-tailscale-subnet-router) and a new key. The router keeps its `customer_address`.

```json theme={null}
{
  "auth_key": "tskey-auth-<new key>"
}
```

## Approve the Route

With the auto-approver above, the route is active as soon as the router advertises it. Otherwise open the machine's menu in the admin console and choose **Edit route settings**:

![The machine's menu in the Tailscale admin console, with Edit route settings and Disable key expiry](https://mintcdn.com/telnyx/bKPfJi1ncDCb37mt/assets/images/tailscale-subnet-router-machine-menu.png?fit=max\&auto=format\&n=bKPfJi1ncDCb37mt\&q=85\&s=268ec7645097201598410755d31ca0c7)

Approve `172.27.0.0/24` and save, as in Tailscale's [subnet routers](https://tailscale.com/docs/features/subnet-routers) guide:

![Edit route settings of ts837c5e7f, with 172.27.0.0/24 advertised but not approved](https://mintcdn.com/telnyx/bKPfJi1ncDCb37mt/assets/images/tailscale-subnet-router-approve-route.png?fit=max\&auto=format\&n=bKPfJi1ncDCb37mt\&q=85\&s=54af89c97eda2f80b68ac6c326c40af9)

`provisioned` reports enrollment, not approval. The tailnet decides which routes are approved and who reaches them.

## Bind the Function

Add a [network binding](/docs/edge-compute/runtime/bindings/network) with the interface's `id` to the function's `func.toml`:

```toml theme={null}
[network.PRIVATE_NET]
id = "ecc72c55-6faf-4388-a06b-4c2fc2d4cc40"
```

Ship the function:

```bash theme={null}
telnyx-edge ship
```

The deploy registers the function as a peer of the interface, named `func-<function-id>`.

## Find the Address

`GET /v2/wireguard_peers?filter[wireguard_interface_id]=<interface-id>` lists the interface's peers. The function's peer configuration, [`GET /v2/wireguard_peers/{id}/config`](/api-reference/wireguard-interfaces/retrieve-wireguard-config-template-for-peer), shows its `Address`, `172.27.0.4/32` here.

Each deploy gives the function a new address. Look it up again after every deploy.

## Call the Function From Behind the Router

A tailnet device is behind the router once it [accepts the route](https://tailscale.com/docs/features/subnet-routers#use-your-subnet-routes-from-other-devices). Devices on macOS, Windows, iOS, and Android accept it automatically. Linux devices need:

```bash theme={null}
tailscale set --accept-routes
```

Call the function on its address and `PORT`, 8080:

```bash theme={null}
curl http://172.27.0.4:8080/
```

The function answers with its default response:

```json theme={null}
{"message":"Hello from Telnyx Edge Compute!"}
```

The function sees the request from the router's `customer_address`, `172.27.254.1`.

## Change the Routes

[`PATCH /v2/tailscale_subnet_routers/{id}`](/api-reference/tailscale-subnet-routers/update-a-tailscale-subnet-router) with a new `advertised_routes` list replaces the advertisement:

```json theme={null}
{
  "advertised_routes": ["172.27.0.0/24", "172.27.1.0/24"]
}
```

The router returns to `provisioning` for about four minutes. It keeps its machine, with the same `device_id` and `tailscale_ips`. A new route needs approval unless an auto-approver covers it. A request while the router is `provisioning` or `deleting` returns `409`.

## Delete the Router

[`DELETE /v2/tailscale_subnet_routers/{id}`](/api-reference/tailscale-subnet-routers/delete-a-tailscale-subnet-router) returns `status: deleting`, and the record disappears within a few minutes. The router logs out of the tailnet. Its machine stays in the admin console, expired, until an admin chooses **Remove** in the machine's menu. Delete the tag, the auto-approver, and the ACL entry when nothing else uses them.

Delete a *Network*'s routers before the *Network*, as for its other interfaces.
