Documentation
API reference

Start here

Search every guideesc close

Connections

Local, direct, or relay

The three paths a stream can take from your server to your screen, what each one means for quality, and how to get the fastest one.

6 min read

Every time an app plays something from your server, the stream takes one of three paths. Knowing which one you're on answers most "why does it look different away from home" questions.

The three paths#

Local#

Your device and your server are on the same network, so the stream never touches the internet. This is the fastest path: full quality, instant seeks, and it works even when your internet is down. Local playback never counts against any limit.

Direct#

You're away from home and your device connects across the internet, straight to your server. Still full quality: the only limit is your home connection's upload speed. Direct needs a port that's reachable from outside, which tofa sets up automatically on most routers (more below). A tunnel or your own domain also counts as direct, with no port forwarding at all. See Use your own tunnel or domain.

Relay#

When a direct connection can't be made, the stream routes through our relay. It works from anywhere with zero setup, and it is a pipe: the relay forwards your encrypted stream without decrypting or inspecting it. The trade-off is bandwidth. Each relayed stream is capped at 2 Mbps on the free tier, and 4 Mbps with up to 3 relayed streams for Supporters. During the beta every server runs with Supporter limits.

Your player adjusts the quality to fit inside the cap, so relay looks like a softer picture on big screens, not buffering.

How the apps choose#

You don't pick a path; the apps race them. On each playback the app tries local first, then direct, then relay, and uses the fastest one that answers. A path that stops working doesn't strand you: the app falls through to the next one. If your situation improves, say a port mapping starts working, the next playback picks the better path automatically.

Because it is a race rather than a setting, having more than one working path is always better than having exactly one. A server with a port mapping and a tunnel simply uses whichever answers first.

How to tell which one you're on#

  • In the player: open the quality menu. On relay you'll see a relay notice with the bandwidth limit, and quality options above the cap are disabled. No notice means local or direct.
  • On the server: Admin, Settings, Remote Access shows how your server is reachable from the internet and explains why when it isn't, including double NAT and CGNAT. The card describes the server in general; the player notice describes the connection this device actually got.

Getting local playback at home#

Usually there is nothing to do: your apps find the server through local discovery and connect straight to it.

If devices at home show the relay notice, the server probably isn't advertising a reachable home-network address. This mostly happens in Docker without host networking, and on Docker Desktop, where the only address the server can see for itself is an internal container address that no other device on your network can reach. Set Local network address in Admin, Settings, Remote Access (or the ADVERTISED_LAN_IP variable in your compose file), and see Remote access and local playback in the server guide.

The Remote Access card has a test button that checks the advertised home address from the device you're reading it on, which is the quickest way to confirm you got it right.

Getting direct playback away from home#

There are four ways to get a direct path, and they stack. Set up whichever ones are easy for you.

Automatic port mapping, the default#

The server asks your router to open a port and keeps the mapping renewed. It tries UPnP first, then PCP, then NAT-PMP, so it works with most consumer routers without you touching anything. If your router allows it, you're done: the Remote Access card shows your server as reachable.

Some routers ship with this disabled, or call it something else in their settings. Common names are UPnP, IGD, NAT-PMP, and "automatic port forwarding". If you'd rather not enable it, use a manual forward instead.

Manual port forward#

Forward a port on your router to your server's port (33333 by default) and enter the outside port as the external port in Admin, Settings, Remote Access. tofa then skips the automatic attempts and advertises the port you gave it. This is the right choice when automatic mapping is off, blocked, or unreliable on your router.

IPv6#

If your connection has IPv6, the server picks up its address and hands it to us, and once we have confirmed the address is actually reachable your devices start using it. Nothing to set up. This matters most under carrier-grade NAT, where IPv6 often works even though IPv4 port forwarding cannot.

The Remote Access card says whether we have confirmed the address or are still waiting, and there is a switch to stop advertising your IPv6 address if you would rather not hand it out.

Your own tunnel or domain#

If you already reach your server through Tailscale, a Cloudflare Tunnel, or a reverse proxy, add that address under Custom access URLs in Remote Access. Connections through it count as direct, with no relay caps and no port forwarding. Use your own tunnel or domain walks through each of the three setups.

When your connection can't be opened: CGNAT and double NAT#

Some connections can't be opened from the inside, no matter how the router is configured. The Remote Access card detects the two common cases and names the one you have:

  • Carrier-grade NAT. Your provider shares one public IPv4 address across many customers, so no amount of port forwarding makes your server reachable over IPv4.
  • Double NAT. Your router sits behind another router, often a provider box in front of your own, so a port opened on one still dead-ends at the other.

What helps, roughly in order of effort:

  • IPv6 often just works under CGNAT, and needs nothing from you.
  • For double NAT, forward the port on both routers, or put the outer box in bridge mode. The test button tells you when you've succeeded.
  • A tunnel sidesteps the problem entirely, because the connection is made outward from your server rather than inward from the internet. See Use your own tunnel or domain.
  • Ask your provider for a public or static IP address, or to be taken off CGNAT. Many do this on request, sometimes for a small fee, and it fixes the problem at the source.
  • Or do nothing. Remote streams fall back to the relay automatically. It always works, and for a lot of households it is enough. A direct path is worth having if you watch high-bitrate files away from home.