Introducing zrok v2.0
Decoupling names from shares. A more powerful conceptual model for zrok.

Today we're releasing zrok v2.0.0, and I'm really excited about it.
When we shipped v1.0 last year, it was about proving that zrok was production-ready... a solid foundation with a redesigned web console, a new zrok Agent, and all the infrastructure that a serious release needs. v2.0 is a different kind of milestone. This release is about rethinking the conceptual model where it was weakest and building a much more powerful foundation for what comes next.
In case you're not sure what zrok is, take a look at the post introducing zrok. zrok is all about making powerful, secure, peer-to-peer sharing work in a simple way... network resources, files, applications, all with a single command. zrok is open source, self-hostable, and built on top of OpenZiti. It's developed by NetFoundry, and there's a free hosted instance available at zrok.io.
For those of you who prefer video, I did a zrok Office Hours previewing the v2.0 changes a while back that is still very relevant:
https://www.youtube.com/watch?v=iJfWj7umdFI
Let's dig in...
The One Main Issue: Namespaces and Names
The headline change in v2.0 is that reserved sharing is gone. The zrok reserve, zrok release, and zrok share reserved commands have been removed entirely, replaced by a new system of namespaces and names.
This is a major conceptual shift, and I think it's the right one. Here's why.
In the old model, share tokens did double duty as public identifiers. Your share token was the name that the outside world used to reach your share. That seems fine until you realize that share tokens are tied to shares, and shares are tied to environments, which means they're tied to a specific host system and a specific account.
This created real operational problems. Want to move a named share to a different machine? You couldn't do it without disrupting the public name that people were using to reach it. If you stop and think about it, this is a pretty significant limitation for anything beyond casual use.
In v2.0, names are decoupled from shares. You create names, and then you attach those names to shares. If you need to move the sharing backend to a different environment, you just detach the name from the old share and attach it to the new one. The public-facing identity stays stable. Your users never notice.
Namespaces provide the organizational layer above names, giving you logical grouping and scoping. The combination is dramatically more flexible than what reserved sharing could ever offer.
For the full details on how namespaces and names work, see the zrok v2 Migration Guide. But here's the practical upshot: anything you could do with reserved sharing, you can do with namespaces and names... and a lot of things you couldn't do before are now straightforward.
Try It, Then Keep It
One of my favorite new features is zrok2 modify name. It solves a workflow problem that has always bugged me.
Previously, you had to decide up front whether a share was going to be ephemeral or reserved. If you shared something ephemerally and then realized you wanted to keep it around, you had to tear it down and recreate it as a reserved share. With zrok2 modify name -r you can just promote an ephemeral name to a reserved name on the fly. It persists indefinitely, or until you decide otherwise. Conversely, zrok2 modify name -r=false will schedule a reserved name for release when its associated share terminates.
Ephemeral by default, persistent by choice. That's the workflow I always envisioned.
Private Share Allocation
Now that reserved sharing has been replaced with namespaces, and all shares are effectively ephemeral (while reserved names are not)... where does this leave private sharing?
Private sharing is still one of zrok's super powers. Private shares still use share tokens as identifiers in the same way they always have. But in v1.0, the zrok reserve command was doing double-duty for both public share names and private share tokens. So how does v2.0 handle this?
In v2.0 you can use zrok2 create share and zrok2 delete share to pre-allocate and manage shares for private sharing. This is a streamlined replacement for v1.0's zrok reserve and zrok release commands. The zrok2 share private command includes a --share-token flag that lets you start sharing using an existing pre-allocated share, in the same way that zrok share reserved worked in v1.0. You can also use --share-token to give your private shares human-readable vanity names that are easy to remember and share with collaborators.
Side-by-Side: Running v1 and v2 Together
We made a deliberate decision with v2.0: no forced migration. You can run zrok v1 and zrok v2 on the same system simultaneously, with zero interference between them.
The binary is now called zrok2 instead of zrok. The environment directory is ~/.zrok2 instead of ~/.zrok. Environment variables use the ZROK2_ prefix instead of ZROK_. Linux packages are zrok2 and zrok2-agent, the systemd service is zrok2-agent.service, and configuration lives in /etc/zrok2.
This means you can install v2 alongside your existing v1 setup, experiment with the new namespace model, and migrate at your own pace. Your existing v1 environment is completely untouched. When you run zrok2 enable, it creates a fresh environment in ~/.zrok2... nothing in ~/.zrok is affected.
When you're comfortable and ready to make the switch, just stop using the zrok binary and switch to zrok2. That's it.
Web Console Improvements
The web console received a significant overhaul for v2.0. The node graph layout has been drastically improved... the visual network navigator is cleaner and more intuitive. Under the hood, the internals have been cleaned up and refactored.
There are some nice new interaction features too. A new focus mode lets you press F on the keyboard to focus the graph on just the nodes reachable from your current selection, cutting through the noise when you're working with larger configurations. The detail panel can now be toggled on and off, giving you more screen real estate when you need it.
Overall the web console received a solid dose of attention and cleanup.
The New dynamicProxy Frontend
For self-hosters, v2.0 introduces zrok2 access dynamicProxy, a new frontend implementation designed to work with the namespace/names model.
The previous publicProxy frontend worked by parsing the Host header and extracting a share token. That approach was tightly coupled to the old model where share tokens were the public identifiers. The new dynamicProxy receives mapping updates directly from the zrok controller, allowing it to support any kind of mapped name, not just share tokens extracted from headers.
zrok2 access public remains available for legacy-style setups, so existing self-hosted deployments aren't disrupted. See the zrok dynamicProxy Guide for details on setting up the new frontend.
Agent Improvements
The zrok Agent continues to mature. In v2.0, it includes significantly improved error handling for subordinate processes. When shares or accesses encounter errors, whether during agent reloading or during active runtime, they're now retried using an exponential backoff approach rather than failing hard. Errored processes get transient err_XXXX tokens, which you can use to manage and release them through the normal agent interface. This makes the agent much more resilient in production environments where transient failures are a fact of life.
The agent has also been updated for the v2 naming model. Any share with a reserved name will be automatically restarted by the agent, giving you the persistence behavior you'd expect without manual intervention.
CLI Quality of Life
v2.0 includes a set of new commands that make working with your zrok account much more pleasant.
New zrok2 list commands for names, namespaces, environments, shares, and accesses let you query everything in your account. They support filtering on activity, accesses, shares, descriptions, host, IP address, and other criteria. Human-readable tabular output by default, with --json when you need machine-readable output.
zrok2 overview now defaults to a human-readable format that lays out your account details clearly. The classic JSON output is still available with --json.
zrok2 delete environment lets you clean up environments other than your currently enabled one. Pair it with zrok2 list environments --idle to find and remove stale environments.
Under the Hood
For those who care about the internals... v2.0 includes a complete overhaul of the core OpenZiti automation logic. The legacy controller/zrokEdgeSdk package has been replaced with a much more streamlined controller/automation package. If you've ever had to read through the controller code, this is a significant clarity improvement.
All logging has been migrated from pfxlog/logrus to df/dl and log/slog. Use DL_USE_JSON=true for JSON output or DL_USE_COLOR for colorized output.
The root package path has moved to github.com/openziti/zrok/v2 to follow Go's v2+ package naming conventions.
Get Started
To try zrok 2.0, grab a zrok2 binary from the releases page and run zrok2 enable to create a new v2 environment. Your existing v1 setup will remain completely untouched.
For the full details on migrating from v1 to v2, see the zrok v2 Migration Guide.
Thank You
Thank you for supporting zrok. We're really excited about where the v2.0 roadmap takes us... namespaces and names open up a lot of possibilities that we're already exploring for future releases.
If you like zrok, it's always very much appreciated if you take a moment to drop a star onto the zrok repository on GitHub. We literally see and appreciate every repository star. If zrok is an important part of your workflow, maybe consider getting a subscription on zrok.io? Those subscriptions are an incredibly helpful signal that we're on the right track.
If there is anything we can do to improve zrok or if you've run into anything we can help with, please reach out to us at our OpenZiti Discourse forum. There is a zrok category, and we're standing by ready to help.



