I would like to migrate my two ziti routers from my private domain name to a public domain.
Can I simply change the configuration and enroll the routers manually?
config.yml:
-listeners.bindings.option.advertise: private.domain.name
+listeners.bindings.option.advertise: public.domain.name
-edge.csr.sans.dns: private.domain.name
+edge.csr.sans.dns: public.domain.name
ziti edge re-enroll edge-router router_n --jwt-output-file /tmp/router_n.jwt
ziti router enroll config.yml --jwt < (echo /tmp/router_n.jwt)
Here's the Linux router guide with a migration example: Router Deployment | OpenZiti
It's usually easiest to create a new router, and you may transplant a router's configuration YAML, private key, and certificates if you wish.
With ziti v1.5.0 and newer, you may run the router like ziti router run config.yml --extend
to renew the router's certificates. These are the default run arguments for the Linux, Docker, and Kubernetes distributions of Ziti. The new server certificate will have the new SAN(s) based on the advertised address(es) and any additional SANs in your config.yml.
There's no need to perform the re-enroll operation unless both are true:
- you have lost the router's identity private key and certificates, or the certificates are expired
- your router policies pin the specific name of the
@router
and are not using #role-attributes
Creating a new router is the fastest way. You are right.
Can a router have multiple domain names/IP addresses:
ZITI_ROUTER_ADVERTISED_ADDRESS= domain1 domain2 ... domain_n
$ dig domain_j +short
ip_j
The one-shot configurator included with most distributions of the ziti router accepts a single router address. However, you can always craft a router configuration YAML file with any number of edge and link listeners, each with its respective unique address. Many listeners can share a TCP port as long as they can be distinguished by protocol (e.g., ziti-edge, ziti-link) and address (e.g., domain, IP).
I added the second ip address to the listeners. I tried also to start edge listeners on different ports. In all cases zrok-agent connects to only one ip address (ip_2) for a given router. However this warning says me the opposite: the only ip_1 will be used.
this is not supported. Advertise domain.name_1:4465 will be used for all protocols","time":"2025-04-24T05:35:12.585Z"}
listeners:
# bindings of edge and tunnel requires an "edge" section below
- binding: edge
address: tls:ip_1:4465
options:
advertise:domain.name_1:4465
connectTimeoutMs: 5000
getSessionTimeout: 60
- binding: edge
address: tls:ip_2:4465
options:
advertise: domain.name_2:4465
connectTimeoutMs: 5000
getSessionTimeout: 60
- binding: tunnel
options:
mode: host #tproxy|host
edge:
csr:
country: US
province: NC
locality: Charlotte
organization: NetFoundry
organizationalUnit: Ziti
sans:
dns:
- localhost
- domain.name_1
- domain.name_2
ip:
- "127.0.0.1"
- "::1"
this router is configured to use different hostnames for different edge listeners. If the controller is v0.26.3 or earlier this is not supported. Advertise %s will be used for all protocols
from: ziti/router/handler_edge_ctrl/hello.go at v1.5.4 · openziti/ziti · GitHub
This harmless warning does not apply to your scenario.
Agree.
But zrok-agent sees only the last address ip_2/domain.name_2.
The ziti network dislikes my configuration of the router. It makes sense if each ip has its own cost, precisely the cost of the router.
Thus I came to a conclusion that I need to create a router for each external ip_n/domain.name_n.
Is it enough to have a single link listener if all the routers are on the same machine attached to the same controller?
You expected the zrok agent to maintain TCP connections (ziti-edge
) to all authorized routers, but it has only one concurrent connection to the domain name of the second edge listener you added to the router, correct?
To clarify, router-to-router "links" form the Ziti fabric, and identiy-to-router "edge" connections are formed by enabled zrok environments which use the Ziti Edge SDK to access and share Ziti services orchestrated by zrok.
So, routers may advertise zero or more addresses on which they are listening for other routers dialing to form fabric links, and routers may advertise zero or more addresses on which they are listening for Ziti identities, e.g., enabled zrok environments, dialing to form edge connections.
The main reason that comes to mind for advertising multiple addresses for the same type of listener is to eliminate a single point of failure, like a scenario with redundant ISP circuits routed to discrete interface addresses on the host.
I expected the zrok-agent connects to all available ip (if it can). But after adding the listener on another ip_2/domain.name_2 the zrok-agent connects to only the last added domain.name_2.
So if your network, say in Europe, you need only one link router 
You are right. Not all people live in US/Europe. so for them the privacy of the connection is one of major concerns. There is another one: ISPs cut at random the network connections making the communication painful. A given ip can be unavailable for hours, then it comes back to life. I have several ips ranges and different hosts.
Zrok/zitti will work like a charm. I will add a router for each ip on all hosts. This way if one ip range becomes unavailable i can simply stop the router but keep all others alive (double green).
There is a single point of failure. It is apiEndpoint. It would be much easier if zrok-agent could read DNS SRV record.
Hopefully apiEndpoint is not needed frequently.
You're describing the behavior of the Ziti Edge SDK in a scenario where it is authorized to use a router that advertises two Edge listeners, and is connecting to only the second listener.
It may automatically switch to the other listener if the current connection fails. Additionally, a recent update has been implemented to utilize multiple connections, so you may notice this behavior change the next time you upgrade.
All routers will continually attempt to form links until a full mesh is established with one bi-directional link per pair of routers.
I don't think it will be necessary to intervene. The Ziti network should handle this automatically, routing traffic via the best available path, assuming you have placed router listeners carefully to avoid single points of failure.
I still think you can eliminate this SPoF with a horizontal array of zrok controllers like we sketched out in Ziti-router: no network interface found for 0.0.0.0 - #8 by qrkourier
I can not afford me to deploy only one zrok controller on a single VPS provider regardless how huge its network is. On the zrok-agent side I have to put an url into apiEndpont property.
In case the ip address referenced by the url becomes unavailable I need to manually change the DNS record, isn't it? Can I put a list of urls into apiEndpont?
Unfortunately zrok-agent will be installed many thousand miles from me. I will never have access to it.
This scenario is part of DNS SRV specification. But only a few of applications do this.
Yes, SRV records would be helpful in this case.
For now, each zrok agent is configured with a single apiEndpoint.
If you have multiple zrok controllers sharing a PostgreSQL instance, the apiEndpoint could be directional/regional DNS name, round robin DNS, load balancer, or a single zrok controller.
If your zrok controller IP addresses will change infrequently, you might do well with a simple DNS round robin. If all controllers are hosted in the same cloud provider you could use that provider's API gateway or cloud endpoint service for HA LB.
There is a routing issue in the data center where my HA ziti controller is deployed. The controller is unreachable for ziti routers. Zrok does not work any more.
Since the zrok (v1.0.4) environment references the controller's domain name I am asking my self what can be done to bring the network to life. How my second HA node can help me
ziti agent cluster list
╭────┬───────────────────────────────┬───────┬────────┬─────────────────┬───────────╮
│ ID │ ADDRESS │ VOTER │ LEADER │ VERSION │ CONNECTED │
├────┼───────────────────────────────┼───────┼────────┼─────────────────┼───────────┤
│ id │ tls:primary.controller:port │ true │ false │ <not connected> │ false │
╰────┴───────────────────────────────┴───────┴────────┴─────────────────┴───────────╯
To review our findings here in the forum, we discovered that zrok does not yet support ziti clustered mode. However, you observed it may work when there's only one ziti controller node. Officially, we don't expect zrok to work yet with the ziti clustered beta, so you may have discovered a situation where even a ziti cluster with a single node does not work with zrok for some reason.
I see only one ziti controller in your paste, and I understand you have a routing problem for packets sent by a ziti router to a ziti controller, but there's not enough information to understand the problem, or how a ziti or zrok configuration change might help.
Generally, your ziti routers need a ziti controller endpoint address for their first connection. Then, they'll "learn" ziti controller addresses automatically as the cluster grows. The new endpoints are saved in an endpoints.yml file adjacent the routers' config.yml files.
Initially I installed 2 HA ziti controllers.
But I was unable to make zrok works with two HA ziti controllers.
So I turned off one of them, and installed all routers, zrok on the primary controller (leader).
Then the data center where the primary controller is hosted got a network issue (down time=12 hours).
By now they have resolved the issue => My ziti network is back to life!
The command ziti agent cluster list was executed on the secondary HA controller. The secondary is not the leader, has no routers and only replicates the state of the primary controller who was not reachable.
Looking at .zrok/identities/environment.json I understand that it was impossible to make my ziti network work without access to the primary controller.
{"ztAPI":"https://primary.controller:port/edge/client/v1","ztAPIs":null,"configTypes":null,"id":....}