Confused Adventures with Browzer

I am trying to configure the following:

  1. Controller and router on one host
  2. Browser on another
  3. Service on a third, this is a regular Apache2 on 80 and/or 443

The controller and router are deployed via qickstart with PKI_ALT*. Here’s my config with changed dns:

 v: 3
db:                     "/home/ubuntu/ziti_t2/db/ctrl.db"
identity:
cert:        "/home/ubuntu/ziti_t2/pki/ctrl.internal.domain.my-intermediate/certs/ctrl.internal.domain.my-client.chain.pem"
server_cert: "/home/ubuntu/ziti_t2/pki/ctrl.internal.domain.my-intermediate/certs/ctrl.internal.domain.my-server.chain.pem"
key:         "/home/ubuntu/ziti_t2/pki/ctrl.internal.domain.my-intermediate/keys/ctrl.internal.domain.my-server.key"
ca:          "/home/ubuntu/ziti_t2/pki/cas.pem"
alt_server_certs:
- server_cert:  "/etc/letsencrypt/live/internal.domain.my/fullchain.pem"
server_key:   "/etc/letsencrypt/live/internal.domain.my/privkey.pem"

ctrl:
options:
advertiseAddress: tls:ctrl.internal.domain.my:11281
listener:             tls:0.0.0.0:11281

healthChecks:
boltCheck:
interval: 30s
timeout: 20s
initialDelay: 30s

edge:
api:
sessionTimeout: 30m
address: ctrl.internal.domain.my:11282
enrollment:
signingCert:
cert: /home/ubuntu/ziti_t2/pki/signing.pem
key:  /home/ubuntu/ziti_t2/pki/zecontroller-signing-intermediate/keys/zecontroller-signing-intermediate.key
edgeIdentity:
duration: 180m
edgeRouter:
duration: 180m

web:

name: client-management
bindPoints:

interface: 0.0.0.0:11282
address: ctrl.internal.domain.my:11282
identity:
ca:          "/home/ubuntu/ziti_t2/pki/zecontroller-edge-controller-root-ca/certs/zecontroller-edge-controller-root-ca.cert"
key:         "/home/ubuntu/ziti_t2/pki/zecontroller-edge-controller-intermediate/keys/ctrl.internal.domain.my-server.key"
server_cert: "/home/ubuntu/ziti_t2/pki/zecontroller-edge-controller-intermediate/certs/ctrl.internal.domain.my-server.chain.pem"
cert:        "/home/ubuntu/ziti_t2/pki/zecontroller-edge-controller-intermediate/certs/ctrl.internal.domain.my-client.chain.pem"
alt_server_certs:

server_cert: "/etc/letsencrypt/live/internal.domain.my/fullchain.pem"
server_key:  "/etc/letsencrypt/live/internal.domain.my/privkey.pem"

I launch my Browzer instance like this:
docker run -d --name ziti-browzer-bootstrapper -v /etc/letsencrypt:/etc/letsencrypt -v ./2.log:/etc/2.log --user "${UID}:2171" -p 443:443 --env-file ./browzer.env Package ziti-browzer-bootstrapper · GitHub

With these envs:
NODE_ENV=production
#ZITI_BROWZER_OIDC_URL=https://keycloak.domain.my/realms/ziti
#ZITI_BROWZER_CLIENT_ID=openziti-client
ZITI_BROWZER_BOOTSTRAPPER_DISABLE_CSP=true
ZITI_BROWZER_BOOTSTRAPPER_LOG_PATH=/etc/2.log
ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT=443
ZITI_BROWZER_BOOTSTRAPPER_LOGLEVEL=debug
ZITI_BROWZER_RUNTIME_LOGLEVEL=debug
ZITI_BROWZER_RUNTIME_HOTKEY=alt+F12
ZITI_CONTROLLER_HOST=ctrl2.internal.domain.my
ZITI_CONTROLLER_PORT=11282
ZITI_BROWZER_BOOTSTRAPPER_HOST=znet.domain.my
ZITI_BROWZER_BOOTSTRAPPER_SCHEME=https
ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH=/etc/letsencrypt/live/znet.domain.my/fullchain.pem
ZITI_BROWZER_BOOTSTRAPPER_KEY_PATH=/etc/letsencrypt/live/znet.domain.my/privkey.pem
ZITI_BROWZER_BOOTSTRAPPER_TARGETS={"targetArray":[{"vhost": "znet.domain.my","service": "ubuntu","path": "/","scheme": "https","idp_issuer_base_url": "``https://keycloack.domain.my/realms/ziti","idp_client_id``": "openziti-client"}]}

Everything is up and running and seems to be working correctly:

  • I can log into ZAC via ctrl.internal.domain.my.
  • I can enroll JWTs created in ZAC on my Android device.
  • For the experiment, I used Android Ziti to connect to the service I want to provide via Browzer. No problems whatsoever.
  • When I open the Browzer host in Chrome, it redirects me to my login page in Keycloak.
  • After entering my credentials, Browzer starts performing some actions, which can be seen in the console.

But as a result after 5-10 seconds I see the following error:
TLS Handshake timeout connecting to Ziti Service [ubuntu]
Please verify that the destination server is listening on HTTPS

I tried using https on the ubuntu service, checked that the session was created correctly in SSO, and also tried changing the configurations in different ways. Unfortunately, neither the forum nor Google could help me find any useful information.

Please help and point me in the right direction, as I am new to this and cannot yet grasp all the subcommands and details of Ziti.

UPD. Inside router log i found:
Oct 19 11:43:23 zecontroller ziti[8501]: {"_context":"{c/ib4qz94IuGLkISBbUtPNg|@/6SOOgkEbwKV1nIt8SySgvL}\u003cInitiator\u003e","circuitId":"ib4qz94IuGLkISBbUtPNg","error":"cannot forward payload, no destination for circuit=ib4qz94IuGLkISBbUtPNg src=6SOOgkEbwKV1nIt8SySgvL dst=1bpAsvnspIUOzJ4Im3jGvj","file":"http://github.com/openziti/ziti/router/handler_xgress/data_plane.go:58","func":"github.com/openziti/ziti/router/handler_xgress.(*dataPlaneAdapter).ForwardPayload","level":"error","msg":"unable to forward payload","origin":0,"seq":5,"time":"2025-10-19T11:43:23.088Z"}

Hi @xaocmda, welcome to the community and to OpenZiti!

This seems to me to be a misconfiguration. Did youlook at the router logs to see if there's anything useful in them? The "unable to forward payload" in the controller definitely seems to agree.

I would:

  • check the host.v1 configuration of the service
  • make sure whatever identity is binding the service can access the target underlay service at whatever the host.v1 configuration specifies (i expect this is where it went wrong)
  • look at whatever identity is binding the service logs to see if there's any helpful errors are in there
  • check tcpdump/wireshark to see if the router is trying to dial your target service at all - sometimes the port is wrong etc.

hth

Thank you, I was able to solve this problem. It wasn’t very obvious, but changing the scheme to HTTP in the service definition for BrowZer helped fix it.

However, after I managed to resolve this issue, I found out that our frontend will soon start using service workers. As far as I understand, BrowZer also relies on service workers, which means my application might not be properly exposed through BrowZer.

Could you please confirm whether my understanding is correct?

Thanks for the awesome work you’re doing!

That's more a question for @curt since he's the browzer pro. I would think if you're using service workers, you might be able to just inspect how browzer is working and just tap in the same way that browzer did/does. That might even be more straightforward for you?

Thanks. I’m not strong on frontend/browser intricacies too :sweat_smile: . Let’s wait for Curt; maybe he can suggest a workaround if the app also uses service workers.

Hi @xaocmda Yes, the ZIti browZer runtime (ZBR) has multiple pieces, and one of them is a ServiceWorker. When you run your web app under browZer, the ZBR will detect your app's attempt to activate your SW. When this happens, the ZBR will activate a "mock" for your SW. This mock will/should allow your app's SW register/activation process to proceed... but to effectively make your app's SW a no-op. If your web app cannot properly function without your SW being active, browZer will most likely break your app. However, if your SW is more of an offline support/caching mechanism, then your web app will/should function just fine under browZer (since the ZBR will do much of the same caching work for you transparently).

Also, as you discovered, if you encounter err msgs that read...
"Please verify that the destination server is listening on HTTPS"
...this is because you configured the "scheme" for the "service" in your "targetArray" to be "https" when in fact the service was listening on "http"

Thanks for your detailed answer.

I’ll try to fix my current issue, so I’ll be able to check functionality after we start using service workers. The current issue seems like a loop: the login page finishes loading and then reloads. But It's probably on our side, so I need to ask our frontend devs how CSRF tokens are generated now (without service workers).