{"owner":"openziti","repo":"zrok","hasDocker":true,"hasCompose":true,"hasDockerfile":false,"composePath":"docker/compose/zrok2-instance/compose.yml","servicesCount":10,"services":[{"name":"ziti-controller","image":"${ZITI_CONTROLLER_IMAGE:-docker.io/openziti/ziti-controller}:${ZITI_CONTROLLER_TAG:-latest}","restart":"unless-stopped","ports":["${ZROK2_INSECURE_INTERFACE:-127.0.0.1}:${ZITI_CTRL_PORT:-1280}:${ZITI_CTRL_PORT:-1280}"],"environment":["ZITI_BOOTSTRAP=true","ZITI_BOOTSTRAP_CLUSTER=true","ZITI_CTRL_ADVERTISED_ADDRESS=ziti.${ZROK2_DNS_ZONE:?err}","ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_PORT:-1280}","ZITI_USER=${ZITI_USER:-admin}","ZITI_PWD=${ZITI_PWD:?err}","ZITI_CLUSTER_TRUST_DOMAIN=${ZROK2_DNS_ZONE}","ZITI_CLUSTER_NODE_NAME=ziti-ctrl","PFXLOG_NO_JSON=true"],"volumes":["ziti-ctrl-data:/ziti-controller"]},{"name":"ziti-router-init","image":"${ZITI_CONTROLLER_IMAGE:-docker.io/openziti/ziti-controller}:${ZITI_CONTROLLER_TAG:-latest}","command":"set -o errexit -o nounset -o pipefail\n\n# Retry helper (self-contained — no external dependencies)\nretry() {\n  local max=\"$$1\" delay=\"$$2\" desc=\"$$3\"; shift 3\n  local n=1\n  while true; do\n    if \"$$@\"; then return 0; fi\n    if (( n >= max )); then\n      echo \"ERROR: $$desc failed after $$max attempts\" >&2; exit 1\n    fi\n    echo \"WARN: $$desc failed (attempt $$n/$$max), retrying in $${delay}s...\"\n    sleep \"$$delay\"; (( n++ ))\n  done\n}\n\nROUTER_NAME=\"$${ZITI_ROUTER_NAME:-zrok2-router}\"\nJWT_FILE=\"/ziti-router/$${ROUTER_NAME}.jwt\"\nZITI_ENDPOINT=\"https://ziti.$${ZROK2_DNS_ZONE}:$${ZITI_CTRL_PORT:-1280}\"\n\necho \"INFO: logging into Ziti controller...\"\nretry 60 5 \"Ziti controller login\" \\\n  ziti edge login \"$$ZITI_ENDPOINT\" \\\n    --username \"$${ZITI_USER:-admin}\" \\\n    --password \"$${ZITI_PWD}\" \\\n    --yes\necho \"INFO: logged into Ziti controller\"\n\n# skip if router already enrolled (identity cert exists)\nif [[ -f \"/ziti-router/$${ROUTER_NAME}.cert.pem\" \\\n   || -f \"/ziti-router/certs/cert.pem\" ]]; then\n  echo \"INFO: router identity already exists, skipping creation\"\n  exit 0\nfi\n\n# create the edge router (idempotent check via list)\n_create_router() {\n  if ziti edge list edge-routers \"name=\\\"$${ROUTER_NAME}\\\"\" 2>/dev/null \\\n     | grep -q \"$${ROUTER_NAME}\"; then\n    echo \"INFO: edge router '$${ROUTER_NAME}' already exists\"\n    return 0\n  fi\n  echo \"INFO: creating edge router '$${ROUTER_NAME}'...\"\n  ziti edge create edge-router \"$${ROUTER_NAME}\" \\\n    --jwt-output-file \"$$JWT_FILE\" \\\n    --tunneler-enabled\n  echo \"INFO: edge router created, JWT saved to $$JWT_FILE\"\n}\nretry 5 3 \"create edge router\" _create_router\n","environment":["ZROK2_DNS_ZONE=${ZROK2_DNS_ZONE:?err}","ZITI_PWD=${ZITI_PWD:?err}","ZITI_USER=${ZITI_USER:-admin}","ZITI_CTRL_PORT=${ZITI_CTRL_PORT:-1280}","ZITI_ROUTER_NAME=${ZITI_ROUTER_NAME:-zrok2-router}"],"volumes":["ziti-router-data:/ziti-router"],"depends_on":["ziti-controller"]},{"name":"ziti-router","image":"${ZITI_ROUTER_IMAGE:-docker.io/openziti/ziti-router}:${ZITI_ROUTER_TAG:-latest}","restart":"unless-stopped","ports":["0.0.0.0:${ZITI_ROUTER_PORT:-3022}:${ZITI_ROUTER_PORT:-3022}"],"environment":["ZITI_BOOTSTRAP=true","ZITI_BOOTSTRAP_ENROLLMENT=true","ZITI_BOOTSTRAP_CONFIG=true","ZITI_AUTO_RENEW_CERTS=true","ZITI_CTRL_ADVERTISED_ADDRESS=ziti.${ZROK2_DNS_ZONE}","ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_PORT:-1280}","ZITI_ROUTER_ADVERTISED_ADDRESS=router.${ZROK2_DNS_ZONE}","ZITI_ROUTER_PORT=${ZITI_ROUTER_PORT:-3022}","ZITI_ROUTER_NAME=${ZITI_ROUTER_NAME:-zrok2-router}","ZITI_ENROLL_TOKEN=/ziti-router/${ZITI_ROUTER_NAME:-zrok2-router}.jwt","PFXLOG_NO_JSON=true"],"volumes":["ziti-router-data:/ziti-router"],"depends_on":["ziti-router-init"]},{"name":"postgresql","image":"postgres:16-alpine","restart":"unless-stopped","environment":["POSTGRES_USER=zrok2","POSTGRES_PASSWORD=${ZROK2_DB_PASSWORD:-zrok2defaultpw}","POSTGRES_DB=zrok2"],"volumes":["pg-data:/var/lib/postgresql/data"]},{"name":"zrok2-init","image":"${ZROK2_IMAGE:-docker.io/openziti/zrok2}:${ZROK2_TAG:-latest}","environment":["ZROK2_DNS_ZONE=${ZROK2_DNS_ZONE:?err}","ZROK2_ADMIN_TOKEN=${ZROK2_ADMIN_TOKEN:?err}","ZITI_PWD=${ZITI_PWD:?err}","ZITI_USER=${ZITI_USER:-admin}","ZITI_CTRL_PORT=${ZITI_CTRL_PORT:-1280}","ZROK2_CTRL_PORT=${ZROK2_CTRL_PORT:-18080}","ZROK2_FRONTEND_PORT=${ZROK2_FRONTEND_PORT:-8080}","ZROK2_STORE_TYPE=${ZROK2_STORE_TYPE:-postgres}","ZROK2_DB_PASSWORD=${ZROK2_DB_PASSWORD:-zrok2defaultpw}","ZROK2_METRICS_ENABLED=${ZROK2_METRICS_ENABLED:-false}","ZROK2_INFLUX_TOKEN=${ZROK2_INFLUX_TOKEN:-}","HOME=/var/lib/zrok2"],"volumes":["zrok2-config:/var/lib/zrok2","./entrypoint-init.bash:/bootstrap/entrypoint-init.bash:ro"],"depends_on":["ziti-controller","postgresql","rabbitmq"]},{"name":"zrok2-controller","image":"${ZROK2_IMAGE:-docker.io/openziti/zrok2}:${ZROK2_TAG:-latest}","restart":"unless-stopped","command":"controller /var/lib/zrok2/config/ctrl.yaml","ports":["${ZROK2_INSECURE_INTERFACE:-127.0.0.1}:${ZROK2_CTRL_PORT:-18080}:${ZROK2_CTRL_PORT:-18080}"],"environment":["ZROK2_ADMIN_TOKEN=${ZROK2_ADMIN_TOKEN:?err}","ZROK2_API_ENDPOINT=http://127.0.0.1:${ZROK2_CTRL_PORT:-18080}","HOME=/var/lib/zrok2"],"volumes":["zrok2-config:/var/lib/zrok2"],"depends_on":["zrok2-init"]},{"name":"zrok2-frontend","image":"${ZROK2_IMAGE:-docker.io/openziti/zrok2}:${ZROK2_TAG:-latest}","restart":"unless-stopped","command":"access dynamicProxy /var/lib/zrok2/config/frontend.yaml","ports":["${ZROK2_INSECURE_INTERFACE:-127.0.0.1}:${ZROK2_FRONTEND_PORT:-8080}:${ZROK2_FRONTEND_PORT:-8080}"],"environment":["ZROK2_API_ENDPOINT=http://zrok2-controller:${ZROK2_CTRL_PORT:-18080}","HOME=/var/lib/zrok2"],"volumes":["zrok2-config:/var/lib/zrok2:ro"],"depends_on":["zrok2-controller"]},{"name":"zrok2-metrics-bridge","image":"${ZROK2_IMAGE:-docker.io/openziti/zrok2}:${ZROK2_TAG:-latest}","restart":"unless-stopped","command":"controller metrics bridge /var/lib/zrok2/config/ctrl.yaml","environment":["HOME=/var/lib/zrok2"],"volumes":["zrok2-config:/var/lib/zrok2:ro","ziti-ctrl-data:/ziti-data"],"depends_on":["zrok2-controller","rabbitmq"]},{"name":"rabbitmq","image":"rabbitmq:3-management-alpine","restart":"unless-stopped","volumes":["rabbitmq-data:/var/lib/rabbitmq"]},{"name":"influxdb","image":"${INFLUXDB_IMAGE:-influxdb:2.8-alpine}","restart":"unless-stopped","environment":["DOCKER_INFLUXDB_INIT_MODE=setup","DOCKER_INFLUXDB_INIT_USERNAME=zrok2","DOCKER_INFLUXDB_INIT_PASSWORD=${ZROK2_INFLUX_PASSWORD:-zrok2defaultpw}","DOCKER_INFLUXDB_INIT_ORG=zrok2","DOCKER_INFLUXDB_INIT_BUCKET=zrok2","DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${ZROK2_INFLUX_TOKEN:-zrok2defaulttoken}"],"volumes":["influx-data:/var/lib/influxdb2"]}],"exposedPorts":["2"],"dockerRunCommand":"docker run -d --name zrok -p 2:2 --restart always postgres:16-alpine","podmanRunCommand":"podman run -d --name zrok -p 2:2 --restart always postgres:16-alpine","skopeoInspectCommand":"skopeo inspect docker://docker.io/library/postgres:16-alpine","orasPullCommand":"oras pull postgres:16-alpine","registryMeta":{"provider":"dockerhub","image":"library/postgres","canonicalImage":"docker.io/library/postgres:16-alpine","latestTag":"17.11-alpine3.23","multiArch":["linux/amd64","linux/ppc64le","linux/386","linux/s390x","linux/arm","linux/arm64","linux/riscv64"],"sizeMb":111,"lastUpdated":"2026-10-22T16:09:15.123389Z","cliCommands":{"dockerRun":"docker run -d --name zrok -p 2:2 --restart always postgres:16-alpine","dockerPull":"docker pull postgres:16-alpine","podmanRun":"podman run -d --name zrok -p 2:2 --restart always postgres:16-alpine","skopeoInspect":"skopeo inspect docker://docker.io/library/postgres:16-alpine","orasPull":"oras pull postgres:16-alpine","composeYaml":"services:\n  zrok:\n    image: postgres:16-alpine\n    restart: unless-stopped\n    ports:\n      - \"2:2\""}}}