---
title: 'TestingBot Tunnel Health Checks: /healthz, /readyz, Docker and Kubernetes'
description: Check whether TestingBot Tunnel is alive and ready to forward traffic
  with /healthz, /readyz and --ready. Docker HEALTHCHECK, Kubernetes probes and CI
  wait loops.
source_url:
  html: https://testingbot.com/support/tunnel/health-checks
  md: https://testingbot.com/support/tunnel/health-checks.md
---

# Know when the tunnel can carry traffic

Starting the tunnel process is not the same as the tunnel being able to forward requests. A remote tunnel server has to be provisioned, the SSH connection established and a self-test passed. Health checks let your CI job or orchestrator wait for exactly that moment, and notice when it is lost.

- Since v5.0 
- Docker HEALTHCHECK 
- Kubernetes probes 

## Endpoints

Served on the metrics port, `8003` by default (change with `--metrics-port`).

| Path | Answers | Use it for |
| --- | --- | --- |
| /healthz | `200 {"status":"ok"}` whenever the process is answering, including mid-reconnect | Liveness: restart the tunnel only if this fails |
| /readyz | `200` when the tunnel is forwarding, `503` otherwise | Readiness: start tests, or route traffic, only when this is 200 |
| / | JSON status: version, uptime, requests, bytes transferred | Dashboards and quick inspection |
| /metrics | Prometheus exposition | [Monitoring](https://testingbot.com/support/tunnel/monitoring) |

```bash
curl -i http://127.0.0.1:8003/readyz
```

- `/readyz` turns 200 only after the startup self-test passes, and after a reconnect only once both forwarding directions are back.
- During a reconnect, `/healthz` stays 200 while `/readyz` returns 503. The tunnel is recovering by itself, so it should be taken out of rotation, not restarted.
- The health endpoints are deliberately not behind `--metrics-auth`. Container probes have no good way to carry credentials, and the endpoints disclose nothing beyond up or down.
- Like every local listener, the metrics port binds `127.0.0.1` unless you set `--bind-address 0.0.0.0`.

## The --ready command

Asks a running tunnel whether it is ready, then exits `0` (ready) or `1` (not ready, or nothing listening). No `curl` or `wget` needed.

```bash
java -jar testingbot-tunnel.jar --ready
echo $? # 0 when ready

# a tunnel started with --metrics-port 9003
java -jar testingbot-tunnel.jar --ready --metrics-port 9003
```

`--ready` queries `/readyz` on `--metrics-port`, so pass the same port you started the tunnel with.

## Waiting for the tunnel in CI

Start the tunnel in the background, then block until it is ready before running tests.

```bash
java -jar testingbot-tunnel.jar &
TUNNEL_PID=$!

for i in $(seq 1 60); do
  java -jar testingbot-tunnel.jar --ready 2>/dev/null && break
  sleep 2
done
java -jar testingbot-tunnel.jar --ready || { echo "tunnel not ready"; exit 1; }

npm test

kill $TUNNEL_PID
```

On GitHub Actions the [testingbot-tunnel-action](https://testingbot.com/support/integrations/ci-cd/github-actions) does this for you.

## Docker

The `testingbot/tunnel` image has a built-in `HEALTHCHECK` that runs `--ready`, so `docker ps` shows _healthy_ once the tunnel is actually forwarding.

```bash
docker run -d --name tb-tunnel \
  -e TESTINGBOT_KEY=... -e TESTINGBOT_SECRET=... \
  -p 127.0.0.1:4445:4445 \
  testingbot/tunnel:5.0

docker inspect --format '{{.State.Health.Status}}' tb-tunnel
```

With Docker Compose, other services can wait for it:

```yaml
services:
  tunnel:
    image: testingbot/tunnel:5.0
    environment:
      TESTINGBOT_KEY: ${TESTINGBOT_KEY}
      TESTINGBOT_SECRET: ${TESTINGBOT_SECRET}
  tests:
    build: .
    environment:
      SELENIUM_URL: http://tunnel:4445/wd/hub
    depends_on:
      tunnel:
        condition: service_healthy
```

 Changing the metrics port 

The image's `HEALTHCHECK` assumes the default metrics port. If you set `--metrics-port` or `TESTINGBOT_METRICS_PORT`, override the healthcheck to match.

## Kubernetes

Use `/healthz` as the liveness probe and `/readyz` as the readiness probe. Tunnel options are available as `TESTINGBOT_*` environment variables, so no command line is needed.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: testingbot-tunnel
spec:
  replicas: 1
  selector:
    matchLabels: { app: testingbot-tunnel }
  template:
    metadata:
      labels: { app: testingbot-tunnel }
    spec:
      containers:
        - name: tunnel
          image: testingbot/tunnel:5.0
          env:
            - name: TESTINGBOT_KEY
              valueFrom: { secretKeyRef: { name: testingbot, key: key } }
            - name: TESTINGBOT_SECRET
              valueFrom: { secretKeyRef: { name: testingbot, key: secret } }
            - name: TESTINGBOT_TUNNEL_IDENTIFIER
              value: k8s-staging
          ports:
            - containerPort: 4445 # Selenium relay
            - containerPort: 8003 # metrics and health
          startupProbe:
            httpGet: { path: /readyz, port: 8003 }
            periodSeconds: 5
            failureThreshold: 36
          readinessProbe:
            httpGet: { path: /readyz, port: 8003 }
            periodSeconds: 10
          livenessProbe:
            httpGet: { path: /healthz, port: 8003 }
            periodSeconds: 30
```

 Who can reach port 4445 

The image binds every interface so that the Service can reach it. The Selenium relay attaches your TestingBot credentials to everything it forwards, so restrict access to it with a `NetworkPolicy` and do not expose it outside the cluster.

Running more than one tunnel, for example one per environment? See [multiple tunnels](https://testingbot.com/support/tunnel/multiple) for how identifiers route tests to the right one.

## --readyfile

`--readyfile FILE` touches a file once the tunnel is ready. It still works, but it cannot express “was ready, has since dropped”.

The file is created once and not removed while the process lives, so a tunnel that lost its SSH connection still looks ready on disk. Prefer `--ready` or `/readyz`, which ask the process for its current state.

## Looking for more help?

Have questions or need more information? Reach out via email or Slack.

[Email us](https://testingbot.com/contact/new) [Join our Slack](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw)
