---
title: "Networks"
description: "Hand subnets and exit nodes to chosen groups with networks, narrow them by protocol and port, and let peers relay traffic through a machine of your own."
---

A network is a set of prefixes reached through one or more routing machines
and handed out only to the machines in the groups you pick, the way NetBird's
networks and routes work. It replaces the per-machine route approval and the
policy needed to restrict who sees a subnet: the network approves the routes
on its routers and trims them out of the map of every machine outside its
groups, so those machines never learn the route exists. That is the split
tunnel most operators want, with no policy file involved.

A network with the exit routes (`0.0.0.0/0` and `::/0`) is an exit node
offer to its groups. Naming either exit route brings the other, because
clients advertise them as a pair.

## Setting one up

1. On the routing machine, advertise the prefixes as you would for any
   [subnet router](/slopscale/ref/routes#subnet-router) or [exit node](/slopscale/ref/routes#exit-node):

    ```console
    $ sudo tailscale set --advertise-routes=10.10.0.0/24
    ```

    IP forwarding must be on; see [Enable IP forwarding](/slopscale/ref/routes#enable-ip-forwarding).

1. Create the network with the prefixes, the routing machine and the groups
   that get the routes. From the console's _Networks_ page, or:

    ```console
    $ slopscale networks create --name "Office LAN" --prefix 10.10.0.0/24 --router 7 --group 2
    ```

    The routes are approved on the router at once, no separate approval step.
    The machines in group 2 receive them; nobody else does. Use the builtin
    _All_ group to hand the routes to everyone.

1. On a machine in the group, check that the route arrived:

    ```console
    $ tailscale status --json | jq '.Peer[] | select(.HostName == "office-router") | .PrimaryRoutes'
    ```

Two or more routers make a failover pair: every one advertises the same
prefixes and Slopscale elects a primary, as for any
[high availability](/slopscale/ref/routes#high-availability) router. The console marks a
router that stops advertising one of the network's prefixes; the network
still hands out whatever the other routers serve.

## What a network does and does not do

Approval belongs to the network. Creating or enabling a network approves its
prefixes on its routers; editing it withdraws the approvals that no longer
match and adds the new ones; disabling or deleting it withdraws them all.
Approvals made by hand on the machine's routes page are left alone, so a
route approved both ways stays approved when the network goes.

Distribution follows the groups. A machine receives a network's routes when it
is in one of the network's groups or is itself one of the routers. Group
membership is the same as for [access rules](/slopscale/ref/access-control): a user's
machines follow the user, tagged machines join directly.

Reachability follows the tailnet. While the tailnet is open (no enabled access
rule and no restricting policy file), a machine that has the route can use it.
Once something makes the tailnet enforce, the network's groups may reach its
prefixes on the network's protocol and ports (every port unless the network
narrows them), and nothing else may; a network on its own never switches
enforcement on.

A network can narrow what its groups reach behind the routers. The protocol
is one of `all`, `tcp`, `udp` or `icmp`, and for TCP and UDP a port list such
as `22, 8000-8100` limits the reach further, the same fields an access rule
has. A network for a printer subnet on `tcp` port 631 hands out the whole
route but lets its groups print and nothing more. The narrowing only takes
effect while the tailnet enforces; on an open tailnet the route stays open, the
network list reports `enforcing: false`, and the console marks the narrowing as
not in force. The _Routes_ page next to _Networks_ lists every route any
machine advertises, network-owned or not, and approves the rest by hand.

A group that a network uses cannot be deleted until the network drops it.

## API and CLI

Networks live at `/api/v1/network` and need the `devices:routes` scope
(`devices:routes:read` to list), the same scope as route approval. A network
is created with `POST /api/v1/network`:

```json
{
  "name": "Office LAN",
  "prefixes": ["10.10.0.0/24"],
  "routerNodeIds": ["7"],
  "groupIds": ["2"]
}
```

`protocol` (`all`, `tcp`, `udp`, `icmp`; defaults to `all`) and `ports`
(a comma list of ports or ranges, for TCP and UDP) narrow what the groups may
reach behind the routers.

`PUT /api/v1/network/{id}` replaces the whole record, `PATCH` with
`{"enabled": false}` switches it off, and `DELETE` removes it. The response
carries a `routers` list with each router's liveness, the prefixes it serves
and the ones it does not advertise.

`slopscale networks` has `list`, `show`, `create`, `update` (which fetches the
network and replaces only the flags given), `enable`, `disable` and `delete`.
`create` and `update` take `--protocol` and `--ports`.

## Peer relays

A peer relay is a machine of your own tailnet that forwards UDP between two
peers that cannot reach each other directly. It is an alternative to
[DERP](/slopscale/ref/derp) for that pair: the traffic stays inside the network the
relay sits in and keeps its own WireGuard session, instead of going out to a
relay server on the internet. A machine in the office that both sides can
reach is the usual candidate.

Run one with a Tailscale client 1.86 or later on Linux, Windows or macOS
(iOS builds carry no relay server). On the machine that is to relay:

```console
$ sudo tailscale set --relay-server-port=41642
```

Any UDP port will do, `0` picks a free one and an empty value turns the relay
server off again. Open that UDP port on the machine's firewall for the peers
that will use it.

The client only offers to relay for peers the control server lets it, which is
a grant with the `tailscale.com/cap/relay` capability. It names the sources
that may allocate a relay session and the machines that will carry it:

```json title="policy.json"
{
  "grants": [
    {
      "src": ["autogroup:member"],
      "dst": ["tag:relay"],
      "app": {
        "tailscale.com/cap/relay": [{}]
      }
    }
  ]
}
```

Slopscale compiles that into the packet filter both sides receive, and adds
the companion `tailscale.com/cap/relay-target` rule in the opposite
direction, so the relay learns which machines may allocate on it. It also
treats a relay as a machine whose comings and goings matter: when one
connects or disconnects, the peers that may allocate through it recompute
their whole netmap rather than taking the cheap online/offline patch, so an
allocation through a relay that has gone away is dropped instead of being
used.

The port is a client preference, so the control server cannot switch a relay
server on. It can switch one off, with the `disable-relay-server`
[node attribute](/slopscale/ref/policy#node-attributes): while a machine carries it, its
relay server stays down whatever its `--relay-server-port` says.

```json title="policy.json"
{
  "nodeAttrs": [
    {
      "target": ["tag:laptop"],
      "attr": ["disable-relay-server"]
    }
  ]
}
```

To check the result, ask the relay what it is carrying:

```console
$ tailscale debug peer-relay-sessions
```

It prints the port it is bound to, or that none is configured, and one line
per active session. On a client, `tailscale debug peer-relay-servers` lists
the relays it knows it may use, `tailscale status` shows `peer-relay <addr>`
for a peer it reaches that way, and `tailscale ping` reports
`via peer-relay(<addr>)`.
