Skip to main content
Star us on GitHub Star


BrowZer is a set of technologies which is capable of bootstrapping zero trust connectivity entirely in a browser, and without the need to install any client-side software! To enable BrowZer on your OpenZiti Network the ziti-browzer-bootstrapper will need to be deployed. This pages outlines the steps needed to deploy BrowZer to your own overlay. For an example of enabling BrowZer, see the Example Enabling BrowZer subpage showing the steps in more detail.


To deploy and enable BrowZer on your OpenZiti Network, you will need to have:

  • an OpenZiti Overlay Network is available and has been configured with alternative server certs
  • an OIDC Provider and the ability to define applications/clients for the provider
  • a wildcard certificate from a 3rd party verifiable CA

OIDC Prerequisites

Enabling BrowZer will require configuring the OpenZiti Network to delegate authentication to an OIDC provider. Every OIDC provider is different and understanding OIDC flows is beyond this guide. There are numerous, excellent posts to find and read about OIDC. The OIDC concepts you will want to understand are:

  • how to create/obtain the client id the OpenZiti Network will use
  • how to learn/find/discover the OIDC discovery endpoint
  • what audience the OIDC provider will add to the bearer token
  • what field or claim the OIDC provider will add to the bearer token which will be used to locate matching identities

Configuring the OpenZiti Network

With the OIDC information in hand, the next step is to actually configure OpenZiti to allow the delegation of authentication. To do this you will need to:

  • create an external jwt signer
  • create an authentication policy and associate the external jwt signer
  • associate identities with the authentication policy delegating the authentication to the specified OIDC provider

Creating the External JWT Signer

To create the external jwt signer, you will need to have the OIDC discovery endpoint and the audience values handy. Using the OIDC discovery endpoint, discover the issuer and jwks_uri from the discovery endpoint. Using the ziti CLI, create the external jwt. Shown below is a bash example. Replace the values accordingly. Capture the returned identity, it will be necessary after creating the external jwt signer:

ziti edge create ext-jwt-signer \
"ext-jwt-signer-name-here" "${issuer}" \
--jwks-endpoint "${jwks_uri}" \
--audience "${audience}" \
--claims-property ${claims_property}

Creating the Authentication Policy

Authentication policies configure the OpenZiti Network to delegate authentication one or more OIDC providers. To create the authentication policy you only need the id of the external jwt signer (from above). Shown below is a bash example. Replace the values accordingly. Capture the returned identity, it will be necessary after creating the external jwt signer:


Shown below is an example creating a new authentication policy and allowing it to be used for primary authentication. This means the associated external jwt signer (OIDC provider) is allowed to provide a document that OpenZiti will validate, and use for authentication. You can also choose to modify the default policy if you decide to. You do not need to create a new policy. If this is your first time using BrowZer it is recommended you start with a new authentication policy, as shown. Once you understand how authentication policies work and how BrowZer works, then you can make an informed decision if you want to modify the default authentication policy or not

ziti edge create auth-policy \
"auth-policy-name-here" \
--primary-ext-jwt-allowed \
--primary-ext-jwt-allowed-signers ${ext_jwt_signer}

Associate Identities to the Authentication Policy

With an auth policy created and associated to the external jwt signer, you are now ready to create or modify identities to use this new authentication policy. To allow a given identity to be enabled for BrowZer, you will need to first update (or create) the identity with an externalId and you will need to associate the identity with the authentication policy.

In this example, a new identity will be created and the associated OIDC provider will be expected to provide a bearer token which has an email claim with the value and names the identity openziti_ziggy:

ziti edge create identity user "${identity_name}" \
--auth-policy ${auth_policy} \
--external-id "${external_id}" \
-a docker.whale.dialers

Running the Ziti BrowZer Bootstrapper

Running the Ziti BrowZer Bootstrapper can be done directly using NodeJS or with a container engine such as Docker. Either way you choose to run it, you will need to establish some environment variables. If you are using NodeJS, you'll export them. To run using Docker, you can either reference the environment variables (shown below) or use an .env file.

  • NODE_ENV: controls if the environment is production or development
  • ZITI_BROWZER_RUNTIME_LOGLEVEL: the log level for the Ziti BrowZer Runtime (ZBR) to use. trace|debug|info|warn|error
  • ZITI_BROWZER_RUNTIME_HOTKEY: the hotkey to activate the BrowZer settings dialog modal. default: alt+F12
  • ZITI_CONTROLLER_HOST: the "alternative" address for the OpenZiti controller. example:
  • ZITI_CONTROLLER_PORT: the port to find the OpenZiti controller at. example: 8441
  • ZITI_BROWZER_BOOTSTRAPPER_LOGLEVEL: the log level for the ziti-browzer-bootstrapper to log at. trace|debug|info|warn|error
  • ZITI_BROWZER_BOOTSTRAPPER_HOST: the address the ziti-browzer-bootstrapper is available at. example:
  • ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT: the port the ziti-browzer-bootstrapper is available at. example: 443
  • ZITI_BROWZER_BOOTSTRAPPER_SCHEME: the scheme to use to access the ziti-browzer-bootstrapper. http|https (https by default)
  • ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH: the path to the certificate the ziti-browzer-bootstrapper presents to clients
  • ZITI_BROWZER_BOOTSTRAPPER_TARGETS: A json block representing the services to enable BrowZer for.
      NODE_ENV: production

Set these values accordingly. Also shown is the reuse of certificates provisioned in this case by LetsEncrypt. BrowZer requires a wildcard certificate to be provisioned that aligns to the ZITI_BROWZER_BOOTSTRAPPER_HOST value used. For example, if you had set, the certificate must be valid for *


If you use Certbot/LetsEncrypt, the certificate created is likely to be accessible by root only. You will need to modify the folder/files accordingly. accordingly.

Cloning From GitHub

Once the environment variables are set, to start the Ziti BrowZer Bootstrapper perform the following:

  • clone the repository and checkout the desired tag/version. main should be fine:
    git clone $ZITI_HOME/ziti-browzer-bootstrapper
  • cd to the cloned location: cd $ZITI_HOME/ziti-browzer-bootstrapper
  • ensure the proper version of node and yarn are installed and run yarn install: yarn install
  • start the node server:
    NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node index.js

Running via Docker

Running the Ziti BrowZer Bootstrapper using Docker is similar to running with NodeJS. Establish the environment variables then run the agent with a command as shown. Note that this is running in the foreground. It's up to you to decide to put this into daemon mode, to use docker compose, etc.


To work around the LetsEncrypt issue mentioned above (the certs only visible to root), this example explicitly sets the --user the container runs as to a group id of 2171. Not shown was the creation of this group prior to running in Docker. In the Docker host OS, a group was added using a command such as: sudo groupadd -g 2171 zitiweb. Then the LetsEncrypt folder containing the certificates/keys was chown'ed: sudo chown -R root:zitiweb /etc/letsencrypt/. This allows the Docker container that will run the bootstrapper to access the files

Understanding the exact mechanics of why/how this works is beyond the scope of this page and is more relevant to Linux/Docker system administration.

Example Docker Command

docker run \
--name ziti-browzer-bootstrapper \
--rm -v /etc/letsencrypt:/etc/letsencrypt \
--user "${UID}:2171" \

Enabling BrowZer with Systemd

If you want the BrowZer Bootstrap Agent to start when the machine starts or if the process fails for some reason and you have systemd on your system, you can enable the BrowZer Bootstrap Agent to start automatically on failure or reboot.

If you have used the "clone from GitHub" approach, you have sourced the helper script, and have the environment variables set from the quickstart installation you can execute a single function to create a systemd unit file: createBrowZerSystemdFile. Execute this now and you'll see something like:

Ziti BrowZer Bootstrapper systemd file written to: /home/ubuntu/.ziti/quickstart/ip-172-31-47-200/browzer-bootstrapper.service

Once created, you can copy that file and enable the unit with systemd:

sudo cp "${ZITI_HOME}/browzer-bootstrapper.service" /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable --now browzer-bootstrapper
Verify BrowZer Started
systemctl status browzer-bootstrapper --no-pager --lines 0
Example systemctl Output

You should see output that looks similar to this. Notice the "Active" status is (running) and not failed/restarting etc:

● browzer-bootstrapper.service - A systemd unit file for the Ziti BrowZer Bootstrapper
Loaded: loaded (/etc/systemd/system/browzer-bootstrapper.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2023-08-18 12:52:54 UTC; 1min 24s ago
Main PID: 54770 (node)
Tasks: 11 (limit: 2316)
Memory: 42.9M
CPU: 2.269s
CGroup: /system.slice/browzer-bootstrapper.service
└─54770 /usr/local/bin/node /home/ubuntu/.ziti/quickstart/ip-172-31-47-200/ziti-browzer-bootstra…