Running 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, you interact with it using docker compose exec to create names, start shares, and manage the lifecycle described in the Agent guide.
Prerequisites
- Docker with Compose v2
- A zrok account token
Bind-mount approach
This approach mirrors the Linux systemd agent service — you enable the zrok environment on the Docker host and mount it into the container.
1. Enable the environment on the host
If you haven't already, install zrok2 and enable your account:
zrok2 enable <your_account_token>
Verify with:
zrok2 status
2. Start the agent container
services:
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/.zrok2
The 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 ~/.zrok2 directory. If your UID is not 1000, set UID in your shell or .env file.
Start the agent:
docker compose up -d
Verify it's running:
docker compose logs zrok-agent
3. Interact with the agent
Use docker compose exec to run zrok2 commands inside the running container:
# check agent status
docker compose exec zrok-agent zrok2 agent status
# create a name in the default namespace
docker compose exec zrok-agent zrok2 create name myapp
# start a public share using the name
docker compose exec zrok-agent zrok2 share public http://host.docker.internal:8080 -n public:myapp
# list shares
docker compose exec zrok-agent zrok2 agent status
To share a service running on the Docker host, use host.docker.internal as the hostname. On Linux, you may also need --network=host on the container or add extra_hosts: ["host.docker.internal:host-gateway"] to the compose service.
Troubleshooting: ~/.zrok2 owned by root
If ~/.zrok2 does not exist on the Docker host when you first run docker compose up, Docker will create the directory 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 to your user
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 will enable the environment if the ZROK2_ENABLE_TOKEN variable is set, and does nothing if the environment is already enabled.
services:
# 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:
.env
Create a .env file next to compose.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 and use
docker compose up -d
The init containers run first (set volume permissions, then enable the environment), and the agent starts automatically once the environment is ready. Interact with the agent the same way:
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
Cleaning 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.
Agent lifecycle reference
Once the agent is running (in either approach), the workflow is the same as any other zrok platform. See the Agent guide for the full tutorial, including:
- Creating and deleting names
- Starting public and private shares
- Reserving persistent share tokens
- Accessing private shares
- Using the agent web console