Multi-Server
Attach other servers you own to one sh0 installation and run some of your apps on them. The primary server keeps the dashboard, the builds and the routing.
Requirements
- A Business license, and the admin or owner role: every node endpoint is refused otherwise.
- On the remote server: Docker installed and running. sh0 does not install anything there.
- SSH access from the primary server to the remote one, with a user that can use the Docker socket (
/var/run/docker.sock):root, or a member of thedockergroup. - Either an SSH key registered beforehand in the dashboard (SSH key management), or the user's password.
How it works
- The primary server keeps the database, the dashboard and Caddy. A node only runs containers; sh0 drives its Docker through an SSH tunnel.
- Images are always built on the primary server, then transferred to the node (the deployment shows the
transferringstep). - Domains still point at the primary server. Its Caddy forwards each request to the container on the node through a relay carried by the same SSH tunnel.
- Internal names (
my-api.internal) resolve only inside one server: an app on a node cannot reach a service of the same project on another server by that name. The build log warns when a project spans several nodes.
Adding a node
- In the dashboard, open Nodes, then Add Node.
- Give a Name (lowercase letters, digits and hyphens, at most 64 characters) and the Hostname (IP address or DNS name;
localhostand loopback addresses are refused). - Set the SSH Port (22 by default), the Username (
rootby default) and the Authentication: SSH Key or Password. - Save, then use Test Connection: sh0 checks the SSH connection and Docker on the node.
From the CLI (nodes create takes --port for a non-standard SSH port, and --password instead of --ssh-key):
sh0 nodes create --name worker-1 --host 203.0.113.20 --ssh-user root --ssh-key <ssh-key-id>
sh0 nodes list
sh0 nodes info <node-id>
sh0 nodes test <node-id>Through the API:
curl -X POST https://panel.example.com/api/v1/nodes \
-H "Authorization: Bearer $SH0_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"worker-1","hostname":"203.0.113.20","port":22,"username":"root","auth_method":"ssh_key","ssh_key_id":"<ssh-key-id>"}'port,usernameandauth_methodare optional (22,root,ssh_key). With"auth_method":"password", sendpasswordinstead ofssh_key_id; it is stored encrypted.- Since 1.10.3: sh0 tries to connect as soon as the node is created: the status becomes
onlineon success,errorwith the message on failure. The attempt is bounded to 15 seconds: on an address that does not answer, the node is recorded inerrorand the CLI exits with code 1, namingnodes testto retry andnodes deleteto remove it. - The node's SSH host key is recorded at the first connection and checked afterwards. If the server is reinstalled, its key changes and the connection is refused: Reset the fingerprint (
POST /api/v1/nodes/<id>/reset-fingerprint) so that the next connection records the new key.
Deploying to a node
When you create an app from a Git repository, a Dockerfile, a Docker image, a framework or an archive, the Target Node field chooses the server; through the API, send node_id (the node's ID or name). An empty value means the primary server; a value that matches no node is refused rather than silently deployed on the primary.
Moving an app
An app is moved by changing its node_id, with PATCH /api/v1/apps/<id>. The app must be stopped first; otherwise the change is refused, because its container would be left running on the old server. An empty string brings the app back to the primary server.
curl -X PATCH https://panel.example.com/api/v1/apps/<app-id> \
-H "Authorization: Bearer $SH0_TOKEN" -H "Content-Type: application/json" \
-d '{"node_id":"worker-1"}'Then redeploy the app: the image is built on the primary and transferred to the new node. The container on the old node is not migrated, and volume data does not follow: copy it yourself.
Node status
Nodes lists each server with its status (Online, Pending, Error, Offline), its Docker version, CPU and memory, and the last contact. A monitor re-checks the nodes every 30 seconds and re-opens the relays of running apps after a reconnection.
Removing a node
A node can be removed only when no app is assigned to it any more: “Cannot delete node: N app(s) still assigned. Migrate them first.” Move or delete those apps first, then delete the node from Nodes, with sh0 nodes delete <node-id> or DELETE /api/v1/nodes/<id>.
Limitations
- The primary is a single point of failure. If it stops, the dashboard, the builds and the routing to every node stop with it.
- All traffic goes through the primary. Requests reach a node over the SSH relay; plan the primary's bandwidth accordingly.
- No automatic placement. sh0 does not choose a node for you and does not spread replicas across nodes: each app runs on one server.
- No drain or automatic migration. Emptying a node means stopping, moving and redeploying its apps one by one.
- No cross-server network. See internal names above.
- Use the node ID in the CLI.
sh0 nodes test,infoanddeleteannounce “Node ID or name”, but in v1.10.2 only the ID is found.