Skip to main content
Star us on GitHub Star

Local - Docker Compose

If you are not familiar with it, Docker Compose is a tool for defining and running multi-container Docker applications. It makes deploying multiple containers easy by using a declarative format defined via yaml. Note that this page uses "Compose V2". This means all the commands shown will reference docker compose, not docker-compose. If you're using the older style of compose, consider upgrading to the newer v2.

Preparation - Required Files

First, grab the compose file from the ziti repository.

Using curl that would look like this:

curl -so docker-compose.yaml

Next, grab the default environment file or just make a file in this folder that looks like this:

curl -so .env

or, if you would prefer to make your .env file manually, create a file in some way such as using the command shown below:

cat > .env <<DEFAULT_ENV_FILE
# OpenZiti Variables

## Additional variables to override.

If you are running Void linux, you need to modify the docker-compose file, otherwise the services will not start properly. To do this, add the following two lines to each service definition.

- seccomp:unconfined

Please see this discussion for more information

Running via Docker Compose

Once the compose file is downloaded and the .env file exists, you'll be able to start this network using docker compose just like you can with any other compose file: docker compose up


Docker compose will name your containers based on the folder you were in when you started them. For me, I've made a folder named docker so all my containers start with docker_. You can influence how this works by adding --project-name docker (or whatever name you like) to your docker compose up/down commands

docker compose --project-name docker up 

Stopping the Network

This docker-compose file will generate a volume mount as well as a two docker networks. When you issue --project-name docker down the volume mapping will not be removed. If you wish to remove the volume, you'll need to specify the -v flag to the docker compose command. Leave the -v off your command if you want to just stop the containers without losing the controller database and PKI.

Deployment Diagram

The docker-compose file will create quite a few containers on your behalf. Here is a logical overview of the network that will get created:


As you can see there's a fair bit going on in there, let's break it down. The first thing to notice is that the entire image is within the scope of a Docker network. You'll see with this compose file there are three pieces of the overlay which span the Docker network: the controller, an edge router, and a websocket-based edge router.

Deployment Simplified

The stock docker-compose.yml deploys many components and is somewhat complex. If you prefer a simplified deployment via Docker compose, one which only includes the basic controller and edge router combination you can instead download the simplified-docker-compose.yml


Inside the Docker network you'll see there are three networks:

  • the blue docker network
  • the red docker network
  • the purple "logical" network

Docker will ensure only the pieces within a given network, can only communicate within that network. This network topology is designed to approximate, very loosely, what it would be like to have a publicly deployed network. The purple network would approximate the internet itself, the blue network would represent a cloud provider's private network (such as AWS) and the red network could represent another cloud provider network (like Azure). Those details are not important, the important part is that the networks are totally private to one another. See more on this topic below in the "Testing" section.

Purple Network

There is no Docker network named "purple" in the compose file, it's entirely a logical construct. It is shown only for clarity. All the assets in the purple network are in both the blue and red docker networks (which is why it's referred to as purple). The assets in the purple network need to be in both the red and blue networks because the assets located in the blue and red networks need to communicate to the public edge routers and also need to communicate to the controller. If that's confusing, see the "Testing" section below which will hopefully make this more clear.

Red Network

The red network exists for demonstration only at this time. As you can see there are no assets inside the red network other than the private, ziti-private-red router and the ziti-fabric-router-br. This means there's nothing in the red network for Ziti to access. It would serve as a great place for you to put your own assets and explore using Ziti!

Blue Network

The blue network contains two important assets, the ziti-private-blue router and the web-test-blue server. Along with those assets, the network also contains the ziti-fabric-router-br. Although the web-test-blue server does export a port by default (port 80 on your localhost, will translate to port 8000 on the web-test-blue server), you can use Ziti to access this server without the exported port.

The "Fabric" Router

The ziti-fabric-router-br exists to illustrate that you can create edge routers that are not necessarily fully public. This is the only router which can communicate to all the other routers. The Ziti mesh may choose to use this router if the algorithm indicates it's the fastest path. Perhaps we'll see more about this in future docs.

Testing the Network

Using Docker Locally

A quick note. If you are not well-versed with Docker you might forget that exposing ports in Docker is one thing, but you'll also need to have a hosts entry for the containers you want to access from outside the Docker network. This quickstart will expect that you understand this and for every router you add you will want to make sure you add a host entry. In the docker compose example you will want/need hosts entries for at least:

  • ziti-edge-controller,
  • ziti-edge-router

And if you want to expose any other routers - of course you'll need/want to have entries for those as well.


Now that we have used docker compose to deploy a relatively complicated network, we can start testing it out to make sure everything is in place and looks correct. Let's try it out.

To test, we will docker exec into the running controller. Notice we'll be specifying the container and it's expected that the project was named "docker". If you don't start your compose using --project-name docker, use the proper exec command:

docker exec -it docker-ziti-controller-1 bash

Once exec'ed into the controller, the ziti CLI will be added to your PATH for you. There is also the zitiLogin alias to make it easy for you to authenticate to the Ziti controller. Run zitiLogin now and ensure you're authenticated.

ziti@724087d30014:/persistent$ zitiLogin
Token: 55ec6721-f33b-4101-970a-412331bd7578
Saving identity 'default' to /persistent/ziti-cli.json

Test - Edge Routers Online

Once authenticated, let's see if all our routers are online by running ziti edge list edge-routers:

ziti@724087d30014:/persistent$ ziti edge list edge-routers
│ C6LbVE7fIc │ ziti-edge-router │ truetrue0 │ public │
│ GY1pcE78Ic │ ziti-private-blue │ truetrue0 │ ziti-private-blue │
│ H0UbcE78Tc │ ziti-fabric-router-br │ truetrue0 │ ziti-fabric-router-br │
│ KHTAct78Tc │ ziti-private-red │ truetrue0 │ ziti-private-red │
│ Yblbct7fTc │ ziti-edge-router-wss │ truetrue0 │ public │
results: 1-5 of 5

We can see all the routers are online - excellent.

Test - Edge Router Identities

In this compose file, we have used a script that adds an identity for each of our edge routers as well. We can see those by running ziti edge list identities:

ziti@724087d30014:/persistent$ ziti edge list identities
│ C6LbVE7fIc │ ziti-edge-router │ Router │ │
│ GY1pcE78Ic │ ziti-private-blue │ Router │ │
│ H0UbcE78Tc │ ziti-fabric-router-br │ Router │ │
│ KHTAct78Tc │ ziti-private-red │ Router │ │
│ Yblbct7fTc │ ziti-edge-router-wss │ Router │ │
│ kkVrSLy.D │ Default Admin │ User │ │
results: 1-6 of 6

Notice there is an identity for every router.

Test - Network Connectivity Success

Recall that the controller should be able to contact both the red and blue edge routers using the underlay network. Let's use ping and verify:

ziti@724087d30014:/persistent$ ping ziti-private-red -c 1
PING ziti-private-red ( 56 data bytes
64 bytes from icmp_seq=0 ttl=64 time=0.387 ms
--- ziti-private-red ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.387/0.387/0.387/0.000 ms
ziti@724087d30014:/persistent$ ping ziti-private-blue -c 1
PING ziti-private-blue ( 56 data bytes
64 bytes from icmp_seq=0 ttl=64 time=0.633 ms
--- ziti-private-blue ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.633/0.633/0.633/0.000 ms

Test - Underlay Network Connectivity Failure

Now let's exit the Ziti controller and instead attach to the private blue router by running this command: docker exec -it docker-ziti-private-blue-1 bash. Once attached to the blue router we'll verify that we cannot connect to the private red router:

ziti@e610d6b44166:/persistent$ ping ziti-private-red -c 1
ping: unknown host

Unknown host - the private blue router cannot connect to the red router.

Test - Underlay Network Web Test Blue

While we're attached to the blue router - let's make sure we can connect to that web-test-blue server.

ziti@e610d6b44166:/persistent$ curl http://web-test-blue:8000
Hello World

## .
## ## ## ==
## ## ## ## ## ===
/""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o _,/
\ \ _,'

Don't forget - you can also access this from the exported port 80 on your local machine too!

curl http://localhost:80
Hello World

## .
## ## ## ==
## ## ## ## ## ===
/""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o _,/
\ \ _,'

Next Steps

  • Now that you have your network in place, you probably want to try it out. Head to the services quickstart and start learning how to use OpenZiti.
  • Add a Second Public Router: In order for multiple routers to form transit links, they need a firewall exception to expose the "link listener" port. The default port is 10080/tcp.
  • Help