Apps
Route traffic for chosen domains through tagged app connector nodes: define apps, how learned and static routes and split DNS work, and manage them.
An app is a set of domains reached through app connectors, following
Tailscale’s app connectors.
Instead of routing all Internet traffic through an exit node or advertising
broad subnets, an app connector lets devices on your tailnet reach specific
applications and SaaS domains (such as example.com or *.example.com)
through designated connector nodes in your network.
How it works
- Connector node. A machine runs the app connector service and advertises itself as a connector.
- App definition. An operator defines the app with its domains, static routes, and connector selectors.
- Route learning and approval. The connector resolves the app’s domains, advertises single-address host routes for the learned IPs, and the server approves them automatically.
- DNS. The server sends every machine split DNS for the app’s domains that points at the connectors, so queries reach a connector and it learns the addresses.
Setting up a connector node
A connector node must be a tagged machine because connectors act as shared network infrastructure; user-owned machines cannot serve as connectors.
On the machine, advertise the connector service:
tailscale set --advertise-connector
When registering a new node, pass --advertise-connector to tailscale up
along with the node’s tags:
sudo tailscale up --login-server <YOUR_SLOPSCALE_URL> --auth-key <KEY> \
--advertise-connector
The node reports to the server that it runs the app connector service. The
server sends app definitions to matching connector nodes using the
tailscale.com/app-connectors node capability.
Defining apps
An app has:
- Name: 1 to 63 characters.
- Description: an optional summary.
- Domains: domain names or wildcard domains the connectors watch and
resolve, such as
example.comor*.example.com. - Connectors: node tag selectors (such as
tag:connector) that specify which connector nodes serve the app, or*to select every tagged machine running the connector. If omitted,*is the default. - Routes: optional static CIDR prefixes (such as
198.51.100.0/24) that connectors always advertise. Full internet routes (0.0.0.0/0and::/0) are refused.
Learned and static routes
Connector nodes watch the app’s configured domains and resolve them. Whenever
a connector learns an address for a domain, it advertises a host route
(/32 for IPv4 or /128 for IPv6).
The server approves learned single-address routes automatically. If an app
defines static routes, any prefix within those routes is also approved
automatically for the app’s connectors. Any other advertised routes, such
as broader subnets (10.0.0.0/16) or exit routes, are not covered by the app
and require manual approval by an operator (or policy autoApprovers.routes).
When a domain leaves an app, or the app is deleted, the connector withdraws the routes it learned for it and the server drops their approvals with them, so the connector’s route list only holds what it advertises. Exit routes are left alone, and a plain subnet router keeps its approvals when it stops advertising a route, as before.
DNS
The server sends every machine split DNS for the app’s domains, pointing
at the connectors’ DNS endpoints over the tailnet, the way Tailscale’s
control plane does: a query for example.com goes to a connector, the
connector answers it and learns the addresses in the answer. A machine
sees only the connectors it has as peers, online ones first, and a
connector is never sent its own apps. A wildcard domain (*.example.com)
routes the base domain too. Nothing has to be configured under
DNS; a split DNS rule for the same domain, if one exists,
comes first.
A connector answers a peer’s query only when the policy lets that peer
send traffic to the internet through it, which is the same access the
peer needs for the addresses the connector learns: a rule with
autogroup:internet or the addresses themselves as the destination and
the peer as the source.
Machines at the connector’s site
A machine that reaches the internet from the same public address as a connector skips that connector. The app already sees the address it allows, so going through the connector would only add a hop. Say the connector sits in the office: a laptop in the office goes out directly, while the same laptop at home still goes through the office connector.
The server compares the public IPv4 address each client reports among its endpoints, the address its NAT shows the internet, so nothing has to be configured. When a machine or a connector moves, its peers get a new netmap. A machine that skips a connector does not get these from it:
- the host routes the connector learned from the app’s domains
- the public prefixes inside the app’s static routes
- the split DNS for the app’s domains
Private prefixes such as 10.0.0.0/8 in an app’s static routes stay
routed through the connector, since sharing a public address says nothing
about reaching a private network. If an app has connectors at several
sites, a machine skips only the connector behind its own address and
still uses the others.
Console and API
The admin console has an Apps page under Connectivity (Connectivity › Apps),
listing configured apps, their domains, connector selectors, static routes,
and the connector nodes assigned to each app with counts of learned and pending
routes.
From the CLI:
slopscale apps list
slopscale apps show --id 1
slopscale apps create --name "Internal Tools" \
--domain tools.corp.example.com --domain "*.tools.corp.example.com" \
--connector tag:connector \
--route 192.0.2.0/24
slopscale apps update --id 1 --route 198.51.100.0/24
slopscale apps delete --id 1
Through the API:
GET /api/v1/apps: list all apps (requirespolicy_file:read).POST /api/v1/apps: create an app (requirespolicy_file).GET /api/v1/app/{id}: retrieve an app (requirespolicy_file:read).PUT /api/v1/app/{id}: update an app definition (requirespolicy_file).DELETE /api/v1/app/{id}: delete an app (requirespolicy_file).
Creating, updating and deleting an app are audited as app.create,
app.update and app.delete.