Using the OpenZiti Tunneler with Docker


You can run a Linux tunneler with Docker. If you are looking to run the Linux tunneler natively without Docker then check out the main article about the Linux tunneler.  

Docker Compose

Compose is part of Docker and provides a convenient and powerful way to store containers' configuration parameters in a YAML file.

You may download the Docker Compose file from GitHub to the Docker host. Docker Compose uses the up or run commands to start the container.

Elevated Privileges

The Linux tunneler requires elevated privileges to manage systemd-resolved (Ziti DNS) and effect IP routes. This means that you will need to have permission to run a privileged container on the Docker host to use the Docker Compose reference file linked below. This is often accomplished by adding a user to the dockergroup and restarting the user session.

sudo usermod -aG docker $USER 

Endpoint Enrollment

You will need the enrollment token (JWT) from NetFoundry for the endpoint you have created for Docker Tunneler. By providing the JWT file, your endpoint will be enrolled the first time you run the container and the permanent identity JSON file will be stored in the volume mounted on /ziti-edge-tunnel , typically the same directory as your Docker Compose file. There are several ways you can pass the enrollment token JWT file to the tunneler. Each of these three enrollment methods will create myClientTunneler1.json in the same directory as docker-compose.yml.

Enroll with JWT Filename as Env Var

Save the JWT file in the same directory as docker-compose.yml e.g. myClientTunneler1.jwt and  assign the base filename without .jwt suffix to the variable.

NF_REG_NAME=myClientTunneler1 \
docker-compose up ziti-tun

Enroll with JWT String as Env Var

NF_REG_NAME=myClientTunneler1 \
NF_REG_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbSI6Im90dCIsImV4cCI6MTYyODgyMzkwMiwiaXNzIjoiaHR0cHM6Ly9mYzc5ZWFjNi03YzU3LTQxNWMtYjhiZi05ZTRjNTYzNjI5ZWIuc3RhZ2luZy5uZXRmb3VuZHJ5LmlvOjQ0MyIsImp0aSI6ImYxNjNlMzlkLWY5M2ItNDBjYS1hY2U2LTQzY2IzZTFiM2Q1MiIsInN1YiI6IkU3U3RldjhtV0YifQ.NCWwFIa0A66TNdIknUx4gszuLMDwTyKfN4RiI2trZgqmc61dNDzSzceLB96kL-2kYrZGTUNx8996qxpJcJS5E3VhkmYv5Qo7lGfppEoPHf-akij4RXP2uuOa7lIkZcI6230WgqwwIG5rbvnurAJ03VCKqhJ7_mfonG_71MpB3QBXvpCZPPa7hu-IK9Qo4k1Mmtq3lUQ-w46zQ0RdjKQPye_Y_bDGP4SZBWJ4U6gH4mLskyQapNlr4QDZbUzxEel05sT9ywaVo3JFHskHqGnuELqoZxM5pwOigYrHoko03bM0nbgFeDdJJN266ThIm_P4EtjfC7nHoGx-3P0LLeiWbXcGnFZeB1yRwYSzd9quuKGGte4XalTSZ9gynEUd_-3nyV4n0EZccNxqIHKC9ZPOHW0Zl5DrkD7eBl9tr7jjks8_ByF_VCRiLNWJP_V86qpCBHaCyAM3KQ_mmQ4f9IDBFOsgTP7X_CRtsQpDd0d-oJ4mC1nFSpihym2daZgaVcTyzFLWBaocou5wyJtgBk2435WpI1Mqh66bg4HLlfMXTOdyorBo4UdPlTW0JcIayrQlTdPJ2OjQYgy5nSgKw2ogjVaidGcLk7xe6zG7rAOf_wqpZTZwB7uDpz66sqrfsuGtVL_e1EquHR5LaU2DO_AWqIHSZL7BHy-IJf5YsJNHmfA" \
docker-compose up ziti-tun

Enroll with JWT String as Standard Input

NF_REG_NAME=myClientTunneler1 \
docker-compose run ziti-tun < /tmp/myClientTunneler1.jwt


Linux Tunneling Proxy

Single Identity

# note that we only specify the base filename without suffix
NF_REG_NAME=myClientTunneler1 docker-compose up ziti-tun

Multiple Identities

The container will load all identities (pre-enrolled JSON files) in the same directory as docker-compose.yml.

# no env vars are specified because we will load all identities from same directory
docker-compose up ziti-tun-dir

Running in the Background

To run the container in the background you may add the--detach parameter like this:

NF_REG_NAME=myClientTunneler1 docker-compose up --detach ziti-tun

# optionally, follow the output from the detached container
docker-compose logs --follow ziti-tun


The provided Compose file uses the magic :latest container image tag to always pull the latest release version. The local container image cache may be updated to latest by running the pull command before the run or up command. If you are managing the configuration of a device you may wish to always run this command after a reboot.

docker-compose pull

In special cases where Ziti provides the remote access to a device running Docker you may wish to perform an upgrade in-place that does not require stopping the older tunneler. For this purpose you may wish to temporarily run the Docker Tunneler without Compose as described below. In that scenario it would also be necessary to configure

  1. a discrete Ziti service to represent the temporary out-of-band remote access path
  2. a discrete DNS IP range for the temporary tunneler

After you have verified the temporary remote access path is functional then you could safely pull and restart the primary tunneler.

Docker without Compose

Docker Compose is recommended because it provides process management and stores the containers' configurations. You may find the Docker options, arguments, and parameters needed to run each container without Compose by referencing the docker-compose.yml file linked above. For example:

# it is necessary to run each tunneler with a discrete DNS IP range in 100.64/10
docker run \
--rm \
--name myTunneler1 \
--privileged \
--network host \
--device "/dev/net/tun:/dev/net/tun" \
--volume "${PWD}:/ziti-edge-tunnel" \
--volume "/var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket" \
--env NF_REG_NAME=myTunneler1 \
Was this article helpful?
2 out of 2 found this helpful


1 comment

  • When I run this then I get a "no key mechanism specified", unsure where to configure this. On the dashboard or do I need another file that has the key config?


Article is closed for comments.