Run the zrok agent in Docker
The zrok2 agent runs in Docker using the docker.io/openziti/zrok2 container image. This guide covers two
approaches:
- Bind-mount approach — mount your existing
~/.zrok2directory from the Docker host. Quick to set up; requires enabling the zrok environment on the host first. - Self-contained approach — use Docker named volumes and init containers to enable the environment automatically. No host-side setup required beyond an account token.
Both approaches run the agent as a long-lived container. Once the agent is running, interact with it using
docker compose exec to create names, start shares, and manage the lifecycle.
Prerequisites
- Docker with Compose v2
- A zrok account token
Bind-mount approach
This approach mirrors the Linux agent service—you enable the zrok environment on the Docker host and mount it into the container.
-
If you haven't already, install
zrok2and enable your account:zrok2 enable <your_account_token>Verify with:
zrok2 status -
Save the following as
compose.yml:compose.ymlservices:
zrok-agent:
image: docker.io/openziti/zrok2
restart: unless-stopped
user: "${UID:-1000}"
environment:
HOME: /mnt
entrypoint:
- bash
- -c
- rm -f /mnt/.zrok2/agent.socket && exec "$@"
command:
- --
- zrok2
- agent
- start
- --console-address
- 0.0.0.0
- --console-start-port
- "8888"
- --console-end-port
- "8888"
expose:
- 8888 # agent web console
# ports:
# - 8888:8888 # uncomment to publish the agent console on the host
volumes:
- ${HOME}/.zrok2:/mnt/.zrok2Set the container userThe
user: "${UID:-1000}"directive sets the container's effective UID to match your Docker host user. This is required so the container can read and write to the bind-mounted~/.zrok2directory. If your UID is not 1000, setUIDin your shell or.envfile. -
Start the agent:
docker compose up -dVerify it's running:
docker compose logs zrok-agent -
Use
docker compose execto runzrok2commands inside the running container:docker compose exec zrok-agent zrok2 agent status
docker compose exec zrok-agent zrok2 create name myapp
docker compose exec zrok-agent zrok2 share public http://host.docker.internal:8080 -n public:myapphost.docker.internalTo share a service running on the Docker host, use
host.docker.internalas the hostname. On Linux, you may also need--network=hoston the container or addextra_hosts: ["host.docker.internal:host-gateway"]to the compose service.
Troubleshooting: ~/.zrok2 owned by root
If ~/.zrok2 doesn't exist on the Docker host when you first run docker compose up, Docker will create it
automatically—but it will be owned by root. The agent container will fail with permission errors.
To fix this:
-
Stop the container:
docker compose down -
Fix ownership:
sudo chown -R "$(id -u):$(id -g)" ~/.zrok2 -
Enable the environment:
zrok2 enable <your_account_token> -
Restart:
docker compose up -d
To avoid this entirely, always run zrok2 enable on the host before the first docker compose up.
Self-contained approach
This approach uses Docker named volumes and init containers to manage the zrok environment entirely within Docker.
No host-side zrok2 installation or ~/.zrok2 directory is needed — only an account token.
The zrok2-enable script included in the container image enables the environment if ZROK2_ENABLE_TOKEN is set,
and does nothing if the environment is already enabled.
-
Save the following as
compose.yml:compose.ymlservices:
# Set ownership on the named volume so the zrok2 user (UID 2171) can use it.
zrok-init:
image: busybox
command: chown -Rc 2171:2171 /mnt/
user: root
volumes:
- zrok_env:/mnt
# Enable the zrok environment if not already enabled.
zrok-enable:
image: docker.io/openziti/zrok2
depends_on:
zrok-init:
condition: service_completed_successfully
entrypoint: zrok2-enable
environment:
HOME: /mnt
ZROK2_ENABLE_TOKEN: ${ZROK2_ENABLE_TOKEN}
ZROK2_API_ENDPOINT: ${ZROK2_API_ENDPOINT:-}
volumes:
- zrok_env:/mnt
# Run the zrok agent.
zrok-agent:
image: docker.io/openziti/zrok2
restart: unless-stopped
depends_on:
zrok-enable:
condition: service_completed_successfully
environment:
HOME: /mnt
entrypoint:
- bash
- -c
- rm -f /mnt/.zrok2/agent.socket && exec "$@"
command:
- --
- zrok2
- agent
- start
- --console-address
- 0.0.0.0
- --console-start-port
- "${ZROK2_AGENT_CONSOLE_PORT:-8888}"
- --console-end-port
- "${ZROK2_AGENT_CONSOLE_PORT:-8888}"
expose:
- "${ZROK2_AGENT_CONSOLE_PORT:-8888}"
# ports:
# - "${ZROK2_AGENT_CONSOLE_PORT:-8888}:${ZROK2_AGENT_CONSOLE_PORT:-8888}"
volumes:
- zrok_env:/mnt
volumes:
zrok_env: -
Create a
.envfile next tocompose.yml:ZROK2_ENABLE_TOKEN=<your_account_token>
# ZROK2_API_ENDPOINT=https://zrok.example.com # uncomment for self-hosted
# ZROK2_AGENT_CONSOLE_PORT=8888 # agent web console port -
Start the agent:
docker compose up -dThe init containers run first (set volume permissions, then enable the environment). The agent starts automatically once the environment is ready.
-
Interact with the agent using
docker compose exec:docker compose exec zrok-agent zrok2 agent status
docker compose exec zrok-agent zrok2 create name myapp
docker compose exec zrok-agent zrok2 share public http://some-service:8080 -n public:myapp
Clean up
To destroy the environment and start fresh, remove the named volume:
docker compose down --volumes
Then delete the zrok environment from the web console or with zrok2 admin.