---
title: "Share an app, not your whole machine"
description: "Share one localhost app over Tailscale through its own TSLink node. See what each node exposes and what changes if the host also runs Tailscale."
url: "https://tslink.md/docs/share-one-app"
locale: "en"
product_version: "0.1.1"
source: "https://github.com/anydoor7/tslink/blob/v0.1.1/docs/architecture.md"
---

> Documentation index: https://tslink.md/llms.txt · Installed binary is authoritative: `tslink manifest`.

## One node for each registered app

**One app, not the whole machine.** With no separate host Tailscale connection, TSLink exposes each app's configured target through its own embedded node, without adding other host ports. Independent routes and other gateways on the host are outside this statement; review them separately. A proxy target may also be a non-local address reachable by the daemon. See [architecture](https://tslink.md/docs/architecture.md), [proxy configuration](https://tslink.md/docs/services.md), [Tailscale tsnet](https://tailscale.com/docs/features/tsnet) and the [tsnet package overview](https://pkg.go.dev/tailscale.com@v1.102.5/tsnet).

The nodes have distinct identities but run in one shared daemon. They do not create separate execution environments or reduce the daemon's OS-user privileges. An app may itself provide host administration, file access or other powerful operations. See [architecture](https://tslink.md/docs/architecture.md).

## Follow a request from phone to app

[Without a separate host Tailscale connection, Phone requests reach separate app A and report nodes on port 443, then localhost:3000 or report.html on one host with a shared TSLink daemon. A TCP client reaches its own node and target. Optional portal and remote MCP nodes are separate; dashed management arrows never carry app requests. A second panel shows a separate host Tailscale device and its policy-controlled route to listening services.](https://tslink.md/app-entry-points-light.svg)

[Without a separate host Tailscale connection, Phone requests reach separate app A and report nodes on port 443, then localhost:3000 or report.html on one host with a shared TSLink daemon. A TCP client reaches its own node and target. Optional portal and remote MCP nodes are separate; dashed management arrows never carry app requests. A second panel shows a separate host Tailscale device and its policy-controlled route to listening services.](https://tslink.md/app-entry-points-dark.svg)

Solid transport arrows follow `phone → app A node:443 → localhost:3000`, `phone → report node:443 → report.html` and `TCP client → TCP node:<port> → target`. The identities are drawn outside the host box for clarity; they are embedded in its shared daemon. Dashed arrows denote management. App requests do not pass through MCP. See [request paths](https://tslink.md/docs/architecture.md), [MCP setup](https://tslink.md/docs/mcp-server.md) and [Tailscale access controls](https://tailscale.com/docs/features/access-control/acls).

## What each listener exposes

| Entry point              | What it makes available                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTP proxy/file app node | HTTPS on node port 443, the selected proxy or file handler, authorization and request middleware. A proxy includes its configured backend's reachable routes and functions. Explicit public Funnel uses that node's port 443. [App management](https://tslink.md/docs/services.md) · [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel)                                                                      |
| TCP app node             | One private listener on the configured port, 443 if unspecified, forwarding to its TCP target. No HTTP `--allow`/people checks or HTTPS termination: use network policy and backend authentication. [TCP behavior](https://tslink.md/docs/architecture.md) · [Tailscale access controls](https://tailscale.com/docs/features/access-control/acls)                                                                                  |
| Directory or single file | A directory share serves its subtree and may list directories. A regular-file share serves only the selected filename, redirects `/` with 302 and returns 404 for siblings/other paths. Directory opens use an anchored OS root; traversal and symlinks escaping that root are rejected. Contents remain live; hard links inside the served tree are ordinary served files. [File sharing](https://tslink.md/docs/file-sharing.md) |
| Optional portal          | A separate embedded HTTPS node on 443, serving the app directory `/`, filtered `/api/apps` and access-request handling. It is not added to every app node; sharing the portal node does not make app nodes reachable. [Portal](https://tslink.md/docs/portal-requests.md) · [Tailscale device sharing](https://tailscale.com/docs/features/sharing)                                                                                |
| Optional remote MCP      | Off by default, on a separate private HTTPS node with `/mcp` and an optional owner `/events` stream. It is not an app listener and is not published through Funnel. [MCP setup](https://tslink.md/docs/mcp-server.md) · [MCP roles](https://tslink.md/docs/mcp-scopes.md)                                                                                                                                                          |

Backend health probes contact the configured backend directly; file checks inspect the configured directory/file. App-node assembly adds no TSLink health/admin HTTP route. An app's own health route remains part of its proxy target. See [health checks](https://tslink.md/docs/health-and-alerts.md) and [architecture](https://tslink.md/docs/architecture.md).

Local MCP uses stdio. Each embedded node's `LocalClient` is node-local control, not a tailnet control socket; TSLink does not invoke the optional tsnet `Loopback` listener. Publishing does not need the system Tailscale installation or shell out to its CLI, but `doctor` can read a system client's SSH preference through LocalAPI; absence or timeout becomes unknown. See [MCP setup](https://tslink.md/docs/mcp-server.md), [diagnostics](https://tslink.md/docs/troubleshooting.md), [LocalClient](https://pkg.go.dev/tailscale.com@v1.102.5/tsnet#Server.LocalClient) and [Loopback](https://pkg.go.dev/tailscale.com@v1.102.5/tsnet#Server.Loopback).

## Compare a separate Tailscale connection on the host

Compare network entry points. Ordinary Tailscale adds a device, and policy governs reachable device/port combinations. Its listening services also depend on their listening and firewall settings; not every port, process or file automatically becomes available. TSLink adds app-node listeners without requiring that separate host connection. If both run, both paths exist. See the [tsnet package overview](https://pkg.go.dev/tailscale.com@v1.102.5/tsnet) and [Tailscale access controls](https://tailscale.com/docs/features/access-control/acls).

## Set per-app access rules

For a private HTTP app:

```bash
tslink add agent-ui --proxy localhost:3000 --allow you@example.com
tslink url agent-ui --wait
```

Complete enrollment and any approval when required. Separate identities permit separate network rules; optional TSLink `--allow`/people rules add HTTP/file checks. Default private sharing is not automatically owner-only. Portal owner/admin identities can open all private HTTP/file apps, subject to network policy and app login. See [first private share](https://tslink.md/docs/quickstart.md), [people sharing](https://tslink.md/docs/people-sharing.md) and [portal permissions](https://tslink.md/docs/portal-requests.md).

Fresh credential-free nodes do not advertise tags, so do not assume tag-based rules are active. Raw TCP needs network policy and backend authentication. See [credentials](https://tslink.md/docs/configuration.md), [architecture](https://tslink.md/docs/architecture.md), [Tailscale tsnet](https://tailscale.com/docs/features/tsnet) and [access controls](https://tailscale.com/docs/features/access-control/acls).

## What TSLink does not restrict

TSLink does not constrain processes, filesystem privileges, an app's own capabilities or independently exposed LAN/host routes. It does not replace app authentication, and the portal is not a shortcut around network access requirements. A proxy publishes whatever its chosen backend makes available. See [architecture](https://tslink.md/docs/architecture.md), [proxy targets](https://tslink.md/docs/services.md) and [portal access](https://tslink.md/docs/portal-requests.md).

For a practical flow, try [an agent UI from your phone](https://tslink.md/docs/agent-ui-phone.md) or [a single HTML report with a deadline](https://tslink.md/docs/private-html-report.md).

Official Tailscale sources linked above: accessed **2026-10-07**. Product behavior: TSLink v0.1.1.
