Multi-Server
Manage and deploy across multiple servers from a single sh0 dashboard using secure SSH tunnels.
Overview
sh0 supports a Bring Your Own Server (BYOS) model where you can connect multiple remote servers (nodes) to your primary sh0 instance. The primary server acts as the control plane, managing deployments and routing across all connected nodes.
This architecture lets you:
- Distribute workloads across multiple servers for better performance
- Place apps closer to users in different geographic regions
- Isolate workloads (e.g., databases on dedicated hardware)
- Scale beyond the resources of a single server
Adding Remote Nodes
To add a remote server as a node:
- Navigate to Settings → Nodes in the dashboard.
- Click Add Node.
- Enter the node details: hostname or IP, SSH port, and SSH user.
- Provide the SSH private key or select an existing key from your key manager.
- Click Connect. sh0 will verify the connection and register the node.
Via the API:
curl -X POST https://your-server:9000/api/nodes \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "eu-node-1",
"hostname": "10.0.1.50",
"ssh_port": 22,
"ssh_user": "deploy",
"ssh_key_id": "key_abc123"
}'docker group or configure passwordless sudo for Docker.SSH Tunnel Setup
sh0 communicates with remote nodes via SSH tunnels. The tunnel forwards Docker API requests from the primary server to the remote node's Docker socket, keeping all traffic encrypted.
The tunnel is established automatically when you add a node. sh0 uses SSH TOFU (Trust On First Use) for host key verification -- you will be shown the server's fingerprint on first connection and asked to confirm it.
Primary Server (sh0)
|
|-- SSH Tunnel (encrypted) --> Remote Node 1
| |-- Docker Socket
| |-- Container A
| |-- Container B
|
|-- SSH Tunnel (encrypted) --> Remote Node 2
|-- Docker Socket
|-- Container CNode Health Monitoring
sh0 continuously monitors the health of all connected nodes. The monitoring includes:
- SSH connectivity: Checks that the tunnel is active and responsive.
- Docker status: Verifies the Docker daemon is running on the remote node.
- Resource usage: Tracks CPU, memory, and disk usage on each node.
- Container health: Monitors all containers running on the node.
When a node goes unhealthy, sh0 sends alerts through your configured notification channels (email, Slack, Discord, or webhooks). You can configure alert thresholds per node in the node settings.
Deploying to Specific Nodes
When creating or configuring an app, you can specify which node it should run on. This is configured in the app's deployment settings.
Options:
- Primary (default): Deploy on the main sh0 server.
- Specific node: Pin the app to a named remote node.
- Any node: Let sh0 choose the node with the most available resources.
curl -X PUT https://your-server:9000/api/apps/my-app \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"node_id": "node_eu1"}'Node-Aware Routing
The primary server's Caddy reverse proxy handles routing to containers on all nodes. When a request comes in for a domain, Caddy routes it to the correct node and container, regardless of where the container is running.
For apps with replicas spread across nodes, Caddy load-balances across all healthy replicas on all nodes. Latency between the primary proxy and remote nodes should be considered when planning your architecture.
Managing Multiple Servers
The Nodes panel in the dashboard provides a centralized view of all servers in your fleet:
From this panel you can:
- View node metrics: CPU, memory, disk, and network usage for each node.
- List containers: See all containers running on a specific node.
- Drain a node: Gracefully move all containers off a node before maintenance.
- Remove a node: Disconnect a remote node (containers must be migrated or stopped first).
- Terminal access: Open an SSH terminal to any node directly from the dashboard.