Anso 3a20105a33 fix(mesh): persist rotated handshake when peer bridge owns reverse-dialer slot (#1073)
When the proxy-mode mesh peer already holds an open peer-initiated callback
bridge to central, central's Trigger 2 dial (api_token rotation) arrives at
the peer's `/api/mesh/proxy-tunnel` handler with a fresh `mesh_handshake`
frame. The peer's `attachSwitchboard` refuses the new WS at the reverse-dialer
CAS swap, but it was also closing the connection before its `'message'`
listener had been attached, so the handshake frame went unread and the
peer's cached callback JWT stayed at the pre-rotation fingerprint until a
central restart.

Restructures `attachSwitchboard` to attach the `'message'`, `'close'`, and
`'error'` listeners synchronously after the switchboard is created, before
the async MeshService import and the CAS swap run. On the CAS-fail branch,
holds the WS open for up to FIRST_FRAME_WAIT_MS (30ms, well above localhost
RTT and below operator perception) before sending the 1013 close, so an
in-flight first frame lands in `onMessage` and the bootstrap material is
persisted via `MeshCentralRegistry.upsert` regardless of bridge fate. The
success path is untouched; reverseDialer install timing on accepted dials
is unchanged.

Adds a regression test that pre-installs a stub reverse dialer (simulating
a peer-initiated bridge owning the slot), sends a `mesh_handshake` frame
on the new WS, and asserts the registry receives the rotated material
before the 1013 close fires.
2026-05-16 22:32:35 -04:00
2026-03-25 00:40:06 -04:00

Sencho

Self-hosted Docker Compose management for one machine or a fleet.

Docs · Website · Discussions · Sponsor

Latest release Docker Pulls CI License Discussions


Sencho dashboard

What Sencho is

Sencho is for homelab operators, small DevOps teams, and platform engineers who run services on Docker Compose, want a graphical interface without giving up file-on-disk workflows, and need to manage more than one machine without SSH gymnastics or a VPN.

It runs as a single container on your hardware and gives you a UI for the work you currently do over SSH on compose stacks: deploying, editing files, watching logs, restarting containers, browsing volumes, and recovering from failures. Your compose files stay on the host filesystem and remain the source of truth.

A Sencho instance is autonomous. To manage another machine, you install a second Sencho on it and connect them with a long-lived API token; the primary dashboard then acts as a transparent HTTPS proxy across your fleet. There is no SSH and no exposed Docker socket. For nodes behind NAT or strict firewalls, the Pilot Agent establishes a single outbound WebSocket tunnel to the primary, so the remote host opens no inbound port at all.

Most capabilities are free in the Community tier. A few advanced automation and fleet-control features ship in paid tiers; pricing lives at sencho.io/pricing.


Capabilities

Stacks

  • Full Compose lifecycle: create, deploy, restart, stop, pull
  • Monaco editor with diff preview before save and one-click rollback
  • Git-sourced stacks pulled and synced from any repository
  • File explorer for compose, env, and supporting files
  • Stack labels for grouping and bulk operations
  • App Store with LinuxServer.io templates

Observability

  • Aggregated log search and stream across every container in the fleet
  • Live container stats, health checks, and image-update notifications
  • Threshold alerts for CPU, memory, and network
  • Read-only audit log of every action
  • Network topology view of containers, networks, and nodes

Fleet

  • Multi-node management via authenticated HTTP and WebSocket proxy
  • Fleet view with grid and topology layouts
  • Fleet snapshots of compose and env across the fleet
  • Pilot Agent for nodes behind NAT or strict firewalls
  • Node compatibility checks before deploying

Automation

Security

Operations


Quick start

Sencho runs in a single container.

services:
  sencho:
    image: saelix/sencho:latest
    container_name: sencho
    restart: unless-stopped
    ports:
      - "1852:1852"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
      # 1:1 Compose Path Rule: the host path MUST match the container path
      - /opt/docker:/opt/docker
    environment:
      - COMPOSE_DIR=/opt/docker
      - DATA_DIR=/app/data
docker compose up -d

Open http://your-server:1852 and create your admin account.

Always front Sencho with a TLS-terminating reverse proxy in production. See the self-hosting guide for hardening, environment variables, and reverse-proxy examples.

Run with docker run instead
docker run -d --name sencho \
  -p 1852:1852 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v sencho_data:/app/data \
  -e COMPOSE_DIR=/opt/docker \
  saelix/sencho:latest

For the full walkthrough, see the quickstart guide.


Adding remote nodes

To manage a second machine, install Sencho on it the same way, then add it from the primary dashboard with its URL and a long-lived API token. The primary proxies authenticated HTTPS and WebSocket requests to the remote instance. No SSH, no exposed Docker socket, no agent process on the remote. Nodes behind NAT or strict firewalls can opt into the Pilot Agent for outbound-only connectivity.

See the multi-node guide for the full token-bearer flow.


Screenshots

Stacks Editor
Fleet Logs

Documentation, community, and license


Contributors

S
Description
Self-hosted Docker Compose management platform. Great for homelabs, small DevOps teams, and platform engineers.
Readme AGPL-3.0 177 MiB
Languages
TypeScript 99.2%
JavaScript 0.4%
CSS 0.3%
Dockerfile 0.1%