Skip to content

Identity-first transport

Aster’s transport layer is iroh: a networking library that provides QUIC connections identified by ed25519 public keys, with built-in NAT traversal and relay fallback.

For a worker moving from a customer LAN to another network, three things have separate roles: its key identifies the peer, address hints help find it, and a network path carries the connection. Preserve the secret key to preserve the identity. Refresh address information and test reachable paths when the network changes.

Transport authentication proves possession of the expected endpoint key. Your application’s trust policy decides whether that peer may use the service.

Every iroh endpoint has an ed25519 keypair. The public key is called the EndpointId. It serves as the endpoint’s stable identity regardless of network location – the same endpoint keeps the same EndpointId whether it is on a home Wi-Fi network, a corporate LAN, a mobile cellular connection, or a cloud VM.

When you connect to a remote endpoint, you specify its EndpointId. The transport layer resolves that identity to a network path. Applications can supply direct IP addresses and relay hints when discovery alone is insufficient.

iroh uses QUIC as its transport protocol. QUIC provides several properties that matter for distributed systems:

Stream independence. Each QUIC stream has independent flow control. Loss on one stream does not impose TCP-style delivery ordering on other streams. Streams still share connection flow control, congestion control, and network capacity.

Connection migration. QUIC connections are identified by a connection ID, not by the TCP 4-tuple (source IP, source port, destination IP, destination port). When an endpoint moves between networks – Wi-Fi to cellular, one access point to another – the connection can continue if a usable new path is available.

Built-in encryption. QUIC mandates TLS 1.3. In iroh, the TLS handshake authenticates both endpoints using their ed25519 keys. Every connection is end-to-end encrypted and mutually authenticated by construction.

Multiplexed streams. A single QUIC connection supports many concurrent streams. Ordinary Aster calls use one stream per RPC. Session-scoped services carry a session ID across call streams. Concurrent streams share connection resources.

Iroh attempts to establish a direct path between endpoints, including endpoints behind NATs. Network and firewall policy determine which paths are available.

Hole-punching. When two endpoints want to connect, iroh coordinates a simultaneous connection attempt that allows both NATs to create the necessary mappings. Some NAT and firewall configurations prevent direct connectivity.

Relay fallback. When hole-punching fails – for example, behind symmetric NATs or restrictive corporate firewalls – iroh falls back to relay servers. Relay servers forward encrypted QUIC packets between endpoints. Relays forward end-to-end encrypted traffic; they do not receive the application plaintext. They can observe connection metadata.

Path upgrades. iroh continuously attempts to establish direct connections even when using a relay. If network conditions change and a direct path becomes available, iroh transparently migrates the connection. A path upgrade can preserve the existing connection.

An EndpointId identifies who you want to reach. An aster address tells the transport how to find them. Aster uses a compact aster1... format that encodes the endpoint identity and available network hints:

aster14TudWqdmQLgjyczpq19BnP8f4FNF68bp8YBvGa51GFEqi5rnPWYAfhbTVA3SvNXfNeoaQJVTC

This single string encodes:

  • The endpoint’s ed25519 public key (EndpointId)
  • A relay server address (for NAT traversal)
  • Direct IP addresses (for LAN connectivity)

The high-level Python server exposes the address for a client to use. This API fragment assumes the service and imports from the Python quickstart; copy the actual printed address into the consumer:

# Producer
async with AsterServer(services=[MyService()]) as srv:
print(srv.address) # aster14TudW...
# Consumer
async with AsterClient(address="<actual printed aster1 address>") as client:
... # make calls while the connection is owned by this context

The aster1 prefix is a human-readable marker. The rest is base58-encoded binary containing the endpoint identity and network hints. The address contains no secret key; its length depends on the included hints.

QUIC connections use ALPN (Application-Layer Protocol Negotiation) to agree on which protocol to speak. iroh supports multiple ALPNs on a single endpoint:

  • aster/1 – the Aster RPC protocol
  • Blob protocol (aster::alpns::BLOBS) – content-addressed blob transfer
  • Document protocol (aster::alpns::DOCS) – document replication used by the registry
  • Gossip protocol (aster::alpns::GOSSIP) – pub-sub messaging
  • aster.consumer_admission – consumer enrollment (direct credentials)

Use the SDK protocol constants when registering or dialing built-in data protocols; library names are not their literal ALPN bytes. A single iroh endpoint can serve the configured protocols simultaneously. ALPN selects a protocol for each QUIC connection. RPC, blob transfers, and gossip use protocol-specific connections to the same endpoint.

The listed admission protocols belong to the high-level Python enrollment workflow. Python does not implement producer mesh admission and rejects allow_all_producers=False. Rust and other bindings expose their own policy integration; do not assume they perform the Python handshake.

In the Python workflow, aster.consumer_admission verifies consumer credentials signed by the operator’s root key before RPC begins. Python does not register or handle delegated admission (aster.admission); a token issued by @aster cannot admit a consumer to a Python producer. Use direct consumer-admission credentials instead. Registry publication and access records do not install that missing protocol handler.

Aster runs as a unified node: a single iroh endpoint that serves RPC, blobs, documents, and gossip. There is no separate “blob server” or “gossip server.” All capabilities share the same endpoint identity, protocol-specific QUIC connections, and the same NAT traversal infrastructure.

This means a service that needs to transfer large files can use iroh-blobs alongside its RPC methods. A service that needs real-time notifications can use iroh-gossip. A service that needs replicated state can use iroh-docs. All of these use the same EndpointId and protocol-specific connections.

Most applications should leave the QUIC transport defaults alone. For high-throughput servers, Aster exposes a small set of endpoint-level knobs through EndpointConfig / AsterConfig: concurrent stream limits, stream and connection receive windows, send window, idle timeout, keep-alive interval, initial MTU, datagram buffers, send fairness, and segmentation offload.

These settings are process-local. A server daemon can set them before creating its iroh endpoint, and they take effect for that endpoint only. They do not change host networking policy.

Host-level tuning is separate:

  • Linux UDP buffer ceilings, NIC offload policy, firewall rules, and file descriptor limits are outside the daemon unless it is explicitly granted privileges.
  • macOS socket buffer ceilings and packet filter policy are host settings, not endpoint settings.
  • Windows firewall, QoS, and adapter offload settings are host or administrator policy.

The practical split is: put portable QUIC behavior in AsterConfig, and manage privileged OS/network settings with deployment tooling such as systemd units, launchd profiles, container security settings, Group Policy, or infrastructure automation.

The lifecycle of a connection:

  1. The caller knows the remote endpoint’s EndpointId (and optionally a relay URL or direct addresses).
  2. The caller dials the EndpointId with an ALPN (e.g., aster/1).
  3. iroh resolves the EndpointId to a network path – direct if possible, relayed if not.
  4. A QUIC handshake authenticates both endpoints using their ed25519 keys.
  5. The connection is established. Both sides can open streams.
  6. Each RPC call opens a new bidirectional QUIC stream on the existing connection.
  7. If the network path changes, QUIC can migrate to a reachable new path.

Address resolution may use configured discovery services. Endpoint authentication uses the expected public key; deployment authorization is a separate trust policy.

See configuration for endpoint and discovery settings.