A comprehensive, real-time system for managing distributed Doh instances through a unified web dashboard. Cloud Manager enables remote administration, file synchronization, Git repository management, direct SSH terminal access, and collaborative sharing across multiple cloud-connected Doh deployments.
Cloud Manager transforms individual Doh instances into a connected, event-driven ecosystem where you can:
Think of it as your mission control for distributed Doh deployments, built on a secure, modern, and event-driven architecture.
Each connected Doh deployment appears as an "instance" in Cloud Manager. Instances maintain persistent connections via WebSocket and can be controlled remotely. Instances can be owned or shared, with ownership and permissions clearly displayed in the UI.
A Cloud Manager is not a special type of server; it is simply a standard Doh instance with the cloud_manager module installed. This provides incredible flexibility:
Any instance owner can share access with other usersβeither to specific instances or all their instances. Shares can have custom permissions (e.g., read-only, command execution) and optional expiration dates, with all access managed through a secure, database-driven system.
Smart bidirectional sync between instances with conflict detection, progress tracking, and caching. You can perform one-time syncs or create persistent "Active Mirrors" for ongoing relationships.
Cloud Manager provides multiple ways to manage instances remotely:
A WebSocket-based protocol allowing developer tools to securely connect to the Cloud Manager and interact with managed instances. This enables advanced, programmatic control and automation.
Cloud Manager can act as a reverse proxy for managed instances, creating HTTPS servers that forward HTTP and Socket.IO traffic to instances over the secure WebSocket connection. This allows external access to instances without direct network exposure, with each instance accessible on a unique port.
The Cloud Manager dashboard, accessible at /admin/cloud, is a centralized UI for all management tasks. It features a responsive, event-driven interface that updates in real-time without polling.
pod.yaml configuration files of your connected instances.update, restart, and upgrade.Before you can connect instances, you need one Doh instance to act as the central manager.
Step 1: Install the Cloud Manager Module
On the Doh instance you want to designate as your Cloud Manager, run:
# This installs the manager UI and backend
doh install cloud cloud_manager
Step 2: Create a Superadmin User
A Cloud Manager needs at least one user account to own and manage instances. The easiest way to create the initial administrator is with the poduser command.
# Create a new user and grant them superadmin privileges
doh poduser
Follow the prompts to make a superadmin and set the username and password. This user will be able to log in to the Cloud Manager and anchor other instances to their account.
Step 3: Start Your Manager and Ensure It's Accessible
Run your Cloud Manager instance like any other Doh instance:
doh run
Ensure this instance is accessible over the network from any other instances you plan to connect.
Now, from any other Doh instance you want to manage, you can connect it to your new Cloud Manager.
The easiest way to connect is with a single command:
# Set the cloud endpoint and anchor the instance in one step
doh cloud anchor http://your-cloud-manager-url.com
This command will begin an interactive prompt for the username and password you created in Part 1. Your credentials are used only once to get a secure token and are never stored on the client instance.
Once anchored, the instance will appear on your Cloud Manager's dashboard.
Cloud Manager provides a fully functional, browser-based SSH terminal that is compatible with both Bun and Node.js runtimes.
script command on Unix-like systems to allocate a proper pseudo-terminal (PTY). This ensures that the shell runs in interactive mode, with a visible prompt and full support for terminal features, which is not possible with a standard child_process.spawn(). SIGWINCH handling.cd ~, doh update, etc.).command:cloud_instance).The File Sync tab provides a modern, efficient synchronization system with server-side comparison and cross-platform compatibility.
get_file_comparison_data command collects all file metadata (size, mtime, MD5) in one efficient callThe Git tab provides a comprehensive UI for managing Git repositories on any connected instance.
The Shares tab allows you to securely share access to your instances.
read:cloud_instance, command:cloud_instance). If no permissions are specified, the sharee inherits the owner's full permissions.The Cloud Manager can act as a reverse proxy for managed instances, allowing external clients to access instances without requiring direct network connectivity to each instance. This is particularly useful for:
How It Works:
When an instance connects to the cloud manager with reverse_proxy.enabled: true, the cloud manager automatically:
external_portArchitecture:
Configuration:
On the Cloud Manager, ensure SSL certificates are configured:
express_config:
ssl_info:
key: '/path/to/private.key'
cert: '/path/to/certificate.crt'
On the Managed Instance, enable reverse proxy:
cloud:
reverse_proxy:
enabled: true
external_port: 4443 # Unique port for this instance
HTTP Request Proxying:
https://cloud-manager:4443/api/endpointproxy_http_request socket event to instanceFeatures:
Socket.IO Event Proxying:
https://cloud-manager:4443proxy_socket_connectsocket.emit('my_event', data))proxy_socket_event with accumulated cookiessetCookiesCookie Management:
The cloud manager maintains a cookie jar for each connected Socket.IO client:
proxy_socket_eventsetCookies in response to update client cookiesThis ensures authentication state (e.g., accessToken cookies) is preserved across Socket.IO events, enabling secure, stateful connections through the proxy.
Port Mapping Lifecycle:
reverseProxyConfigportMappings (port β instanceId) and portServers (port β { httpsServer, io, app })Security Model:
Doh.permit() checks on the instanceEvents:
proxy_http_request (cloud β instance): HTTP request to proxyproxy_socket_connect (cloud β instance): New Socket.IO client connectedproxy_socket_event (cloud β instance): Socket.IO event from clientproxy_socket_disconnect (cloud β instance): Socket.IO client disconnectedproxy_socket_emit_{clientId} (instance β cloud β client): Response events back to specific clientExample Use Case:
# Cloud Manager (deploydoh.com)
express_config:
ssl_info:
key: '/etc/ssl/private.key'
cert: '/etc/ssl/certificate.crt'
# Managed Instance 1 (dev-server)
cloud:
endpoint: 'https://deploydoh.com'
reverse_proxy:
enabled: true
external_port: 4443
# Managed Instance 2 (staging-server)
cloud:
endpoint: 'https://deploydoh.com'
reverse_proxy:
enabled: true
external_port: 4444
Users can now access:
https://deploydoh.com:4443 β dev-serverhttps://deploydoh.com:4444 β staging-serverAll traffic is securely proxied through the cloud manager's WebSocket connections.
The cloud manager provides granular control over reverse proxy states, allowing you to temporarily pause external access to instances without disconnecting them.
Dashboard Controls:
The Proxies tab in the Cloud Manager dashboard displays all active reverse proxy instances with real-time status:
How Pause/Resume Works:
Pausing a Proxy:
Resuming a Proxy:
State Persistence:
Proxy states are stored in /.doh/static/cloud_proxies.yaml on the cloud manager:
{ inactive_proxies: { instanceId: "Reason - Timestamp" } }Use Cases:
API Endpoints:
GET /api/cloud/proxies/list: List all proxies with their current statesPOST /api/cloud/proxies/:instanceId/toggle: Toggle proxy state (pause/activate){ inactive: true/false, reason: "Optional reason" }{ success: true, inactive: true/false }Security:
command:cloud_instance permission on the target instanceCloud Manager is built on a modern, secure, and event-driven architecture with a DRY (Don't Repeat Yourself) design pattern.
The Cloud Manager implements a unified architecture where:
Cloud Manager as Orchestrator: The cloud_manager module serves as the central orchestrator for all cross-instance operations
Managed Site as Universal Anchor: All instances use the managed_site module as the universal anchor for consistent command handling
Server-Side Processing: File comparisons, sync operations, and data analysis are performed server-side to reduce network overhead
Single-Call Optimization: The get_file_comparison_data command collects all necessary file metadata in one efficient call
Centralized Logic: Duplicate comparison logic has been eliminated by centralizing file analysis in the Cloud Manager
Event-Driven UI: The dashboard uses a WebSocket connection to receive real-time updates from the server. There is no polling; data is pushed to the UI instantly when the state changes on the backend (e.g., an instance connects, a command completes).
JWT Authentication: Instance connections are secured using JSON Web Tokens (JWT). A short-lived siteAuthToken is generated for an instance to authenticate with the Cloud Manager.
Contextual Permissions: The system uses Doh's powerful contextual permission engine. Access is not based on simple roles, but is dynamically evaluated against the action being performed and the specific object being acted upon (e.g., Doh.permit(user, 'command:cloud_instance', instanceObject)). This allows for fine-grained control and secure sharing.
Database-Driven: Shares and Active Mirrors are persisted in a database, ensuring data integrity and consistency across sessions.
Secure Command & Git Handling: All remote operations are subject to path validation and command whitelisting to prevent unauthorized access or execution.
Reverse Proxy Security: SSL/TLS required for all proxy servers, cookie state isolation per client, same authentication/authorization model as direct access, timeout protection, and automatic cleanup on disconnect.
The Cloud Manager now includes enhanced cross-platform file synchronization capabilities:
isFileBinary function.doh/, node_modules/) instead of simple string matching.doh.yaml are properly included in sync operationsThe Cloud Manager exposes a REST API for programmatic control.
Cloud Manager pushes real-time updates to dashboard clients via Socket.IO.
cloud:instance-update
{
"totalInstances": 3,
"totalMcpClients": 1,
"totalUsers": 2,
"instances": [{
"id": "fp-123",
"userId": "alice",
"info": { "fingerprint": "fp-123", "friendlyName": "prod-eu", "hostname": "prod.example.com", "port": 443, "https": true },
"detailedInfo": null,
"status": "connected",
"connectedAt": "2025-01-01T12:00:00.000Z",
"lastHeartbeat": "2025-01-01T12:01:00.000Z",
"lastActivity": "2025-01-01T12:01:00.000Z",
"health": { "memory": {}, "cpu": {}, "uptime": 12345 },
"commandCount": 4,
"online": true,
"lastVerified": "2025-01-01T12:01:00.000Z",
"responseTime": 85,
"mcpControllable": true
}],
"timestamp": "2025-01-01T12:01:00.000Z"
}
cloud:command-progress
{ instanceId, commandId, progress, timestamp }.cloud:sync-activity
{
"id": "op-789",
"type": "push",
"status": "running",
"path": "/var/www/app",
"sourceId": "fp-src",
"destinationId": "fp-dst",
"sourceName": "dev",
"destinationName": "prod",
"message": "Syncing 42 file(s)...",
"filesCount": 42,
"timestamp": "2025-01-01T12:02:00.000Z"
}
tty_data, tty_exit
Dedicated Socket.IO namespace for MCP-compatible developer tools.
Authenticate: mcp:authenticate
{ siteAuthToken, connectionType: "mcp_client" }{ success, connectionId, userId, connectionType }Commands: mcp:command
mcp:list_user_instances, mcp:get_logs, mcp:restart_instance, mcp:sync_files, mcp:run_command, mcp:get_status, mcp:cross_instance_sync_files, mcp:cross_instance_sync_folder, mcp:compare_files_cross_instance, mcp:execute_sync_from_comparison{ targetInstance, params } (fingerprint or instanceId in targetInstance){ success, data | error }GET /api/cloud/instances: List all instances accessible to the authenticated user (owned and shared).POST /api/cloud/instance/:id/command: Execute a command on a specific instance.GET /api/cloud/instance/:id/info: Get detailed system information from an instance.POST /api/cloud/instance/:id/disconnect: Forcibly disconnect an instance.GET /api/cloud/instance/:id/browse: Browse the filesystem of an instance.POST /api/cloud/sync/cross-instance: Perform a sync operation between two instances.GET /api/cloud/shares/list: List all shares created by or shared with the user.POST /api/cloud/shares/save: Create or update a share.POST /api/cloud/shares/delete: Delete/revoke a share.GET /api/cloud/mirrors/list: List the user's active mirrors.POST /api/cloud/mirrors/save: Create or update an active mirror.POST /api/cloud/mirrors/delete: Delete an active mirror.Instances and health
POST /api/cloud/instances/refresh: Force verification sweep and return latest statesGET /api/cloud/instance/:id/status: Fresh ping/health for a single instanceGET /api/cloud/mcp-connections: List MCP client connections and controllable instances for the userFile browse and transfer
GET /api/cloud/instance/:id/folders: List known project folders on an instanceGET /api/cloud/instance/:id/browse: Server-side directory listing with metadataPOST /api/cloud/instance/:id/transfer/start: Start a chunked transfer sessionGET /api/cloud/instance/:id/transfer/:transferId/status: Query transfer statePOST /api/cloud/instance/:id/transfer/:transferId/cancel: Cancel a transferSynchronization
POST /api/cloud/instance/:id/sync/enhanced: One-shot enhanced file sync for an instancePOST /api/cloud/instance/:id/sync/folder: Folder sync via streaming/chunked pipelinePOST /api/cloud/sync/compare-cross-instance: Server-side comparison between two instancesPOST /api/cloud/sync/execute-from-comparison: Execute transfers from a prior comparison resultPOST /api/cloud/sync/cross-instance: Streaming cross-instance sync orchestrationGET /api/cloud/sync/activity: Placeholder for historical activity (real-time via sockets)Shares
GET /api/cloud/shares/listPOST /api/cloud/shares/savePOST /api/cloud/shares/deletePush Mirrors (Active Mirrors)
GET /api/cloud/mirrors/listPOST /api/cloud/mirrors/savePOST /api/cloud/mirrors/deletePOST /api/cloud/mirrors/syncPOST /api/cloud/mirrors/checkPull Mirrors
GET /api/cloud/pulls/listPOST /api/cloud/pulls/savePOST /api/cloud/pulls/deletePOST /api/cloud/pulls/syncPOST /api/cloud/pulls/checkAuthentication (Anchoring)
POST /api/cloud/request-anchor-token: Exchange dashboard credentials for short-lived siteAuthTokenPOST /api/cloud/request-anchor-token-as: Same, on behalf of a target user (requires permission)siteAuthToken).await Doh.permit(req.user, 'action:context', runtimeContext).read:cloud_instance, command:cloud_instance with the target instance object context.List instances
GET /api/cloud/instances
Authorization: session cookie
{ "success": true, "instances": [], "stats": { "total": 0 } }
Request anchor token (for doh cloud anchor)
POST /api/cloud/request-anchor-token
Content-Type: application/json
{ "username": "admin@example.com", "password": "...", "instance_info": { "fingerprint": "fp-123" } }
{ "success": true, "siteAuthToken": "<jwt>", "expires": 3600 }
Cross-instance sync (server-side orchestration)
POST /api/cloud/sync/cross-instance
Content-Type: application/json
{
"sourceInstanceId": "fp-src",
"destinationInstanceId": "fp-dst",
"sourcePath": "/var/www/app",
"targetPath": "/var/www/app",
"options": { "exclude": ["node_modules/**", ".doh/**"] }
}
{ "success": true, "operationId": "op-789" }
POST /api/cloud/request-anchor-token: Request a site authentication token for an instance.POST /api/cloud/request-anchor-token-as: Request a token on behalf of another user (requires special permissions).Cloud Manager automatically creates and manages the following tables in the application's primary database.
cloud_sharesCREATE TABLE cloud_shares (
id TEXT PRIMARY KEY, -- Unique identifier
sharerId TEXT NOT NULL, -- Instance owner's user ID
shareeId TEXT NOT NULL, -- User ID receiving access
instanceId TEXT, -- Specific instance ID or NULL for all
permissions TEXT, -- JSON array of permissions or NULL for all
description TEXT, -- Human-readable description
createdTimestamp TEXT NOT NULL, -- Creation date
expiresTimestamp TEXT, -- Optional expiration
isEnabled INTEGER DEFAULT 1 -- Enable/disable flag
);
active_mirrorsCREATE TABLE active_mirrors (
id TEXT PRIMARY KEY,
userId TEXT NOT NULL,
sourceInstanceId TEXT NOT NULL,
destinationInstanceId TEXT NOT NULL,
sourcePath TEXT NOT NULL,
targetPath TEXT NOT NULL,
type TEXT NOT NULL,
createdTimestamp TEXT,
lastCheckTimestamp TEXT,
lastSyncTimestamp TEXT,
needsSync INTEGER,
isEnabled INTEGER DEFAULT 1
);