Troubleshooting
Common issues and how to resolve them when deploying the Tunnel Agent.
How routing works
Understanding the request flow helps diagnose issues:
Zihin Cloud sends a request to:
tunnel.zihin.ai/t/{tenant_id}/{service}/{path...}
────────── ──────── ─────────
1. identifies 2. service 3. forwarded
the tunnel name to the agent
Agent receives: { service: "my-service", path: "/api/data" }
Agent resolves: "my-service" → base URL from config
Agent fetches: GET https://internal-host:8080/api/data
The path from the cloud endpoint is appended to the base URL configured in the agent. The agent only provides host and port — the path comes from the request.
Error reference
404 — "No tunnel found for tenant"
The agent is not connected to the tunnel server.
| Possible cause | Solution |
|---|---|
Token (ztun_...) is incorrect or expired | Verify ZIHIN_TOKEN environment variable, request a new token |
| Agent is not running | Check with docker ps or systemctl status |
| Firewall blocking outbound WSS on port 443 | Allow outbound HTTPS/WSS to tunnel.zihin.ai |
401 — "Unauthorized"
Two possible sources — check the response body to distinguish:
| Source | Response body | Agent logs | Cause |
|---|---|---|---|
| Tunnel Server | {"error":"Unauthorized"} | No log (request doesn't reach agent) | Invalid or missing Bearer token |
| Internal service | HTML or JSON from the service | Fetch completed { status: 401 } | Service credential (xc-mcp-token, etc.) is invalid |
If the response body is {"error":"Unauthorized"}, the issue is at the Tunnel Server level — verify that the cloud service is sending the correct Authorization: Bearer header.
502 — "Bad gateway"
The agent is connected, but the local fetch to the internal service failed.
| Possible cause | Solution |
|---|---|
| Internal service URL is unreachable from the container | Test connectivity from inside the container (see below) |
| Self-signed SSL certificate without treatment | Add ssl_verify: false or mount the CA certificate |
| Wrong port for the internal service | Verify the correct port |
| Internal service rejected the authentication token | Test the token directly with curl from the server |
Diagnosis: Set log_level: debug in the agent config. The log line Fetch failed { code, error } shows the exact error.
504 — "Gateway timeout"
The internal service took longer than 30 seconds to respond.
- Check the health of the internal service
- Avoid large queries without filters or pagination
SERVICE_NOT_FOUND
The service name in the agent config doesn't match the request.
The service name in zihin-agent.yml must match the {service} segment in the cloud endpoint URL:
Cloud endpoint: /t/{tenant}/nocodb/mcp/...
──────
Agent config: services:
- name: nocodb ← must match
Authentication errors (4001, 4003)
| Code | Meaning | Solution |
|---|---|---|
4001 | Invalid or expired token | Check ZIHIN_TOKEN, request a new token |
4003 | Tunnel not found on the server | Contact the Zihin team to verify provisioning |
Diagnostic commands
Test from inside the Docker container
If the agent returns 502, test whether the container can reach the internal service:
# Test basic connectivity
docker exec zihin-tunnel wget -qO- --no-check-certificate https://INTERNAL_HOST:PORT/
# If this fails, the container can't reach the service.
# Solution: add network_mode: host to docker-compose.yml
Test the internal service directly (from SSH)
# Test the service endpoint with authentication
curl -sk -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
https://INTERNAL_HOST:PORT/api/endpoint
Enable debug logs
# In zihin-agent.yml
log_level: debug
Or via environment variable:
export ZIHIN_LOG_LEVEL=debug
Restart the agent after changing the log level. Remember to set it back to info after troubleshooting.
Common issues
| Symptom | Likely cause | Solution |
|---|---|---|
| Reconnect loop | Firewall blocking outbound 443 | Allow outbound HTTPS/WSS to tunnel.zihin.ai |
Agent token is required | ZIHIN_TOKEN not set | Set the environment variable before starting |
No services defined | YAML missing services block | Add at least one service to zihin-agent.yml |
HOST_NOT_ALLOWED | Host policy restricts access | Contact the Zihin team to adjust allowed_hosts |
RATE_LIMITED | Too many requests per minute | Reduce request frequency or request a limit increase |
| Response timeout | Internal service slow or unreachable | Verify the service URL is accessible from the agent machine |
HTTP status codes — quick reference
| HTTP | Meaning | Where it failed |
|---|---|---|
| 200 | Success | — |
| 401 | Invalid Bearer token or service credential | Cloud → Tunnel Server (check response body for {"error":"Unauthorized"}) or Agent → Internal service |
| 404 | Agent offline or tunnel doesn't exist | Tunnel Server |
| 429 | Rate limit exceeded | Tunnel Server or Agent |
| 502 | Agent connected, local fetch failed | Agent → Internal service |
| 504 | Timeout (>30s) | Agent → Internal service |
Support
If you need help:
- Send logs with
debuglevel to the Zihin team - Include the agent version:
docker exec zihin-tunnel node dist/index.js --version - Describe your setup: number of services, network type, corporate proxy (if any)