> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nearai/ironclaw/llms.txt
> Use this file to discover all available pages before exploring further.

# Tunnel Setup for Remote Access

> Expose IronClaw to the internet via Cloudflare, Tailscale, ngrok, or custom tunnel providers

## Overview

IronClaw's tunnel system wraps external tunnel binaries (cloudflared, ngrok, tailscale, etc.) behind a common trait. The gateway starts a tunnel after binding its local port and stops it on shutdown.

## Supported Providers

| Provider | Type | Use Case | Cost |
| - | - | - | - |
| **None** | Local-only | Development | Free |
| **Cloudflare** | Zero Trust tunnel | Production | Free (with Cloudflare account) |
| **Tailscale** | Private mesh VPN | Team access | Free (up to 3 users) |
| **ngrok** | Public URL | Testing, demos | Free tier available |
| **Custom** | Any binary | Custom setups | Varies |

## Configuration

### Environment Variables

```bash theme={null}
# Provider selection
TUNNEL_PROVIDER=cloudflare  # Options: none, cloudflare, tailscale, ngrok, custom

# Cloudflare
TUNNEL_CF_TOKEN=eyJh...  # From Zero Trust dashboard

# Tailscale
TUNNEL_TS_FUNNEL=false  # true = public, false = tailnet-only
TUNNEL_TS_HOSTNAME=my-ironclaw  # Optional override

# ngrok
TUNNEL_NGROK_TOKEN=...  # Auth token
TUNNEL_NGROK_DOMAIN=my-app.ngrok.app  # Optional (paid plan)

# Custom
TUNNEL_CUSTOM_COMMAND="cloudflared tunnel --no-autoupdate run --url http://{host}:{port}"
TUNNEL_CUSTOM_HEALTH_URL=http://localhost:8080/health
TUNNEL_CUSTOM_URL_PATTERN="https://"
```

## Provider Setup

### None (Local Only)

No tunnel. Agent is only accessible on localhost.

```bash theme={null}
TUNNEL_PROVIDER=none
# Or omit TUNNEL_PROVIDER entirely
```

**Use Cases**:

* Local development
* Single-user setups
* Behind existing reverse proxy

### Cloudflare Zero Trust

Secure, authenticated tunnel via Cloudflare's network.

#### Setup

1. **Create Cloudflare account** at [cloudflare.com](https://cloudflare.com)

2. **Install cloudflared**:

   ```bash theme={null}
   # macOS
   brew install cloudflare/cloudflare/cloudflared

   # Linux
   wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
   sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared
   sudo chmod +x /usr/local/bin/cloudflared
   ```

3. **Create tunnel** in [Zero Trust dashboard](https://one.dash.cloudflare.com/):

   * Navigate to Networks > Tunnels
   * Click "Create a tunnel"
   * Choose "Cloudflared"
   * Copy the tunnel token

4. **Configure IronClaw**:

   ```bash theme={null}
   TUNNEL_PROVIDER=cloudflare
   TUNNEL_CF_TOKEN=eyJh...  # Paste token here
   ```

5. **Start IronClaw**:

   ```bash theme={null}
   ironclaw run
   ```

   The tunnel URL will be displayed in logs:

   ```
   [INFO] Tunnel started: https://random-name-123.cfargotunnel.com
   ```

**Features**:

* Zero Trust authentication
* Automatic HTTPS
* DDoS protection
* Access control policies
* No firewall configuration needed

**Configuration**:

```rust theme={null}
pub struct CloudflareTunnelConfig {
    pub token: String,  // From Zero Trust dashboard
}
```

### Tailscale

Private mesh VPN with optional public access.

#### Setup (Tailnet-Only)

1. **Install Tailscale**:

   ```bash theme={null}
   # macOS
   brew install tailscale

   # Linux
   curl -fsSL https://tailscale.com/install.sh | sh
   ```

2. **Authenticate**:

   ```bash theme={null}
   sudo tailscale up
   ```

3. **Configure IronClaw**:

   ```bash theme={null}
   TUNNEL_PROVIDER=tailscale
   TUNNEL_TS_FUNNEL=false  # Tailnet-only
   ```

4. **Start IronClaw**:

   ```bash theme={null}
   ironclaw run
   ```

   Access via: `https://<machine-name>.<tailnet-name>.ts.net`

#### Setup (Public Funnel)

1. **Enable Funnel** (requires Tailscale account):

   ```bash theme={null}
   TUNNEL_PROVIDER=tailscale
   TUNNEL_TS_FUNNEL=true  # Public access
   ```

2. **Start IronClaw**:

   ```bash theme={null}
   ironclaw run
   ```

   Public URL: `https://<machine-name>.<tailnet-name>.ts.net`

**Features**:

* Private mesh network
* Automatic HTTPS (via Let's Encrypt)
* ACLs for access control
* Optional public access (Funnel)
* Magic DNS

**Configuration**:

```rust theme={null}
pub struct TailscaleTunnelConfig {
    pub funnel: bool,              // Use public funnel
    pub hostname: Option<String>,  // Override machine name
}
```

### ngrok

Instant public URLs for testing and demos.

#### Setup

1. **Create account** at [ngrok.com](https://ngrok.com)

2. **Install ngrok**:

   ```bash theme={null}
   # macOS
   brew install ngrok

   # Linux
   wget https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-amd64.tgz
   tar xvzf ngrok-v3-stable-linux-amd64.tgz
   sudo mv ngrok /usr/local/bin/
   ```

3. **Get auth token** from [dashboard](https://dashboard.ngrok.com/get-started/your-authtoken)

4. **Configure IronClaw**:

   ```bash theme={null}
   TUNNEL_PROVIDER=ngrok
   TUNNEL_NGROK_TOKEN=...  # Your auth token
   ```

5. **Start IronClaw**:

   ```bash theme={null}
   ironclaw run
   ```

   URL: `https://random-string.ngrok.app`

#### Custom Domain (Paid)

```bash theme={null}
TUNNEL_PROVIDER=ngrok
TUNNEL_NGROK_TOKEN=...
TUNNEL_NGROK_DOMAIN=my-app.ngrok.app  # Requires paid plan
```

**Features**:

* Instant public URLs
* Web inspection UI
* Replay requests
* Custom domains (paid)
* Edge routing

**Configuration**:

```rust theme={null}
pub struct NgrokTunnelConfig {
    pub auth_token: String,
    pub domain: Option<String>,  // Custom domain (paid plan)
}
```

### Custom Tunnel

Use any tunnel binary with placeholders.

#### Example: bore.pub

```bash theme={null}
TUNNEL_PROVIDER=custom
TUNNEL_CUSTOM_COMMAND="bore local {port} --to bore.pub"
TUNNEL_CUSTOM_URL_PATTERN="bore.pub"
```

#### Example: localtunnel

```bash theme={null}
TUNNEL_PROVIDER=custom
TUNNEL_CUSTOM_COMMAND="lt --port {port}"
TUNNEL_CUSTOM_URL_PATTERN="https://"
```

#### Example: Custom cloudflared

```bash theme={null}
TUNNEL_PROVIDER=custom
TUNNEL_CUSTOM_COMMAND="cloudflared tunnel --url http://{host}:{port}"
TUNNEL_CUSTOM_HEALTH_URL=http://localhost:8080/health
TUNNEL_CUSTOM_URL_PATTERN="https://"
```

**Placeholders**:

* `{host}` - Local bind address (e.g., `127.0.0.1`)
* `{port}` - Local bind port (e.g., `3000`)

**Configuration**:

```rust theme={null}
pub struct CustomTunnelConfig {
    pub start_command: String,          // Command with placeholders
    pub health_url: Option<String>,     // Health check endpoint
    pub url_pattern: Option<String>,    // Substring to match in stdout
}
```

## Tunnel Lifecycle

### Startup

```text theme={null}
1. Gateway binds local port (default: 3000)
2. Tunnel provider starts (if configured)
3. Public URL extracted from stdout
4. Gateway becomes ready
```

### Shutdown

```text theme={null}
1. Gateway receives shutdown signal
2. Tunnel provider stopped gracefully
3. Container cleanup (if any)
4. Process exits
```

### Health Checks

```rust theme={null}
pub async fn health_check(&self) -> bool {
    // Check if tunnel process is still alive
    if let Some(proc) = self.process.lock().await.as_mut() {
        match proc.child.try_wait() {
            Ok(None) => true,  // Still running
            _ => false,        // Exited
        }
    } else {
        false  // Not started
    }
}
```

## URL Extraction

### Cloudflare

Parses `cloudflared` output:

```
2025-03-03T12:34:56Z INF +--------------------------------------------------------------------------------------------+
2025-03-03T12:34:56Z INF |  Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): |
2025-03-03T12:34:56Z INF |  https://random-name-123.cfargotunnel.com                                                 |
2025-03-03T12:34:56Z INF +--------------------------------------------------------------------------------------------+
```

Extraction: Look for `https://.*cfargotunnel.com`

### Tailscale

Queries `tailscale status --json`:

```json theme={null}
{
  "Self": {
    "DNSName": "machine-name.tailnet-name.ts.net.",
    "HostName": "machine-name"
  }
}
```

URL: `https://<DNSName>` (strips trailing dot)

### ngrok

Parses ngrok output:

```
Forwarding   https://random-string.ngrok.app -> http://localhost:3000
```

Extraction: Look for `https://.*ngrok.app`

### Custom

Matches `url_pattern` in stdout:

```bash theme={null}
TUNNEL_CUSTOM_URL_PATTERN="https://"
```

First line containing pattern is used as URL.

## Programmatic API

### Creating Tunnels

```rust theme={null}
use ironclaw::tunnel::{
    create_tunnel,
    TunnelProviderConfig,
    CloudflareTunnelConfig,
};

let config = TunnelProviderConfig {
    provider: "cloudflare".to_string(),
    cloudflare: Some(CloudflareTunnelConfig {
        token: "eyJh...".to_string(),
    }),
    ..Default::default()
};

let tunnel = create_tunnel(&config)?.unwrap();

// Start tunnel
let url = tunnel.start("127.0.0.1", 3000).await?;
println!("Tunnel URL: {}", url);

// Health check
if tunnel.health_check().await {
    println!("Tunnel is healthy");
}

// Get URL
if let Some(url) = tunnel.public_url() {
    println!("Public URL: {}", url);
}

// Stop tunnel
tunnel.stop().await?;
```

### Tunnel Trait

```rust theme={null}
#[async_trait]
pub trait Tunnel: Send + Sync {
    fn name(&self) -> &str;
    
    async fn start(&self, local_host: &str, local_port: u16) -> Result<String>;
    
    async fn stop(&self) -> Result<()>;
    
    async fn health_check(&self) -> bool;
    
    fn public_url(&self) -> Option<String>;
}
```

## Security Considerations

### Tunnel Authentication

* **Cloudflare**: Zero Trust policies (IP restrictions, auth providers)
* **Tailscale**: ACLs, MagicDNS, device authorization
* **ngrok**: Basic auth, OAuth, SAML (paid plans)
* **Custom**: Depends on provider

### Gateway Authentication

In addition to tunnel auth, IronClaw gateway has:

* API key authentication (`GATEWAY_API_KEY`)
* Rate limiting
* Request validation
* CORS configuration

### Recommended Setup

**Production**:

```bash theme={null}
TUNNEL_PROVIDER=cloudflare
TUNNEL_CF_TOKEN=...
GATEWAY_API_KEY=...  # Strong random key
```

**Development**:

```bash theme={null}
TUNNEL_PROVIDER=none
# Access via localhost:3000 only
```

**Team Access**:

```bash theme={null}
TUNNEL_PROVIDER=tailscale
TUNNEL_TS_FUNNEL=false  # Tailnet-only
```

## Troubleshooting

### Tunnel Process Dies

```
Error: Tunnel health check failed
```

**Solutions**:

1. Check binary is installed: `which cloudflared`
2. Check logs for tunnel errors
3. Verify credentials are valid
4. Ensure port is not already in use

### URL Not Extracted

```
Warning: Could not extract tunnel URL from output
```

**Solutions**:

1. Check tunnel binary output format hasn't changed
2. For custom tunnels, verify `url_pattern` matches
3. Increase startup timeout
4. Check logs for tunnel startup errors

### Connection Refused

```
Error: Connection refused at https://random.cfargotunnel.com
```

**Causes**:

1. Tunnel not fully started (takes 10-30s)
2. Gateway not listening on correct port
3. Firewall blocking outbound tunnel connection

**Solutions**:

1. Wait 30 seconds and retry
2. Check gateway is running: `lsof -i :3000`
3. Verify `GATEWAY_PORT` matches tunnel forwarding

### Cloudflare 502 Bad Gateway

```
Error 502: Bad Gateway
```

**Causes**:

1. Gateway crashed after tunnel started
2. Port mismatch between gateway and tunnel
3. Network connectivity issues

**Solutions**:

1. Restart IronClaw
2. Verify `GATEWAY_PORT` configuration
3. Check gateway health: `curl localhost:3000/health`

## Performance

### Latency

| Provider | Typical Latency | Notes |
| - | - | - |
| None | 0ms | Local only |
| Tailscale | 10-50ms | Direct peer-to-peer when possible |
| Cloudflare | 20-100ms | Global CDN, varies by region |
| ngrok | 50-200ms | Depends on edge location |

### Throughput

* **Cloudflare**: Unlimited bandwidth
* **Tailscale**: Full network speed (P2P)
* **ngrok**: Rate limited on free plan

### Recommendations

* **Low latency**: Tailscale (P2P) or None (local)
* **High throughput**: Cloudflare or Tailscale
* **Quick setup**: ngrok
* **Production**: Cloudflare (Zero Trust) or Tailscale (team)

## Source Code

Key files:

* `src/tunnel/mod.rs` - Tunnel trait and factory
* `src/tunnel/cloudflare.rs` - Cloudflare implementation
* `src/tunnel/tailscale.rs` - Tailscale implementation
* `src/tunnel/ngrok.rs` - ngrok implementation
* `src/tunnel/custom.rs` - Custom tunnel implementation
* `src/tunnel/none.rs` - No-tunnel implementation
