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.
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.Cloud 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.
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/list
POST /api/cloud/shares/save
POST /api/cloud/shares/delete
Push Mirrors (Active Mirrors)
GET /api/cloud/mirrors/list
POST /api/cloud/mirrors/save
POST /api/cloud/mirrors/delete
POST /api/cloud/mirrors/sync
POST /api/cloud/mirrors/check
Pull Mirrors
GET /api/cloud/pulls/list
POST /api/cloud/pulls/save
POST /api/cloud/pulls/delete
POST /api/cloud/pulls/sync
POST /api/cloud/pulls/check
Authentication (Anchoring)
POST /api/cloud/request-anchor-token
: Exchange dashboard credentials for short-lived siteAuthToken
POST /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_shares
CREATE 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_mirrors
CREATE 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
);