---
title: Multi-Node Management
description: Connect multiple Sencho instances and manage all your servers from a single dashboard.
---

Sencho's multi-node feature lets you manage Docker Compose stacks on multiple servers, all from the same browser tab. Each server runs its own Sencho instance, and your primary instance acts as a transparent proxy to the others.

<Frame>
  <img src="/images/multi-node/node-manager.png" alt="Node Manager showing a local and a remote node, both Online" />
</Frame>

## How it works

There is no central server. Each Sencho instance manages its own host independently. When you select a remote node, your browser's API calls are proxied through your local Sencho instance to the remote one, authenticated by a long-lived Bearer token. No SSH. No shared Docker sockets.

## The local node

Your primary Sencho installation is always listed as **Local**. It is the default node, marked with a star icon, and cannot be deleted. All operations on the local node run directly against the host's Docker socket.

## Adding a remote node

### Step 1: Generate a token on the remote machine

On the **remote** Sencho instance (the server you want to add), open **Settings → Nodes**. You will see a **Generate Node Token** section at the top of the page. Click **Generate Token**, then copy the token that appears. You will only see it once.

<Note>
  The token is a long-lived credential that grants full control over that Sencho instance. Treat it like a password.
</Note>

### Step 2: Add the node on your primary instance

On your **primary** Sencho instance, open **Settings → Nodes** and click **+ Add Node**. Fill in:

<Frame>
  <img src="/images/multi-node/add-node-form.png" alt="Add Node form with Name, Type, API URL, Token, and Compose Directory fields" />
</Frame>

| Field | Description |
|-------|-------------|
| **Name** | A display name (e.g. `Production VPS`, `media-box`) |
| **Type** | Select **Remote** (or **Local** for an additional local Docker socket) |
| **Sencho API URL** | The full HTTP/HTTPS URL of the remote instance (e.g. `http://192.168.1.50:1852`) |
| **API Token** | The token you generated in Step 1 |
| **Compose Directory** | The root directory where compose stack folders live on the remote node (defaults to `/app/compose`) |

Click **Add Node**. Sencho immediately tests the connection and shows the result.

### Step 3: Verify connectivity

A successful connection shows the remote node as **Online** with a green badge. If it shows **Offline** or **Unknown**, check:
- The remote Sencho instance is running and reachable from your primary host
- The API URL is correct (include the port if non-standard)
- The token was copied correctly without extra whitespace

Click the **wifi icon** (Test Connection) on any node row at any time to re-check status. A successful test shows a **Connection Details** panel below the table with information about the remote instance, including its OS, architecture, container count, and Sencho version.

## Switching between nodes

The **node switcher** sits at the top of the sidebar and acts as a persistent identity anchor. It shows the active node's status dot, type (`LOCAL`, `REMOTE`, or `AGENT`), and name, so you always know which node you are viewing.

When two or more nodes are registered, clicking the switcher opens a popover listing every connected node. Each row includes a status dot, name, and a metadata line with the node type, version, and (for pilot agents) the time since the agent last checked in. The active node is marked with a cyan accent rail, and a filled star calls out the default node.

Click any row to switch. All views (dashboard stats, stack list, editor, resources, logs) immediately reflect the selected node. A **Manage nodes** link at the bottom of the popover opens the Nodes settings page to add, edit, or remove nodes.

<Frame>
  <img src="/images/multi-node/node-switcher-dropdown.png" alt="Node switcher popover listing connected nodes with type, version, and active-row accent" />
</Frame>

## Per-node scheduling and update indicators

The Nodes table surfaces scheduling and update status at a glance for each node:

<Frame>
  <img src="/images/per-node-scheduling/nodes-table-overview.png" alt="Nodes table showing Schedules and Updates columns for each node" />
</Frame>

| Column | What it shows |
|--------|---------------|
| **Schedules** | Number of active scheduled tasks targeting this node, plus a relative countdown to the next run (e.g. "next 2h") |
| **Updates** | Whether auto-update policies are enabled ("Auto" badge), and how many stacks have pending image updates (fuchsia notification dot with expanding halo and a count) |

Click the **calendar icon** on any node row to jump directly to the Schedules view filtered to that node. From there you can create, edit, or manage scheduled tasks scoped to the selected node. The filter bar shows which node you are viewing, with a **Clear filter** button to return to the full list.

When a node is deleted, all scheduled tasks and update status data associated with it are automatically cleaned up.

## What Settings apply per node

When you select a remote node in the node picker, the Settings hub filters to the panels that control that specific instance. Values saved here never cross over to other nodes.

| Panel | Scope | Notes |
|-------|:-----:|-------|
| Appearance | Per browser | Density and theme preferences are stored in your browser, not on the node. |
| System Limits | Per node | Host CPU, RAM, disk, and crash-loop thresholds for the selected node. |
| Notifications | Per node | Discord, Slack, and Webhook channels fire from the node that detects the event. |
| Labels | Per node | Stack and container label palettes. |
| Security | Per node | Trivy install, update, and scanner status. Scan policies and CVE suppressions are managed on the control node and apply fleet-wide. |
| Developer | Per node | Retention windows for metrics and logs, plus Developer Mode. |
| App Store | Per node | Template registry URL for the selected node's catalog. |

Panels that manage control-plane concerns (Account, License, Users, SSO, API Tokens, Registries, Nodes, Routing, Webhooks) are hidden when a remote node is active.

## License enforcement across nodes

When you have a paid license (Skipper or Admiral) on your primary instance, all remote nodes automatically inherit that license tier for proxied requests. You do not need to activate a license on each remote node separately.

### How it works

Your primary Sencho instance asserts its license tier to remote nodes on every proxied request. Remote nodes trust this assertion because it arrives alongside the valid node token you configured when adding the node. No additional configuration is required.

This means:

- **Paid primary → remote nodes**: Skipper and Admiral features work on all remote nodes, governed by the primary instance's license.
- **Community primary → remote nodes**: Paid features are blocked on remote nodes, even if a remote node has its own paid license. The primary's tier is authoritative for proxied requests.
- **Direct access to a node**: If you access a remote Sencho instance directly (not through the primary), it uses its own local license tier as usual.

### Why this matters

Without this trust chain, remote nodes would default to the Community tier and block paid features, even though the primary instance has a valid license. Distributed license enforcement eliminates this gap so your fleet behaves consistently regardless of which node you are operating on.

<Note>
  Remote nodes do not need their own license keys. A single license on the primary instance covers all nodes managed through it.
</Note>

## Editing and deleting nodes

Click the **pencil icon** on any node row to edit its name, URL, token, or compose directory. Click the **trash icon** to remove a remote node. The local (default) node cannot be deleted.

## Security

### Token security

Node tokens grant full control over the remote Sencho instance. Treat them like passwords:

- **Rotate immediately** if a token is compromised: go to the remote instance's **Settings → Nodes** and click **Generate Token**. The old token is invalidated instantly.
- Tokens are **encrypted at rest** in Sencho's database.
- Tokens cannot be used to open interactive terminals (Host Console or container exec). Interactive shell access always requires a real browser session on that specific instance.

### Transport encryption

Sencho delegates transport encryption to your infrastructure rather than implementing TLS at the application layer. This is the same approach used by other self-hosted tools; it avoids certificate management burden while letting you use the encryption layer that best fits your environment.

<Warning>
  **Never send node tokens over plain HTTP across the public internet.** A token intercepted in transit grants full control of the remote instance. Always use one of the approaches below when nodes communicate over untrusted networks.
</Warning>

Sencho shows an inline warning when you enter an HTTP URL in the Add Node form as a reminder:

<Frame>
  <img src="/images/multi-node/http-warning.png" alt="Add Node form showing an inline warning when an HTTP URL is entered" />
</Frame>

There are three recommended approaches depending on your deployment:

#### Private network (LAN or VPC)

If all your Sencho instances are on the same local network, VPC, or subnet, HTTP is perfectly fine. The token never leaves the private network, so there is no interception risk.

```
http://192.168.1.50:1852   ← safe on a private LAN
http://10.0.1.20:1852      ← safe inside a VPC
```

#### VPN tunnel (WireGuard, Tailscale)

<Tip>
  This is the simplest approach for connecting nodes across the internet. A VPN encrypts all traffic between your servers at the network layer, with no certificate management required.
</Tip>

With a mesh VPN like [Tailscale](https://tailscale.com) or [WireGuard](https://www.wireguard.com/), each server gets a private IP on the VPN. Use those IPs as your Sencho API URLs:

```
http://100.64.0.2:1852     ← Tailscale IP, encrypted by the VPN tunnel
```

All traffic between nodes is encrypted by the VPN. Sencho does not need to do anything additional.

#### Reverse proxy (Caddy, Nginx, Traefik)

If you prefer TLS termination at each node, place a reverse proxy in front of each Sencho instance. [Caddy](https://caddyserver.com/) is the simplest option; it auto-provisions HTTPS certificates from Let's Encrypt with zero configuration:

<CodeGroup>
```text Caddyfile
sencho.example.com {
    reverse_proxy localhost:1852
}
```

```nginx nginx.conf
server {
    listen 443 ssl;
    server_name sencho.example.com;

    ssl_certificate     /etc/letsencrypt/live/sencho.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sencho.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:1852;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
```
</CodeGroup>

Then use the HTTPS URL when adding the remote node:

```
https://sencho.example.com   ← TLS terminated by Caddy/Nginx
```

### Why Sencho doesn't implement application-layer TLS

Some tools auto-generate self-signed TLS certificates between their server and agents. In practice, this provides minimal security benefit because the certificates are self-signed with no verification, meaning they do not protect against man-in-the-middle attacks.

Sencho takes a deliberate approach: infrastructure-level encryption (VPN, reverse proxy, or private networking) is more robust, easier to manage, and does not impose certificate rotation burden on the user. This is the same model used by other self-hosted orchestrators.
