Overview
The OrcBot Web Gateway provides:
REST API for remote control and management
WebSocket for real-time events and bidirectional communication
Dashboard hosting for web-based interfaces
Secure authentication with API keys
Quick Start
Start the Gateway
Basic
With Agent
Custom Port
Serve Dashboard
orcbot gateway
# Gateway starts on http://localhost:3100
You should see:
Gateway: Serving static files from /path/to/dashboard
Gateway Server listening on http://0.0.0.0:3100
Configuration
Basic Settings
# ~/.orcbot/orcbot.config.yaml
# Gateway server settings
gatewayPort : 3100
gatewayHost : 0.0.0.0 # Listen on all interfaces
# Security
gatewayApiKey : your-secret-api-key-here
# CORS origins
gatewayCorsOrigins :
- "*" # Allow all (development only!)
# - "https://yourdomain.com" # Production
# Rate limiting
gatewayRateLimitPerMinute : 180 # 180 requests per minute
# Static files (optional)
gatewayStaticDir : ./apps/dashboard
Generate API Key
Auto-Generate
curl -X POST http://localhost:3100/api/gateway/token/rotate
Returns: {
"token" : "a7f3...c2b1" , // 64-char hex token
"message" : "New API key generated and saved to config"
}
Manual
# Generate random token
openssl rand -hex 32
Add to config: gatewayApiKey : "a7f3c4b9...your-token"
Verify
curl http://localhost:3100/api/gateway/token/status
Shows: {
"authEnabled" : true ,
"tokenPartial" : "a7f3****...c2b1" ,
"tokenLength" : 64
}
REST API
Authentication
Include API key in requests:
Header (Recommended)
Bearer Token
Query Parameter
curl -H "X-Api-Key: your-secret-key" \
http://localhost:3100/api/status
API Endpoints
Status & Info
GET /api/status
GET /api/health
GET /api/gateway/capabilities
curl http://localhost:3100/api/status
# Returns agent status, model, memory, queue info
Tasks & Queue
POST /api/tasks
GET /api/tasks
GET /api/tasks/:id
POST /api/tasks/:id/cancel
POST /api/tasks/clear
curl -X POST http://localhost:3100/api/tasks \
-H "Content-Type: application/json" \
-d '{
"description": "Summarize latest AI news",
"priority": 10
}'
# Creates new task
Chat Interface
POST /api/chat/send
GET /api/chat/history
GET /api/chat/export
POST /api/chat/clear
curl -X POST http://localhost:3100/api/chat/send \
-H "Content-Type: application/json" \
-d '{
"message": "What\'s the weather like?",
"sourceId": "web-client-123"
}'
# Send chat message, agent responds
Memory
GET /api/memory
GET /api/memory/stats
GET /api/memory/search
curl http://localhost:3100/api/memory?type=short & limit = 20
# Get recent memories
Configuration
GET /api/config
GET /api/config/:key
PUT /api/config/:key
curl http://localhost:3100/api/config
# Get all configuration
GET /api/skills
POST /api/skills/:name/execute
GET /api/skills/health
curl http://localhost:3100/api/skills
# List all available skills
Models & Providers
GET /api/models
PUT /api/models
GET /api/providers
GET /api/tokens
curl http://localhost:3100/api/models
# Get current model and availability
Security
GET /api/security
PUT /api/security
curl http://localhost:3100/api/security
# Get security settings
Logs
curl http://localhost:3100/api/logs?lines= 50
# Get recent log entries
WebSocket API
Connect to WebSocket
const ws = new WebSocket ( 'ws://localhost:3100' );
ws . onopen = () => {
console . log ( 'Connected to OrcBot gateway' );
// Subscribe to events
ws . send ( JSON . stringify ({
action: 'subscribe' ,
events: [ 'status' , 'event' , 'chat' ]
}));
};
ws . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
console . log ( 'Received:' , data );
};
WebSocket Events
Agent status updates: {
"type" : "status" ,
"data" : {
"agentName" : "OrcBot" ,
"modelName" : "gpt-4o-mini" ,
"isProcessing" : true ,
"queueSize" : 3 ,
"activeTaskId" : "act_abc123"
}
}
Agent events (thinking, action, observation): {
"type" : "event" ,
"data" : {
"eventType" : "action" ,
"actionId" : "act_abc123" ,
"step" : 3 ,
"skill" : "web_search" ,
"args" : { "query" : "latest AI news" }
}
}
Chat message events: {
"type" : "chat:message" ,
"data" : {
"id" : "msg_123" ,
"role" : "assistant" ,
"content" : "Here's the latest AI news..." ,
"timestamp" : "2024-03-15T10:30:00Z"
}
}
WebSocket Actions
Send commands via WebSocket:
Push Task
Execute Skill
Send Chat Message
Get Status
Update Config
ws . send ( JSON . stringify ({
action: 'pushTask' ,
description: 'Analyze server logs' ,
priority: 10
}));
Security
API Key Authentication
The gateway uses timing-safe comparison for API keys:
try {
authenticated = crypto . timingSafeEqual (
Buffer . from ( providedKey , 'utf8' ),
Buffer . from ( apiKey , 'utf8' )
);
} catch {
authenticated = false ;
}
Automatically applied to all responses:
res . setHeader ( 'X-Content-Type-Options' , 'nosniff' );
res . setHeader ( 'X-Frame-Options' , 'SAMEORIGIN' );
res . setHeader ( 'Referrer-Policy' , 'no-referrer' );
res . setHeader ( 'Permissions-Policy' , 'camera=(), microphone=(), geolocation=()' );
res . setHeader ( 'Cache-Control' , 'no-store' );
Rate Limiting
Per-IP rate limiting:
gatewayRateLimitPerMinute : 180 # 180 requests/minute per IP
Exceeding limit returns:
{
"error" : "Too many requests. Slow down and retry shortly." ,
"requestId" : "req_abc123"
}
CORS Configuration
gatewayCorsOrigins :
- "*" # Allow all origins
gatewayCorsOrigins :
- "https://yourdomain.com"
- "https://app.yourdomain.com"
Remote Access with Tailscale
Do NOT expose the gateway directly to the internet. Use a private network like Tailscale.
Why Tailscale?
Private mesh network (WireGuard-based)
No port forwarding needed
Zero-trust access control
End-to-end encryption
Works across NAT/firewalls
Setup
Install Tailscale
# Linux
curl -fsSL https://tailscale.com/install.sh | sh
# macOS
brew install tailscale
Connect to Tailnet
Follow link to authenticate
Configure Gateway
gatewayHost : 0.0.0.0 # Listen on all interfaces
gatewayPort : 3100
gatewayApiKey : your-secret-key
Access Remotely
# Get Tailscale IP
tailscale ip -4
# Example: 100.64.1.2
# Access from any device on your Tailnet
curl http://100.64.1.2:3100/api/status
Set Up ACLs (Optional)
In Tailscale admin console, restrict access: {
"acls" : [
{
"action" : "accept" ,
"src" : [ "group:admins" ],
"dst" : [ "tag:orcbot:3100" ]
}
]
}
Hosting a Dashboard
Static File Serving
Serve a web dashboard:
orcbot gateway -s ./apps/dashboard
Directory structure:
apps/dashboard/
├── index.html
├── app.js
├── style.css
└── assets/
├── logo.png
└── ...
Access at: http://localhost:3100/
API available at: http://localhost:3100/api/*
Example Dashboard Code
<! DOCTYPE html >
< html >
< head >
< title > OrcBot Dashboard </ title >
</ head >
< body >
< h1 > OrcBot Dashboard </ h1 >
< div id = "status" ></ div >
< div id = "chat" >
< div id = "messages" ></ div >
< input type = "text" id = "input" placeholder = "Message OrcBot..." >
< button onclick = " sendMessage ()" > Send </ button >
</ div >
< script >
const API_KEY = 'your-api-key' ;
const WS_URL = 'ws://localhost:3100' ;
// WebSocket connection
const ws = new WebSocket ( WS_URL );
ws . onopen = () => {
console . log ( 'Connected' );
ws . send ( JSON . stringify ({ action: 'subscribe' , events: [ 'chat' ] }));
};
ws . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
if ( data . type === 'chat:message' ) {
displayMessage ( data . data );
}
};
function sendMessage () {
const input = document . getElementById ( 'input' );
const message = input . value ;
ws . send ( JSON . stringify ({
action: 'sendChatMessage' ,
message ,
sourceId: 'dashboard'
}));
input . value = '' ;
}
function displayMessage ( msg ) {
const div = document . createElement ( 'div' );
div . className = msg . role ;
div . textContent = msg . content ;
document . getElementById ( 'messages' ). appendChild ( div );
}
// Fetch status
async function updateStatus () {
const res = await fetch ( '/api/status' , {
headers: { 'X-Api-Key' : API_KEY }
});
const status = await res . json ();
document . getElementById ( 'status' ). textContent =
`Model: ${ status . modelName } | Queue: ${ status . queueSize } ` ;
}
updateStatus ();
setInterval ( updateStatus , 5000 );
</ script >
</ body >
</ html >
Troubleshooting
Gateway Won’t Start
Check Port
# See if port is in use
lsof -i :3100
# Or use different port
orcbot gateway -p 8080
Check Logs
tail -f ~/.orcbot/logs/orcbot.log | grep -i gateway
Verify Config
gatewayPort : 3100
gatewayHost : 0.0.0.0
API Key Not Working
# Check token status
curl http://localhost:3100/api/gateway/token/status
# Rotate token if needed
curl -X POST http://localhost:3100/api/gateway/token/rotate
# Use new token
curl -H "X-Api-Key: new-token" http://localhost:3100/api/status
CORS Errors
In browser console:
Access to fetch at 'http://localhost:3100/api/status' from origin
'http://localhost:8080' has been blocked by CORS policy
Fix:
gatewayCorsOrigins :
- "http://localhost:8080" # Add your origin
WebSocket Disconnects
ws . onclose = ( event ) => {
console . log ( 'Disconnected:' , event . code , event . reason );
// Auto-reconnect
setTimeout (() => {
connectWebSocket ();
}, 5000 );
};
Best Practices
Security
Always set a strong gatewayApiKey
Use Tailscale or VPN for remote access
Restrict CORS origins in production
Enable rate limiting
Monitor logs for suspicious activity
Performance
Use WebSocket for real-time updates
Cache static assets with CDN
Set reasonable rate limits
Monitor memory usage with /api/health
Reliability
Implement WebSocket reconnection logic
Handle rate limit errors gracefully
Use request IDs for debugging
Monitor uptime and errors