<!--
hoody-tunnel Subskill (http)
Auto-generated by Hoody Skills Generator
Generated: 2026-05-06T18:38:36.343Z
Model: mimo-v2.5-pro + fixer:z-ai/glm-5.1
Mode: http


Tokens: 5307

DO NOT EDIT MANUALLY - Changes will be overwritten on next generation
-->

# hoody-tunnel Subskill

## Overview

**hoody-tunnel** provides multiplexed tunnel sessions for secure, authenticated access to containerized services within the Hoody ecosystem. It manages WebSocket-based tunnel connections that enable clients to expose local ports or pull remote services through a unified proxy layer.

### When to Use hoody-tunnel

- **Remote access**: Connect to container services without public DNS exposure
- **Port forwarding**: Expose local development ports to Hoody containers
- **Service mesh**: Pull remote service bindings into local environments
- **Monitoring**: Track active sessions, bindings, and resource utilization

### How It Fits Into Hoody Philosophy

hoody-tunnel embodies Hoody's zero-configuration networking model. Like all Hoody Kit services, it requires no manual DNS setup—clients connect via the standardized Hoody Kit URL pattern:

```
https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu
```

The tunnel service acts as the multiplexing backbone for inter-container and client-to-container communication. It handles WebSocket upgrades, session lifecycle, binding management, and resource accounting (file descriptors, streams) transparently.

**Key characteristics**:
- WebSocket-based multiplexed sessions with protocol versioning (`hoody-tunnel.v1`, `hoody-tunnel.v2`)
- Two binding modes: **EXPOSE** (local-to-remote) and **PULL** (remote-to-local)
- Built-in Prometheus metrics for observability

---

## Common Workflows

### 1. Check Tunnel Service Health

Verify the tunnel service is running and healthy before performing operations.

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/health"
```

**Expected response** (no authentication required):

```
{
  "status": "ok",
  "service": "hoody-tunnel",
  "built": "2025-10-01T12:00:00Z",
  "started": "2025-11-05T08:30:00Z",
  "memory": 48234496,
  "fds": 12,
  "pid": 1,
  "ip": "10.0.0.5",
  "userAgent": "hoody-tunnel/1.0"
}
```

**Verification**: Confirm `status` is `"ok"`. If status differs, investigate the service logs before proceeding.

---

### 2. List All Active Tunnel Sessions

Retrieve all currently active sessions with their bindings, stream counts, and protocol versions.

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/sessions"
```

**Expected response**:

```
{
  "sessions": [
    {
      "session_id": "sess_abc123def456",
      "protocol_version": "hoody-tunnel.v2",
      "bindings": [
        {
          "bind_id": "bind_001",
          "kind": "expose",
          "mode": "tcp",
          "port": 8080,
          "session_id": "sess_abc123def456"
        }
      ],
      "stream_count": 3,
      "connected_at": "2025-11-05T09:00:00Z"
    }
  ]
}
```

**Verification**: Check `sessions` array length. An empty array indicates no active tunnels.

---

### 3. List All Active Bindings

View all EXPOSE and PULL bindings across all sessions.

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/bindings"
```

**Expected response**:

```
{
  "bindings": [
    {
      "bind_id": "bind_001",
      "session_id": "sess_abc123def456",
      "port": 8080,
      "kind": "expose",
      "mode": "tcp"
    },
    {
      "bind_id": "bind_002",
      "session_id": "sess_abc123def456",
      "port": 5432,
      "kind": "pull",
      "mode": "tcp"
    }
  ]
}
```

**Verification**: Each binding references a valid `session_id`. Cross-reference with `/api/v1/tunnel/sessions` to confirm session liveness.

---

### 4. Get Unified Tunnel Overview

Retrieve a comprehensive view of all tunnels including expose/pull bindings, stream counts, orphan count, and FD budget status.

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/tunnels"
```

**Expected response**:

```
{
  "tunnels": [
    {
      "session_id": "sess_abc123def456",
      "expose_bindings": [
        {
          "bind_id": "bind_001",
          "port": 8080,
          "mode": "tcp"
        }
      ],
      "pull_bindings": [
        {
          "bind_id": "bind_002",
          "port": 5432,
          "mode": "tcp"
        }
      ],
      "stream_count": 3,
      "orphan_count": 0,
      "fd_budget": {
        "used": 12,
        "limit": 1024
      }
    }
  ]
}
```

**Verification**: Monitor `orphan_count` for leaked streams. Check `fd_budget.used` against `fd_budget.limit` to prevent resource exhaustion.

---

### 5. Retrieve Prometheus Metrics

Export tunnel metrics for monitoring integration.

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/metrics"
```

**Expected response** (Prometheus text format):

```
# HELP hoody_tunnel_active_sessions Number of active tunnel sessions
# TYPE hoody_tunnel_active_sessions gauge
hoody_tunnel_active_sessions 2
# HELP hoody_tunnel_active_bindings Number of active bindings
# TYPE hoody_tunnel_active_bindings gauge
hoody_tunnel_active_bindings 5
# HELP hoody_tunnel_fd_permits Current FD permit count
# TYPE hoody_tunnel_fd_permits gauge
hoody_tunnel_fd_permits 1012
```

**Verification**: `hoody_tunnel_active_sessions` should match the count from `/api/v1/tunnel/sessions`. Alert if `hoody_tunnel_fd_permits` approaches zero.

---

## Advanced Operations

### Multi-Step Session Lifecycle Management

#### Step 1: Establish Baseline

Before connecting a new tunnel client, capture the current state:

```
# Store current session count
SESSIONS_BEFORE=$(curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/sessions" | jq '.sessions | length')

echo "Active sessions before: $SESSIONS_BEFORE"
```

#### Step 2: Connect via WebSocket

The `/api/v1/tunnel/connect` endpoint requires a WebSocket upgrade. Clients MUST:
1. Request subprotocol `hoody-tunnel.v1` or `hoody-tunnel.v2`
2. Send a HELLO frame as the first binary message

```
# Using websocat (install separately)
websocat --protocol hoody-tunnel.v2 \
  "wss://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/connect"
```

**Note**: The HELLO frame format is defined in the hoody-tunnel README. The connect endpoint does not accept standard HTTP GET requests—only WebSocket upgrades succeed.

#### Step 3: Verify New Session

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/sessions"
```

Confirm the new session appears with the expected protocol version and zero initial bindings.

#### Step 4: Validate Bindings

After the client registers its EXPOSE/PULL bindings:

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/bindings"
```

Verify each binding has the correct `kind`, `mode`, and `port` values.

---

### Error Recovery Patterns

#### Stale Session Cleanup

If a client disconnects ungracefully, orphaned sessions may persist. Identify and clean them:

```
# Find sessions with orphan streams
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/tunnels" \
  | jq '.tunnels[] | select(.orphan_count > 0) | .session_id'
```

#### FD Exhaustion Prevention

Monitor FD budget proactively:

```
curl -s \
  "https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu/api/v1/tunnel/tunnels" \
  | jq '.tunnels[] | select(.fd_budget.used / .fd_budget.limit > 0.8) | {session_id, fd_budget}'
```

If any session exceeds 80% FD utilization, consider terminating low-priority sessions or increasing the FD limit.

---

### Performance Considerations

| Metric | Source Endpoint | Alert Threshold |
|--------|----------------|-----------------|
| Active sessions | `/api/v1/tunnel/sessions` | > 100 per container |
| Orphan streams | `/api/v1/tunnel/tunnels` | > 0 |
| FD utilization | `/api/v1/tunnel/metrics` | > 80% of limit |
| Stream count per session | `/api/v1/tunnel/sessions` | > 50 per session |

**Recommendations**:
- Poll `/api/v1/tunnel/metrics` every 30 seconds for Prometheus scraping
- Use `/api/v1/tunnel/tunnels` for detailed debugging; use `/api/v1/tunnel/metrics` for dashboards

---

## Quick Reference

### Endpoints

| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/api/v1/tunnel/health` | Service health (no auth) |
| `GET` | `/api/v1/tunnel/sessions` | List active sessions |
| `GET` | `/api/v1/tunnel/bindings` | List all bindings |
| `GET` | `/api/v1/tunnel/tunnels` | Unified tunnel overview |
| `GET` | `/api/v1/tunnel/metrics` | Prometheus metrics |
| `GET` | `/api/v1/tunnel/connect` | WebSocket upgrade (tunnel) |

### Base URL Pattern

```
https://{projectId}-{containerId}-hoody-tunnel-{serviceId}.{node}.containers.hoody.icu
```

### Protocol Versions

| Subprotocol | Status |
|-------------|--------|
| `hoody-tunnel.v1` | Supported |
| `hoody-tunnel.v2` | Supported (preferred) |

### Response Formats

| Endpoint | Format |
|----------|--------|
| `/health` | JSON object with 9 fields |
| `/sessions` | JSON with `sessions` array |
| `/bindings` | JSON with `bindings` array |
| `/tunnels` | JSON with `tunnels` array |
| `/metrics` | Prometheus text format |