Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/outray-tunnel/outray/llms.txt

Use this file to discover all available pages before exploring further.

The OutRay client and tunnel server communicate over a WebSocket connection using a JSON-based message protocol. Every message is a JSON object with a type field that identifies the message kind. Messages are serialized and deserialized using encodeMessage and decodeMessage from @outray/core.
import { encodeMessage, decodeMessage } from '@outray/core';

// Serialize before sending
const raw = encodeMessage({ type: 'open_tunnel', apiKey: '...' });
ws.send(raw);

// Deserialize on receipt
const message = decodeMessage(rawString);

Client → server messages

These messages are sent from the OutRay client to the tunnel server.

open_tunnel

Sent immediately after the WebSocket connection is opened. Requests a new tunnel and provides authentication and routing information.
interface OpenTunnelMessage {
  type: "open_tunnel";
  subdomain?: string | null;
  customDomain?: string | null;
  apiKey?: string;
  forceTakeover?: boolean;
  protocol?: TunnelProtocol;      // "http" | "tcp" | "udp"
  remotePort?: number;
  password?: string;
}
type
string
required
Always "open_tunnel".
apiKey
string
Org-scoped authentication token. Required for custom subdomains and authenticated tunnels.
subdomain
string
Requested subdomain (HTTP tunnels only). Omit for a randomly generated URL.
customDomain
string
Custom fully-qualified domain name (HTTP tunnels only). Must be pre-configured in the dashboard.
protocol
string
Tunnel protocol: "http", "tcp", or "udp". Defaults to "http" if omitted.
remotePort
number
Requested public port (TCP/UDP tunnels only). The server assigns a different port if this one is unavailable.
password
string
HTTP Basic Auth password (HTTP tunnels only). When set, the server requires authentication before forwarding requests.
forceTakeover
boolean
When true, the server forcefully reassigns the requested subdomain even if another client currently holds it. The client sets this automatically when reconnecting after a clean disconnect.

response

Sent by the client in reply to a request message. Contains the HTTP response from the local service.
interface TunnelResponseMessage {
  type: "response";
  requestId: string;
  statusCode: number;
  headers: Record<string, string | string[]>;
  body?: string;  // base64 encoded
}
requestId
string
required
The request ID from the originating request message. Used to match responses to requests.
statusCode
number
required
HTTP status code returned by the local service (e.g. 200, 404, 502).
headers
object
required
HTTP response headers as key/value pairs. Header values may be strings or arrays of strings.
body
string
Response body, base64-encoded. Omitted for responses with no body.

tcp_data (client → server)

Sends a chunk of TCP data from the local service back to the remote client.
interface TCPDataMessage {
  type: "tcp_data";
  connectionId: string;
  data: string;  // base64 encoded
}
connectionId
string
required
Identifies the TCP connection this data belongs to.
data
string
required
Raw TCP bytes, base64-encoded.

tcp_close (client → server)

Signals that the client has closed its end of a TCP connection.
interface TCPCloseMessage {
  type: "tcp_close";
  connectionId: string;
}

udp_response

Sends a UDP response datagram back to the remote sender.
interface UDPResponseMessage {
  type: "udp_response";
  packetId: string;
  targetAddress: string;
  targetPort: number;
  data: string;  // base64 encoded
}
packetId
string
required
Correlates the response with the originating udp_data message.
targetAddress
string
required
IP address of the remote UDP sender to reply to.
targetPort
number
required
Port of the remote UDP sender to reply to.
data
string
required
UDP response payload, base64-encoded.

ws_upgrade_response

Confirms or rejects a WebSocket upgrade request from the server.
interface WSUpgradeResponseMessage {
  type: "ws_upgrade_response";
  wsConnectionId: string;
  success: boolean;
  error?: string;
}
wsConnectionId
string
required
Matches the wsConnectionId from the originating ws_upgrade message.
success
boolean
required
true if the client successfully connected to the local WebSocket service.
error
string
Error description when success is false.

ws_frame (client → server)

Relays a WebSocket frame from the local service back to the remote client.
interface WSFrameMessage {
  type: "ws_frame";
  wsConnectionId: string;
  data: string;    // base64 encoded
  isBinary: boolean;
}

ws_close (client → server)

Signals that the local WebSocket connection has closed.
interface WSCloseMessage {
  type: "ws_close";
  wsConnectionId: string;
  code?: number;
  reason?: string;
}

Server → client messages

These messages are sent from the tunnel server to the OutRay client.

tunnel_opened

Sent by the server once the tunnel is established. Contains the public URL (HTTP) or port number (TCP/UDP) assigned to the connection.
interface TunnelOpenedMessage {
  type: "tunnel_opened";
  url: string;
  protocol?: TunnelProtocol;  // "http" | "tcp" | "udp"
  port?: number;
}
url
string
required
The public URL assigned to the tunnel. For HTTP tunnels this is an HTTPS URL such as https://abc123.tunnel.outray.app. For TCP/UDP tunnels this is a placeholder URL; use port for the actual public port.
protocol
string
The active tunnel protocol.
port
number
The assigned public port for TCP/UDP tunnels.

request

Forwards an HTTP request from an internet visitor to the client for local proxying.
interface TunnelDataMessage {
  type: "request";
  requestId: string;
  method: string;
  path: string;
  headers: Record<string, string | string[]>;
  body?: string;  // base64 encoded
}
requestId
string
required
Unique ID for this request. Must be echoed back in the corresponding response message.
method
string
required
HTTP method, e.g. "GET", "POST".
path
string
required
Request path and query string, e.g. "/api/users?page=1".
headers
object
required
HTTP request headers forwarded from the visitor.
body
string
Request body, base64-encoded. Omitted for requests with no body.

tcp_connection

Notifies the client that a new remote TCP client has connected to the public port.
interface TCPConnectionMessage {
  type: "tcp_connection";
  connectionId: string;
}
connectionId
string
required
Unique identifier for this TCP connection. Used to correlate subsequent tcp_data and tcp_close messages.

tcp_data (server → client)

Delivers a chunk of data received from the remote TCP client.
interface TCPIncomingDataMessage {
  type: "tcp_data";
  connectionId: string;
  data: string;  // base64 encoded
}

tcp_close (server → client)

Signals that the remote TCP client has closed the connection.
interface TCPIncomingCloseMessage {
  type: "tcp_close";
  connectionId: string;
}

udp_data

Delivers a UDP datagram received from an internet sender.
interface UDPDataMessage {
  type: "udp_data";
  packetId: string;
  sourceAddress: string;
  sourcePort: number;
  data: string;  // base64 encoded
}
packetId
string
required
Unique identifier for this datagram. Echo it back in the udp_response message.
sourceAddress
string
required
IP address of the remote UDP sender.
sourcePort
number
required
Port of the remote UDP sender.
data
string
required
UDP payload, base64-encoded.

error

Sent by the server when a request cannot be fulfilled. Fatal errors (AUTH_FAILED, LIMIT_EXCEEDED) cause the client to stop reconnecting.
interface ErrorMessage {
  type: "error";
  code: string;   // one of the ErrorCode values
  message: string;
}
code
string
required
Machine-readable error code. See error codes below.
message
string
required
Human-readable description of the error.

ws_upgrade

Sent when an internet visitor upgrades an HTTP connection to WebSocket. The client must connect to the local WebSocket service and reply with ws_upgrade_response.
interface WSUpgradeMessage {
  type: "ws_upgrade";
  wsConnectionId: string;
  path: string;
  headers: Record<string, string | string[]>;
  protocol?: string;
}
wsConnectionId
string
required
Unique ID for this WebSocket connection. Used to correlate all subsequent ws_frame and ws_close messages.
path
string
required
The WebSocket upgrade path, e.g. "/socket.io/".
headers
object
required
HTTP headers from the upgrade request.
protocol
string
Requested WebSocket sub-protocol, if any.

ws_frame (server → client)

Relays a WebSocket frame from the internet visitor to the client, which forwards it to the local service.
interface WSFrameMessage {
  type: "ws_frame";
  wsConnectionId: string;
  data: string;    // base64 encoded
  isBinary: boolean;
}

ws_close (server → client)

Signals that the internet visitor has closed the WebSocket connection.
interface WSCloseMessage {
  type: "ws_close";
  wsConnectionId: string;
  code?: number;
  reason?: string;
}

Message type summary

MessageDirectionProtocolDescription
open_tunnelClient → ServerAllOpen a new tunnel.
tunnel_openedServer → ClientAllTunnel established; provides public URL or port.
requestServer → ClientHTTPForward an HTTP request to the local service.
responseClient → ServerHTTPReturn the HTTP response to the server.
tcp_connectionServer → ClientTCPA new remote TCP client connected.
tcp_dataBothTCPRelay a chunk of TCP data.
tcp_closeBothTCPClose a TCP connection.
udp_dataServer → ClientUDPA UDP datagram from a remote sender.
udp_responseClient → ServerUDPA UDP response datagram.
ws_upgradeServer → ClientHTTPVisitor is upgrading to WebSocket.
ws_upgrade_responseClient → ServerHTTPConfirm or reject the WebSocket upgrade.
ws_frameBothHTTPRelay a WebSocket frame.
ws_closeBothHTTPClose a WebSocket connection.
errorServer → ClientAllAn error occurred.

Error codes

Error codes are defined in packages/core/src/types.ts and exported as ErrorCodes.
export const ErrorCodes = {
  SUBDOMAIN_IN_USE: "SUBDOMAIN_IN_USE",
  AUTH_FAILED: "AUTH_FAILED",
  LIMIT_EXCEEDED: "LIMIT_EXCEEDED",
  INVALID_SUBDOMAIN: "INVALID_SUBDOMAIN",
  CUSTOM_DOMAIN_NOT_CONFIGURED: "CUSTOM_DOMAIN_NOT_CONFIGURED",
} as const;
CodeFatalDescription
SUBDOMAIN_IN_USENoThe requested subdomain is currently held by another connection. The client automatically retries with forceTakeover: true.
AUTH_FAILEDYesThe provided API key is invalid or expired. The client stops reconnecting; the user must re-authenticate.
LIMIT_EXCEEDEDYesThe organization has reached its concurrent tunnel limit. The client stops reconnecting.
INVALID_SUBDOMAINNoThe requested subdomain contains characters that are not allowed.
CUSTOM_DOMAIN_NOT_CONFIGUREDNoThe requested custom domain has not been configured in the OutRay dashboard.
Fatal errors (AUTH_FAILED, LIMIT_EXCEEDED) cause OutrayClient to call stop() internally, preventing further reconnect attempts. All other errors allow the client to reconnect.

Build docs developers (and LLMs) love