This article describes how to use Linux tunnelers from the Ziti project as endpoints in your network. This is the easiest way to provide a bi-directional Ziti Edge to an x86 or ARM Linux device. You may use this technique to provide the Ziti Edge to one or many client or server apps running on the same device. You may reference the article about running the Linux tunneler without Docker.  

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

Docker Compose

Compose provides a convenient and powerful way to store container configuration parameters in a file. You'll need to install Docker Compose to follow the rest of these instructions.

# Install Compose from Python Package Index (PyPi)
pip install docker-compose

You may download the Docker Compose file from GitHub (secondary link) to the Docker host. Docker Compose uses the up or run command to run the container.

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

Linux Hosting Terminator

The ziti-host option is useful when you are only providing the Ziti Edge to a server application that has no need to also initiate connections to a Ziti service. This mode does not require elevated privileges because it will not manage DNS resolver or IP routes with systemd-resolved.

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

MacOS & Windows

Most users should install the Desktop Edge app in order to gain access to their NetFoundry network on MacOS and Windows. It is possible to run the Linux container in other OSs with a VM, but transparent proxy mode only works on Linux where systemd-resolved is available. 

Proxy Service

Modify the ziti-proxy section of the docker-compose.yml file. When the service names and bind ports for the raw TCP proxy(ies) suit your needs and then run this command.

NF_REG_NAME=myTunneler1 docker-compose up ziti-proxy

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 \
netfoundry/ziti-edge-tunnel:latest \

Was this article helpful?
0 out of 0 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.