zrok v2.0.0 - Namespaces and Names
Overview
zrok v2.0.0 represents a major evolution of the platform, introducing a fundamental paradigm shift in how sharing and naming work. This release replaces the reserved sharing model with a more powerful and flexible namespaces and names system, adds a new distributed dynamicProxy frontend architecture, and includes significant improvements to the zrok Agent.
This is a major version release with breaking changes. The zrok reserve, zrok release, and zrok share reserved commands have been removed. Please review the Migration Guide section below and the comprehensive v2 Migration Guide for details.
What's New in v2.0
- Namespaces and Names: logical grouping of share names similar to DNS zones, replacing reserved shares
- Dynamic Proxy Frontend: new AMQP-based distributed frontend with real-time mapping updates
- Enhanced Agent: automatic retry with exponential backoff, improved error handling, and persistent shares
- Private Share Tokens: vanity tokens for private shares using
--share-token - Name Modification: ability to "upgrade" ephemeral names to reserved names on the fly
- Improved CLI: human-readable default output for
zrok overview, better error messages - Modernized Logging: migrated from logrus to structured logging with slog
Breaking Changes
Removed Commands
The following commands no longer exist in v2.0:
zrok reserve public <target> # use: zrok create name + zrok share public -n
zrok reserve private <target> # use: zrok share private --share-token
zrok share reserved <token> # use: zrok share public/private -n <namespaceToken>:<name>
zrok release <token> # use: zrok delete name
zrok overview public-frontends # use: zrok list namespaces
See the Command Migration Reference below for detailed replacements.
Configuration Changes
defaultFrontend→defaultNamespace: the configuration key has been renamed and now specifies the default namespace token rather than frontend- Update with:
zrok config set defaultNamespace <namespaceToken> - Environment variable:
ZROK_DEFAULT_NAMESPACE
- Update with:
API Endpoint Changes
For developers using the zrok API:
/reserveendpoint removed/releaseendpoint removed/shareendpoint now acceptsnameSelectionsarray instead ofshareModeandfrontendSelection/overviewendpoint enhanced withnamesandnamespacesinformation/metadata/publicFrontendsForAccountremoved (replaced with namespace system)
See the API Changes section for complete details.
Major Features
Namespaces and Names System
The core architectural change in v2.0 replaces "reserved shares" with a two-level naming hierarchy:
Namespaces
Namespaces are logical groupings for names, analogous to DNS zones. Each namespace:
- Has a token (identifier) like
publicorcustom-domain - Has a name (DNS zone) like
share.zrok.ioorexample.com - Can be open (anyone can create names) or closed (requires grants)
- Maps to one or more frontend instances
Names
Names are unique identifiers within a namespace, analogous to DNS A records. Each name:
- Exists within a namespace (e.g.,
myappin thepublicnamespace) - Can be reserved (persistent across shares) or ephemeral (temporary)
- Can be assigned to shares using the
-n <namespace>:<name>flag - Supports multiple names per share
Example Workflow
# list available namespaces
$ zrok list namespaces
╭───────────────────────┬─────────────────┬─────────────╮
│ NAME │ NAMESPACE TOKEN │ DESCRIPTION │
├───────────────────────┼─────────────────┼─────────────┤
│ share.zrok.io │ public │ │
╰───────────────────────┴─────────────────┴─────────────╯
# create a reserved name
$ zrok create name -n public myapp
name 'myapp' created in namespace 'public'
# share using the name (the name persists across share restarts)
$ zrok share public http://localhost:8080 -n public:myapp
your reserved name is: http://myapp.share.zrok.io
# list your names
$ zrok list names
╭───────────────────────────┬────────┬───────────┬─────────────┬──────────┬─────────────────────╮
│ URL │ NAME │ NAMESPACE │ SHARE TOKEN │ RESERVED │ CREATED │
├───────────────────────────┼────────┼───────────┼─────────────┼──────────┼─────────────────────┤
│ myapp.share.zrok.io │ myapp │ public │ │ true │ 2025-10-23 10:15:42 │
╰───────────────────────────┴────────┴───────────┴─────────────┴──────────┴─────────────────────╯
# modify name to toggle reserved status
$ zrok modify name -n public myapp -r=false
name 'myapp' will be released when associated share terminates
# delete the name
$ zrok delete name -n public myapp
Benefits over v1.x reserved shares:
- Decouples external names from environments and backends
- Supports multiple names per share
- Easier to move shares between hosts
- More flexible namespace management and access control
- Better aligns with DNS concepts most users understand
Dynamic Proxy Frontend
A new distributed frontend architecture replaces the legacy publicProxy (zrok access public) with dynamicProxy (zrok access dynamicProxy).
Architecture
The dynamic proxy system consists of three components:
-
dynamicProxyController (in zrok controller)
- gRPC service for mapping queries from frontends
- AMQP publisher for broadcasting mapping updates
- Manages namespace/name to share mappings
-
AMQP Message Broker (RabbitMQ)
- Distributes real-time mapping updates
- Enables synchronization across multiple frontend instances
- Topic exchange for efficient routing
-
dynamicProxy Frontend (via
zrok access dynamicProxy)- HTTP/HTTPS listener serving dynamic mappings
- AMQP subscriber receiving updates
- gRPC client for initial and on-demand mapping queries
- OAuth integration support
Key Improvements
- Real-time updates: frontends receive mapping changes via AMQP immediately
- Horizontal scalability: multiple frontend instances can serve the same namespace
- Namespace-based routing: supports complex multi-domain setups
- Better isolation: different namespaces can use different frontend instances
- Consistent OAuth: full OAuth support integrated into the new architecture
Configuration Example
v: 1
frontend_token: KMmfE0VXO7Pp
identity: public
bind_address: "0.0.0.0:8080"
amqp_subscriber:
url: amqp://guest:guest@localhost:5672
exchange_name: dynamicProxy
controller:
identity_path: /home/zrok/.zrok/identities/public.json
service_name: dynamicProxyController
# optional: OAuth, TLS, interstitial page
oauth:
bind_address: "0.0.0.0:8181"
endpoint_url: "https://oauth.example.com"
# ... provider configuration
Migration note: the legacy publicProxy remains available for backward compatibility but will be deprecated in a future release. See the Dynamic Proxy Migration Guide for detailed setup instructions.
Agent Improvements
The zrok Agent received significant enhancements in v2.0:
Retry Manager
Automatic retry with exponential backoff for failed processes:
- Failed shares/accesses automatically retry
- Exponential backoff prevents rapid failure loops
- Configurable maximum retry attempts
- Errored processes receive transient
err_XXXXtokens for management
# view agent status showing failed process with retry state
$ zrok agent status
...
# release the errored process
$ zrok rm err_abc123
Boot Handler
Unified handler for persistent shares and accesses:
- Shares with reserved name selections automatically restart after agent restart
- Private shares with
--share-tokenpersist across agent restarts - Boot handler rebuilds the process tree on startup
- Improved subprocess lifecycle management
# when agent running, this share persists across agent restarts
$ zrok share public http://localhost:3000 -n public:myapp
# private share with --share-token also persists
$ zrok share private http://localhost:3000 --share-token myapi
Improved Status Display
The zrok agent status command now shows:
- Detailed error states and failure information
- Frontend endpoints for public shares
- Retry attempt counts and next retry time
- Active, pending, and failed processes
- Process uptime and restart counts
Private Share Vanity Tokens
Private shares now support custom "vanity" tokens via the --share-token flag:
# create a private share with a memorable token
$ zrok share private http://localhost:8080 --share-token myapi-prod
# access from another environment
$ zrok access private myapi-prod
Benefits:
- Memorable, meaningful share names
- Persistent tokens when using the agent
- Easier sharing with team members
- Better than random generated tokens for long-lived services
Note: unlike reserved names in namespaces (which are global), share tokens are scoped to your zrok account.
Name Modification Command
New zrok modify name command allows toggling the reserved status of a name:
# upgrade an ephemeral name to reserved (persist it)
$ zrok modify name -n public myapp -r
# downgrade a reserved name to ephemeral (release when share terminates)
$ zrok modify name -n public myapp -r=false
Use case: you start sharing something ephemerally, realize you want to keep the name, and can "upgrade" it without recreating the share. (https://github.com/openziti/zrok/issues/1066)
Human-Readable Overview
The zrok overview command now outputs a formatted, human-readable display by default:
$ zrok overview
* Namespaces
╭───────────────────────┬─────────────┬────────────────╮
│ NAME │ DESCRIPTION │ TOKEN │
├───────────────────────┼─────────────┼────────────────┤
│ names.staging.zrok.io │ │ public │
│ stack.dasl.dev │ │ stack.dasl.dev │
╰───────────────────────┴─────────────┴────────────────╯
* Names
╭──────── ──────────────────┬─────────────────┬──────────────┬──────────┬─────────────────────╮
│ URL │ NAMESPACE TOKEN │ SHARE TOKEN │ RESERVED │ CREATED │
├──────────────────────────┼─────────────────┼──────────────┼──────────┼─────────────────────┤
│ api.example.com │ example.com │ - │ true │ 2025-10-23 12:31:10 │
│ testing.example.com │ example.com │ jr6zuvicaun9 │ true │ 2025-10-23 11:52:21 │
╰──────────────────────────┴─────────────────┴──────────────┴──────────┴─────────────────────╯
* Environments
╔══ ══════════════════════───────────────────────
> user@linux (envZId: LT.yW-YiYc)
Host: user; linux; linux; ubuntu; debian; 25.04; 6.14.0-34-generic; x86_64
Address: ...
Created: 2025-10-23 11:43:23
> Shares
╭──────────────┬────────┬─────────┬───────────────────────┬─────────┬─────────────────────╮
│ SHARE TOKEN │ MODE │ BACKEND │ TARGET │ LIMITED │ CREATED │
├──────────────┼────────┼─────────┼───────────────────────┼─────────┼─────────────────────┤
│ jr6zuvicaun9 │ public │ proxy │ http://localhost:8585 │ │ 2025-10-23 12:06:18 │
╰──────────────┴────────┴─────────┴───────────────────────┴─────────┴─────────────────────╯
> jr6zuvicaun9:
> testing.example.com
╚════════════════════════───────────────────────
╔════════════════════════───────────────────────
> user@otherhost (envZId: PE9JTm0iYc)
Host: user; otherhost; linux; ubuntu; debian; 25.04; 6.14.0-34-generic; x86_64
Address: ...
Created: 2025-10-23 12:30:04
╚══ ══════════════════════───────────────────────
For the classic JSON output, use --json:
$ zrok overview --json
(https://github.com/openziti/zrok/issues/1064)
Technical Changes
This section provides detailed technical information for developers and self-hosters.
Database Migrations
Five new migrations added (034-038):
-
034_v2_0_0_namespaces.sql- Creates
namespacestable (token, name, description, open mode, timestamps) - Creates
namespace_grantstable (namespace ↔ account many-to-many) - Tracks namespace access control for closed namespaces
- Creates
-
035_v2_0_0_namespace_frontend_mappings.sql- Creates
namespace_frontend_mappingstable - Links namespaces to frontend instances
- Enables multiple frontends per namespace for load balancing
- Creates
-
036_v2_0_0_dynamic_frontends.sql- Adds
dynamicboolean column tofrontendstable - Distinguishes dynamicProxy frontends from legacy publicProxy
- Adds
-
037_v2_0_0_frontend_mappings.sql- Creates
frontend_mappingstable - Caches namespace/name to frontend mappings
- Improves lookup performance for dynamicProxy
- Creates
-
038_v2_0_0_frontend_public_name_unique.sql- Adds unique constraint on
frontends.public_name(when not deleted) - Prevents duplicate frontend public names
- Adds unique constraint on
Migration management:
# automatic migration on controller start (default)
zrok controller etc/ctrl.yml
# manual migration
zrok admin migrate
# rollback support (new in v2.0)
zrok admin migrate --down 1
API Changes
New Endpoints
Namespace Management (Admin):
POST /admin/namespace- create namespaceGET /admin/namespace- list all namespacesPUT /admin/namespace/{namespaceToken}- update namespaceDELETE /admin/namespace/{namespaceToken}- delete namespace
Namespace Grants (Admin):
POST /admin/namespaceGrant- grant user access to closed namespaceGET /admin/namespaceGrant/{namespaceToken}- list grants for namespaceDELETE /admin/namespaceGrant- revoke namespace grant
Namespace-Frontend Mappings (Admin):
POST /admin/namespaceFrontendMapping- map namespace to frontendGET /admin/namespaceFrontendMapping/{namespaceToken}- list frontends for namespaceGET /admin/frontendNamespaceMapping/{frontendToken}- list namespaces for frontendDELETE /admin/namespaceFrontendMapping- remove mapping
Name Management (End Users):
POST /share/name- create name in namespaceGET /share/name- list user's namesPUT /share/name- update name (toggle reserved status)DELETE /share/name/{nameToken}- delete name
Namespace Discovery (End Users):
GET /share/namespace- list available namespaces (based on grants and open namespaces)
Modified Endpoints
POST /share - create share:
- Added
nameSelectionsarray parameter (replacesshareModeandfrontendSelection) - Each name selection specifies:
namespaceToken,name,reserved - Supports multiple names per share
- Example:
{
"envZId": "abc123",
"shareMode": "public",
"nameSelections": [
{"namespaceToken": "public", "name": "myapp", "reserved": true},
{"namespaceToken": "public", "name": "myapp-staging", "reserved": false}
],
"backendMode": "proxy",
"backendProxyEndpoint": "http://localhost:8080"
}
GET /overview - get account overview:
- Added
namesarray to share details - Added
namespacesarray to account details - Includes reserved status and namespace information
- Enhanced with name-related metadata
Removed Endpoints
/reserve- replaced with/share/name(create name) +/share(create share with name selection)/release- replaced withDELETE /share/name/{nameToken}/metadata/publicFrontendsForAccount- replaced with/share/namespace(list available namespaces)
gRPC API (dynamicProxyController)
New gRPC service for controller ↔ dynamicProxy communication:
service DynamicProxyController {
// query mappings for a specific namespace
rpc GetNamespaceFrontendMappings(NamespaceRequest) returns (MappingsResponse);
// query mapping for a specific name
rpc GetNameMapping(NameRequest) returns (NameMappingResponse);
}
Implemented in controller/dynamicProxyController/grpc.go.
Ziti Automation Refactoring
The OpenZiti resource management code was completely rewritten:
Old: controller/zrokEdgeSdk/ (legacy, complex, hard to maintain)
New: controller/automation/ (streamlined, clear, maintainable)
Key Improvements
- Consistent CRUD interfaces for all resource types
- Resource managers:
IdentityManager,ServiceManager,ConfigManager, etc. - Tag-based resource management for cleanup and filtering
- Better error handling with
AutomationErrortype - Centralized client creation and authentication
- Clearer separation of concerns