evbogue.com

Get evbogue.com in your inbox.

One essay, three stories, no noise.

Monday, June 15, 2026  ·  Augmented publishing by Ev BogueEv Bogue
Anproto

What If iroh Is the Network I Bring?

iroh 1.0 shipped with the one idea I care about: dial the key, not the IP. Then I held it against the library I already use, and the browser made the answer complicated.


iroh 1.0 shipped today, and it leads with the line I have been building toward for years: IP addresses break, dial keys instead. You address a peer by its ed25519 public key, iroh figures out where that key actually is and hole-punches a direct QUIC connection, and only falls back to a relay when it has to. It went up on Hacker News this morning. My first instinct, the reflex of anyone who maintains a protocol, was to go find the catch.

The catch is real, and it lives in the browser. A browser tab cannot send raw UDP, so iroh's hole-punching can't run inside one. Per iroh's own writeup, browser iroh runs in relay-only mode: every byte goes through a relay over a WebSocket, and by default that relay is infrastructure run by n0, the company behind iroh. Even discovery defaults to their DNS server. So the project whose whole pitch is the direct connection becomes, in the one place most people actually run software, a connection that always passes through somebody's server.

I was most of the way into writing the dismissive version of this post when I realized I was wrong about my own protocol.

ANProto separates authentication from transport on purpose. A message is a timestamp, a content hash, and an ed25519 signature, and nothing about it trusts the wire it travels on. The whole design philosophy is bring your own network. Which means the relay objection I was sharpening does not apply to ANProto at all. The relay cannot read a signed, end-to-end-encrypted ANProto message, cannot forge one, cannot reorder authorship. It can only pass the bytes along. When the payload carries its own proof, it stops mattering who operates the pipe. The criticism that lands hard against a protocol that trusts its transport just slides off one that never did.

So the honest question is not whether iroh's relay dependency is a flaw. It is whether iroh is the network I should bring.

Look at what the two things actually are. ANProto is a trust layer: it answers who said this and is it intact. iroh is a connectivity layer: it answers where is this peer and how do I reach them through the NAT. Those are different jobs, and I have been quietly avoiding the second one for years because writing a reliable QUIC stack with NAT traversal and relay fallback is a miserable amount of work I have no desire to do.

They even share a primitive. An ANProto identity is an ed25519 key. An iroh node id is an ed25519 key. iroh lets you hand the endpoint builder your own secret key instead of generating a fresh one, so the same key that signs your ANProto messages can be the address you dial. Your identity and your network location collapse into one keypair. In the browser you call openBi on the connection, get a send and receive pair back, and write signed ANProto messages straight into the QUIC stream. The relay carries them blind.

Here is what I would actually try. Use the key I already have as the iroh node id, so author and address are the same thing. Let iroh move the bytes, since it is demonstrably better at NAT traversal than anything I would write. Run my own relay binary, which iroh ships as open source, or just use n0's, because the signatures mean I do not have to trust either one. And do discovery over the BitTorrent Mainline DHT rather than n0's DNS, which is the decentralized path iroh already supports. I have prior art for that last part: wiredove already rides the same Mainline DHT to bootstrap its browser connections.

It does that through Trystero, and Trystero is where this gets genuinely awkward for the case I am making. Trystero brokers WebRTC connections using public infrastructure for signaling, the Mainline DHT in wiredove's case, and then sends the app's data directly between tabs, end to end encrypted, never touching the signaling medium. Which means in the browser Trystero does the exact thing iroh cannot. The scrappy JavaScript library goes peer to peer where the heavyweight Rust QUIC stack falls back to a relay. If the direct connection is the whole point, Trystero already wins the browser.

So what would iroh actually buy me over the thing I already use? Two things. iroh carries a cryptographic ed25519 identity in the node id itself, and it runs one model across a server, a phone, and a browser tab. The first is half redundant for me, because ANProto already signs every message and supplies its own identity. The second is real: Trystero is browser-only, and it leans on a TURN server you have to run yourself for the peer pairs that cannot punch through, while iroh handles that reach natively. So the trade is honest and unresolved. Trystero gives me a direct browser connection today with no identity of its own and a TURN bill for the hard cases. iroh gives me identity I do not need, reach I do, and a relay in the one place I most want to avoid one. That is why the title of this post is a question and not a plan.

There is one more thing neither of them solves, and I want to be precise about it rather than paper over it. iroh relays connect peers who are both online. They are not mailboxes. Per the iroh FAQ, a relay routes traffic between live endpoints and then steps back once a direct path forms. If the peer you want is offline, the relay drops the message on the floor. Trystero is the same story, a live connection or nothing. And here is the honest part: my own stack does not close this gap either. apds and inproto give me the WebPush plumbing that wakes a client to go fetch what it missed, but WebPush is a doorbell, not a mailbox. The durable store that actually holds a message until an offline peer comes back is the thinnest part of everything I have built. iroh does not help there, Trystero does not help there, and neither do I yet. iroh moves bytes between peers who are both present, ANProto proves who said what, and where a message waits while you are gone is still an open problem on every side of this.

That is the part the version-number announcements never quite admit. No single project in this space hands you the whole stack. Trust is the settled layer: ANProto signs the message and the question of who said what is closed. Connectivity is the contested one, and iroh and Trystero are both real answers with opposite tradeoffs in the browser. Storage, where a message waits while you are offline, is the layer nobody has finished, me included. The interesting move is not to crown a winner at the connectivity layer. It is to treat that layer as swappable, sign everything so it does not matter who carries it, and go finish the part that is actually missing.

I have not built this yet. This is a builder thinking out loud after reading a release, not a working integration, and there are still things I would have to test before I trusted it. But the shape is right, and for the first time the networking layer I kept avoiding looks like something I could just bring.

If you have actually wired ANProto-style signed messages over iroh, or you can tell me why this falls apart in practice, I want to hear it. Email me at ev@evbogue.com or text 773-510-8601. Tell me where the seam splits.