In this page
How Tuvima separates desired network configuration from observed connectivity and chooses remote playback delivery.
Where this lives in the code
src/MediaEngine.Api/Services/Networkingsrc/MediaEngine.Api/DependencyInjection/TuvimaNetworkServiceCollectionExtensions.csdeploy
Tuvima treats networking as an appliance-style workflow. Administrators use
Settings → Server → Network and Remote Access for a health overview, LAN settings,
remote access, network-aware streaming, and advanced diagnostics. A new install
uses the same panels in /setup/network; there is no second onboarding model.
Tuvima is open from the start: any device that can reach the server can use it,
and Tuvima sign-in is always required. The default needs no router, DNS, TLS, or
tunnel knowledge, and a secure outside address is an optional extra.
Source of truth
Desired state lives in config/network.json and is validated against
config/schemas/network.schema.json. There is no rule about how far away a visitor may be: the
Dashboard answers every request whatever its origin, and Tuvima sign-in decides
who gets in. The only exception is the no-password “use Tuvima on this computer”
account, which any device that reaches the server can use, with its administrator
rights, until a password or passkey is added (see
Account security). Closed router ports are the
gatekeeper. The Dashboard serves plain http, so if its port is forwarded to the
internet, sign-ins and pairing codes cross the internet unencrypted; for access
from outside, use Tailscale or an HTTPS reverse proxy. Schema 2.0 includes the
Dashboard port, binding, local discovery, remote mode, advanced router
automation, custom HTTPS address, exact/CIDR trusted proxies, and
remote-streaming policy. Supported remote modes are tailscale, custom, and
the advanced direct-only mode. The removed secure-provider placeholder is
rejected. Keys from the retired reach and app-switch settings left in a
user’s file are ignored.
Phone and TV apps are always allowed; there is no app on/off switch. The paired-app
door (/.well-known/tuvima, /pair, /api/v1/** and /application-events/**) and
the cast relay always answer. native_app_access.allow_browser_apps (default
false, config file only) is a separate switch for packaged TV web apps, whose
page origin is null or an app scheme. Only with it on does the Dashboard give
those origins cross-origin permission for /api/v1/** and /.well-known/tuvima.
Because any web page can claim the null origin, it also lets a website reach the
anonymous pairing surface; pairing still needs a person to approve the code on
/pair. See Configuration.
Addresses apps use
The discovery answer GET /.well-known/tuvima (Dashboard, anonymous) always
answers and carries an optional outside_address (an origin) when a secure
outside address is set up: the Tailscale address or the public hostname. The
Engine supplies it through GET /network/outside-address (Dashboard service
credential only), which returns { outside_address }. Settings →
Network and Remote Access shows both: the home address (the Engine’s preferred
address on the adapter chosen in Settings → Network, with the Dashboard port) and,
when set, the outside address.
The Android app saves the address typed at pairing as its home address and learns the outside address from discovery, at pairing and at app start only. It tries home first (about 1.5 seconds), falls back to the outside address, rechecks when the phone’s network changes, rebases every request, stream and download to the current address, and sends its sign-in token only to those two addresses. Removing the outside address on the server reaches the phone after re-pairing. Apple, Roku and TV web apps do not do this yet.
Observed state stays in memory: usable interfaces, topology, current Tuvima-owned router mapping, public address, latest tests, measured bandwidth, and provider state. The API never writes those observations into configuration.
Supported secure edge
The Dashboard is the only supported user-facing service. The Engine stays on loopback or an internal application network. TLS terminates at one of these external edges:
- Tailscale Serve for private tailnet HTTPS.
- An administrator-managed HTTPS reverse proxy such as Caddy, nginx, or Traefik.
Tuvima authentication remains mandatory. Tailnet membership and forwarded identity headers do not replace the Dashboard sign-in boundary. Settings → Network → Remote Access (How the internet reaches Tuvima) sets up that optional secure outside address, and Test remote access runs a Tuvima challenge probe against the selected HTTPS/tunnel route. Passing the test does not unlock anything; the page only chooses and checks the outside address.
Connectivity lifecycle
- Local discovery announces
_tuvima._tcp.localwhen enabled. - Router setup is off by default and appears only under Advanced settings.
- Advanced automatic setup tries PCP, NAT-PMP, then UPnP IGD, targeting an explicitly configured local TLS reverse-proxy listener rather than the Dashboard HTTP port.
- Lease mappings are renewed every 15 minutes and after a safe port change.
- Disabling router automation or a clean Engine shutdown removes only the mapping that Tuvima created.
- A failed automatic setup produces a dynamic manual TCP forwarding rule.
- CGNAT evidence changes the guidance instead of repeatedly recommending a router rule that is unlikely to work.
- Docker bridge mode is classified as
unsupported-topology. Inside the container, the visible gateway belongs to Docker’s bridge (commonly associated withdocker0) rather than the physical LAN router. No PCP, NAT-PMP, or SSDP traffic is sent in that topology.
Mapping observations use explicit states: not-attempted,
unsupported-topology, protocol-unavailable, router-refused, active, and
expired. Protocol timeouts and malformed responses remain reason codes rather
than being presented as proof that a router refused the request.
External reachability and upload measurements remain unknown when no trusted external measurement target exists. The UI does not substitute sample success, public-IP, or bandwidth values.
Tailscale deployment boundary
Tailscale is an external deployment provider, not an embedded VPN. Native hosts
are observed with tailscale status --json and tailscale serve status --json.
The Docker preset uses the official Tailscale sidecar, private Serve HTTPS, and
a separate persistent state volume. Enrollment keys are deployment secrets
outside Tuvima configuration and backups. The generic
IRemoteConnectivityProvider boundary remains available for Headscale or a
different tunnel provider.
Playback context
Playback manifests and heartbeats carry connection path, provider, approximate bandwidth, latency, device, profile, and optional room identity. These facts are used only for delivery selection and diagnostics—not authentication.
For remote playback, the existing playback manifest can prefer its existing HLS delivery path when source resolution or calculated bitrate exceeds the configured quality/bandwidth budget. Local compatible clients retain direct delivery. This does not introduce a second transcoding engine.
Security boundary
Every network settings and diagnostics endpoint requires the Administrator role.
Reachability never grants authentication. Forwarded host, scheme, and
client-address headers are accepted only from exact proxy IP addresses in
trusted_proxies or explicit CIDR entries in trusted_proxy_networks, with one
forwarding hop allowed. The middleware runs before HSTS, redirection,
authentication, and URL generation. Forwarded headers are honoured only on the
optional proxy port (remote.proxy_port); on the main Dashboard port they are
ignored. Where a request comes from never decides whether the Dashboard answers
it, and plain http is not refused. A Host allow-list (local.allowed_hostnames
plus the machine, server and public names) refuses unknown host names to block
DNS rebinding.