Networks
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
-
On the routing machine, advertise the prefixes as you would for any subnet router or exit node:
$ sudo tailscale set --advertise-routes=10.10.0.0/24IP forwarding must be on; see Enable IP forwarding.
-
Create the network with the prefixes, the routing machine and the groups that get the routes. From the console’s Networks page, or:
$ slopscale networks create --name "Office LAN" --prefix 10.10.0.0/24 --router 7 --group 2The 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.
-
On a machine in the group, check that the route arrived:
$ 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 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: 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:
{
"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 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:
$ 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:
{
"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: while a machine carries it, its
relay server stays down whatever its --relay-server-port says.
{
"nodeAttrs": [
{
"target": ["tag:laptop"],
"attr": ["disable-relay-server"]
}
]
}
To check the result, ask the relay what it is carrying:
$ 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>).