Tunnels
Connect local services to Mirra via secure WebSocket tunnels
Mirra Tunnels provide secure WebSocket connections that let you expose local services (like Claude Code, custom APIs, or development servers) to Mirra without making them publicly accessible.
What you can do with tunnels
- Control Claude Code remotely — The Claude Code Bridge uses tunnels to receive commands from your phone
- Connect local AI services — Route requests to local LLMs, coding assistants, or custom tools
- Development testing — Expose local APIs to Mirra Flows during development
- Multiple services — Run different tunnels for different local services on the same machine
How tunnels work
- Tunnel client connects to Mirra via WebSocket and authenticates with your API key
- HTTP requests to your tunnel URL are forwarded through the WebSocket
- Tunnel client proxies requests to your local service and returns responses
- No port forwarding or public IPs needed — everything goes through Mirra's servers
Quick start with Claude Code Bridge
The easiest way to set up a tunnel is with the Claude Code Bridge:
This starts a tunnel that:
- Connects to Mirra using your API key
- Runs a local server on port 3847
- Handles Claude Code session management
See Claude Code Bridge for the full setup guide.
Prerequisites
To set up a custom tunnel, you need:
| Requirement | Notes |
|---|---|
| Node.js 18+ | For running the tunnel client |
| Mirra API key | From your Mirra account or the mobile app |
| Local service | The HTTP server you want to expose |
Setting up a custom tunnel
1. Get your API key
You can get an API key from:
- Mirra mobile app → Settings → API Keys
- Browser auth during
mirra-cc-bridge configure - Mirra Store → Developer Settings
2. Create a tunnel client
Here's a minimal tunnel client in Node.js:
3. Start your local service
Make sure your local service is running on the configured port:
4. Start the tunnel
You should see:
Named tunnels
You can run multiple tunnels for different services by using different tunnel names:
Each tunnel gets its own URL:
- Default:
https://api.fxn.world/tunnel/{userId} - Named:
https://api.fxn.world/tunnel/{userId}/{tunnelName}
Accessing tunnels from Flows
Use the tunnel adapter in your Mirra Flows:
Protocol reference
Message types
| Type | Direction | Purpose |
|---|---|---|
tunnel:connect | Client → Server | Authenticate and establish tunnel |
tunnel:connected | Server → Client | Confirm connection with tunnel URL |
tunnel:ping | Server → Client | Keepalive check (every 30s) |
tunnel:pong | Client → Server | Keepalive response |
tunnel:http_request | Server → Client | Forward HTTP request |
tunnel:http_response | Client → Server | Return HTTP response |
tunnel:error | Either | Error notification |
Connect message
HTTP request message
HTTP response message
The requestId in the response must match the request. Mirra uses this to correlate responses with pending HTTP requests.
Keepalive
The server sends tunnel:ping every 30 seconds. Your client must respond with tunnel:pong within 10 seconds or the connection will be terminated.
Error handling
Connection errors
| Error code | Meaning | Action |
|---|---|---|
AUTH_REQUIRED | No API key provided | Include apiKey in connect message |
AUTH_FAILED | Invalid API key | Check your API key is valid |
| Close code 4001 | Authentication rejected | Re-authenticate or get new API key |
Reconnection
On unexpected disconnection, wait 5 seconds and reconnect:
Don't reconnect on AUTH_FAILED — the API key is invalid and reconnecting won't help. Get a new API key instead.
Security
Authentication
- Tunnels authenticate using your Mirra API key
- API keys are hashed before storage — we never see your raw key
- Invalid keys are rejected immediately
Transport security
- All connections use WSS (WebSocket Secure)
- HTTP requests through the tunnel use HTTPS endpoints
- No plaintext data transmission
Access control
- Only requests authenticated to your Mirra account can use your tunnel
- Internal calls from Mirra Flows use signed headers
- Each tunnel is isolated to your user ID
Anyone with access to your Mirra account can send requests through your tunnel. Treat tunnel access like SSH access to your machine.
Troubleshooting
"Authentication failed"
Your API key is invalid or expired. Get a new one from:
- Mirra mobile app → Settings → API Keys
- Run
mirra-cc-bridge configureto re-authenticate
Tunnel keeps disconnecting
- Check your internet connection stability
- Ensure you're responding to
tunnel:pingwithtunnel:pong - Look for error messages before disconnect
Requests timing out
- Verify your local service is running
- Check the correct port is configured
- Ensure your service responds within 30 seconds
"No tunnel connection" errors
- The tunnel client isn't running
- Authentication failed silently — check logs
- Network blocked WebSocket connections
Configuration defaults
| Setting | Value |
|---|---|
| WebSocket URL | wss://api.fxn.world/tunnel/ws |
| Request timeout | 30 seconds |
| Ping interval | 30 seconds |
| Pong timeout | 10 seconds |
| Default tunnel name | default |
| Default local port | 3847 (Claude Code Bridge) |
Next steps
- Claude Code Bridge — Full guide for controlling Claude Code remotely
- Flows — Build automations that use your tunnel
- API Reference — Create resources that proxy through tunnels