Skip to main content
Wormkey uses environment variables to configure the CLI, control plane, and gateway. This page documents all available variables and their defaults.

CLI Environment Variables

These variables configure the Wormkey CLI when opening tunnels.
VariableDefaultDescription
WORMKEY_ENV(none)Set to local to use localhost defaults for control plane and edge
WORMKEY_CONTROL_PLANE_URLProduction: https://wormkey-control-plane.onrender.com
Local: http://localhost:3001
Control plane API endpoint for session creation
WORMKEY_EDGE_URLProduction: wss://t.wormkey.run/tunnel
Local: ws://localhost:3002/tunnel
Gateway WebSocket endpoint for tunnel connections

CLI Examples

WORMKEY_CONTROL_PLANE_URL=http://localhost:3001
WORMKEY_EDGE_URL=ws://localhost:3002/tunnel
Use ws:// for local development and wss:// (secure WebSocket) for production deployments.

Control Plane Environment Variables

The control plane manages session lifecycle and slug allocation.
VariableDefaultDescription
PORT3001HTTP server port for control plane API
WORMKEY_PUBLIC_BASE_URLhttp://localhost:3002Public-facing base URL for wormhole links (used in session creation response)
WORMKEY_EDGE_BASE_URLws://localhost:3002Gateway WebSocket base URL (returned to CLI for tunnel connection)

Control Plane Configuration Details

PORT

The HTTP port where the control plane listens. The server binds to 0.0.0.0 to accept connections from any interface. Source reference: packages/control-plane/src/index.ts:252
const port = parseInt(process.env.PORT ?? "3001", 10);
await fastify.listen({ port, host: "0.0.0.0" });

WORMKEY_PUBLIC_BASE_URL

This is the canonical public origin that users will visit to access wormholes. It’s used to construct:
  • Public URLs: ${WORMKEY_PUBLIC_BASE_URL}/s/${slug}
  • Owner URLs: ${WORMKEY_PUBLIC_BASE_URL}/.wormkey/owner?slug=${slug}&token=${token}
  • Overlay script URLs: ${WORMKEY_PUBLIC_BASE_URL}/.wormkey/overlay.js?slug=${slug}
Source reference: packages/control-plane/src/index.ts:34-37
const PUBLIC_BASE_URL =
  process.env.WORMKEY_PUBLIC_BASE_URL ?? "http://localhost:3002";

WORMKEY_EDGE_BASE_URL

The WebSocket base URL where the gateway accepts tunnel connections. The control plane returns this to the CLI during session creation. Source reference: packages/control-plane/src/index.ts:36-37
const EDGE_BASE_URL =
  process.env.WORMKEY_EDGE_BASE_URL ?? "ws://localhost:3002";

Control Plane Examples

PORT=3001
WORMKEY_PUBLIC_BASE_URL=http://localhost:3002
WORMKEY_EDGE_BASE_URL=ws://localhost:3002

Gateway Environment Variables

The gateway handles TLS termination, routing, and stream forwarding.
VariableDefaultDescription
PORT3002HTTP/WebSocket server port
WORMKEY_CONTROL_PLANEhttps://wormkey-control-plane.onrender.comControl plane URL for session validation and state sync
WORMKEY_PUBLIC_BASE_URLhttp://localhost:3002Public base URL (fallback for URL generation)
WORMKEY_PUBLIC_BASEhttp://localhost:3002Legacy alias for WORMKEY_PUBLIC_BASE_URL

Gateway Configuration Details

PORT

The server listens on this port for both HTTP traffic and WebSocket tunnel connections. Binds to 0.0.0.0. Source reference: packages/gateway/main.go:717-720
port := os.Getenv("PORT")
if port == "" {
    port = "3002" // local fallback only
}

WORMKEY_CONTROL_PLANE

The gateway queries the control plane to:
  • Validate sessions and tokens
  • Fetch session policies (public/private, max viewers, blocked paths)
  • Sync viewer state and kicked viewer lists
  • Check if sessions are closed
Source reference: packages/gateway/main.go:480
controlPlaneURL := getEnv("WORMKEY_CONTROL_PLANE", "https://wormkey-control-plane.onrender.com")
The gateway requires access to the control plane for production deployments. If the control plane is unreachable, session validation and state synchronization will fail, but existing tunnel connections will continue to work.

Gateway Examples

PORT=3002
WORMKEY_CONTROL_PLANE=http://localhost:3001
WORMKEY_PUBLIC_BASE_URL=http://localhost:3002

Session Configuration

These values are hardcoded in the control plane but can be modified in the source code.
SettingDefaultLocation
Default expiration24hCan be overridden via CLI --expires flag
Max concurrent viewers20packages/control-plane/src/index.ts:122
Session policy defaults{ public: true, maxConcurrentViewers: 20, blockPaths: [], password: "" }packages/control-plane/src/index.ts:120-125
Slug format{adjective}-{noun}-{number}Generated from predefined word lists
Token length32 charactersLowercase alphanumeric
Basic auth usernamewormWhen using --auth flag
Basic auth password length8 charactersRandom alphanumeric

Modifying Session Defaults

To change default session behavior, edit packages/control-plane/src/index.ts:
const session: Session = {
  // ... other fields
  policy: {
    public: true,                    // Change to false to require owner approval
    maxConcurrentViewers: 20,        // Increase/decrease viewer limit
    blockPaths: [],                  // Add default blocked paths
    password: "",                    // Set default password
  },
  // ...
};

Slug Generation

Slugs follow the pattern {adjective}-{noun}-{number} (e.g., quiet-lime-82). Word Lists (packages/control-plane/src/index.ts:9-16):
const ADJECTIVES = [
  "quiet", "bold", "swift", "calm", "bright", "soft", "warm", "cool",
  "deep", "flat", "wild", "mild", "dark", "pale", "pure", "rare", "max"
];

const NOUNS = [
  "lime", "mint", "sage", "rose", "sky", "sea", "sand", "snow",
  "mist", "dawn", "dusk", "flame", "storm", "wave", "wind", "frost", "tooth"
];
Numbers range from 1-99.

Protocol Configuration

The gateway and CLI use a binary protocol over WebSocket. Frame types are hardcoded: Source reference: packages/gateway/main.go:32-44
const (
    FrameOpenStream   = 0x01
    FrameStreamData   = 0x02
    FrameStreamEnd    = 0x03
    FrameStreamCancel = 0x04
    FrameResponseHdrs = 0x05
    FrameWSUpgrade    = 0x06
    FrameWSData       = 0x07
    FrameWSClose      = 0x08
    FramePing         = 0x09
    FramePong         = 0x0a
    ControlStreamID   = 0
)
See the Protocol Documentation for details.

Complete .env Example

Here’s a complete .env file for local development:
# ============================================
# Wormkey Environment Configuration
# ============================================

# --------------------------------------------
# CLI Configuration
# --------------------------------------------
WORMKEY_CONTROL_PLANE_URL=http://localhost:3001
WORMKEY_EDGE_URL=ws://localhost:3002/tunnel

# --------------------------------------------
# Control Plane Configuration
# --------------------------------------------
# PORT=3001  # Uncomment to change from default
WORMKEY_PUBLIC_BASE_URL=http://localhost:3002
WORMKEY_EDGE_BASE_URL=ws://localhost:3002

# --------------------------------------------
# Gateway Configuration
# --------------------------------------------
# PORT=3002  # Uncomment to change from default
WORMKEY_CONTROL_PLANE=http://localhost:3001
WORMKEY_PUBLIC_BASE_URL=http://localhost:3002

Production Considerations

Security: In production, always use HTTPS (https://) and secure WebSockets (wss://). Never expose unencrypted endpoints to the public internet.
  1. Use a reverse proxy (nginx, Caddy) for TLS termination
  2. Set secure WebSocket URLs with wss:// protocol
  3. Configure CORS if control plane and gateway are on different domains
  4. Use a process manager (PM2, systemd) to keep services running
  5. Set up monitoring for all three components
  6. Consider rate limiting at the reverse proxy level
See Deployment for detailed production setup instructions.

Build docs developers (and LLMs) love