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 |
curl -i http://127.0.0.1:8003/readyz
-
/readyzturns 200 only after the startup self-test passes, and after a reconnect only once both forwarding directions are back. - During a reconnect,
/healthzstays 200 while/readyzreturns 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.1unless 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.
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.
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 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.
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:
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
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.
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
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 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.