tabbify.io
Documentation
Product directionEDGE BOX
ReferenceArchitecture

Routing & public access

Every Tabbify app gets its own address on the private mesh, derived from its UUID. The public node is the one component with a public listener — it joins the mesh and proxies external requests to those addresses. This page covers both halves: the per-app address and the public edge in front of it.

Per-app addresses

An app's mesh address is a deterministic IPv6 ULA derived from its UUID via BLAKE3, in the fd5a:1f02::/32 block:

fn derive_app_ula(app_uuid: Uuid) -> Ipv6Addr {
  let b = blake3::hash(app_uuid.as_bytes());
  let b = b.as_bytes();
  Ipv6Addr::new(
    0xfd5a, 0x1f02,
    u16::from_be_bytes([b[0], b[1]]),
    u16::from_be_bytes([b[2], b[3]]),
    u16::from_be_bytes([b[4], b[5]]),
    0, 0, 1,
  ) // fd5a:1f02:<48-bit hash>::1
}

Because the hash depends only on the UUID, the supervisor and edge compute the same address independently, with no per-request supervisor query. The address stays associated with the application across deployments. Each app's runner binds [app_ula]:8730, and production traffic reaches that address through the managed mesh relay.

Per-instance addresses for managed data

Managed PostgreSQL, KV and object-storage instances are addressed the same way, in their own fd5a:1f03::/32 block: the address is BLAKE3 over the instance id instead of an app UUID, so it too is recomputed rather than stored, and it is the address your connection string names:

postgresql://app_rw@[fd5a:1f03:a1b2:c3d4:e5f6::1]/mydb

No port is printed — every managed protocol is reached on its own default port (PostgreSQL 5432, Redis 6379, S3 443) — and no DNS name is created for an instance: the address is derived, and libpq and every mainstream client library accept a bracketed IPv6 literal as-is.

An instance is not a mesh peer itself; its door (the managed proxy for that protocol) holds the address and answers on it, and only peers holding a grant on that instance are told the address exists. That is why a leaked connection string is not access on its own: reaching the address is a question of the grant, and the credentials in the string are the second factor.

The public edge

tabbify-node serves the standard public application routes. It joins the mesh and installs routes to advertised app ULAs; the managed relay carries the production hop to the selected workload host. The public edge terminates HTTPS, so applications do not expose their guest ports to the internet.

The node exposes two kinds of routes:

  • App-serving — /app/{uuid}, /app/{uuid}/{*rest}, and the bare /{uuid} and /{uuid}/{*rest} aliases. These are public: they carry no bearer gate, because this is the edge that fronts your deployed app to the open internet. Both https://api.tabbify.io/app/<uuid>/path and the shorter https://api.tabbify.io/<uuid>/path reach the same app.
  • Control — /v1/*. These require Authorization: Bearer <TABBIFY_TOKEN>, the API token issued to your Tabbify account. /health and the docs (/openapi.json, /swagger-ui) are public too.
# Reach a deployed app — public, no auth needed
curl https://app.tabbify.io/app/<uuid>/some/path

# Same app via the node's API host (the bare /<uuid> alias also works)
curl https://api.tabbify.io/<uuid>/some/path

# A control call — requires your Tabbify API token
curl https://api.tabbify.io/v1/apps \
  -H "Authorization: Bearer $TABBIFY_TOKEN"

App-serving routes derive the ULA and stream the request to [app_ula]:8730 through the relay. Bodies are not buffered, and hop-by-hop headers are stripped both ways. An unreachable app returns 502; a malformed UUID returns 400.

Getting a public URL

You don't wire any of this up by hand. When you deploy from a git push, the pipeline clones and builds your repo, runs it as a Firecracker microVM, and the runner binds its derived app_ula. The node already knows how to reach that address, so the app is live the moment the runner is healthy:

  1. git push triggers the deploy pipeline; the supervisor spawns a runner that binds [app_ula]:8730.
  2. A request to https://app.tabbify.io/app/<uuid>/ is routed from the TLS edge through the mesh relay to the runner.
browser -> TLS edge -> node -> WireGuard relay -> [app_ula]:8730

Custom domains and TLS

A tenant can attach a custom hostname to an application through the current domain workflow. Follow the DNS target and verification instructions shown by the console or API. After validation, the public edge serves the hostname with TLS and forwards it to the same application route.

Custom ingress does not add application authentication. If a route contains private data or mutations, enforce authentication and authorization in the application.

The deterministic address solves application routing; it does not imply a peer-to-peer production transport. Production currently remains relay-only. See Private Mesh and Self-hosting.