docker-compose dashboard · Rust · htmx

DOCK
SPACE

Every compose stack on your machine — live, editable, one click from up or down.

Point it at a folder of stacks and it finds every compose.yaml: live status, services and ports, logs with a real live tail, an editor that validates before it saves, images/volumes/networks with scoped prune, and an activity feed. A single-machine take on the best parts of sencho — themed in the shared CYBERGRID palette.

◆ 127.0.0.1 ONLY◆ LIVE TAIL (SSE)◆ COMPOSE DOCTOR◆ MIT

01 / Features

The whole harbor,
one screen.

Everything refreshes on its own every few seconds, and slow actions never freeze the page — a cold image pull returns "Working…" instantly and the next poll shows the real outcome.

01 · LIVE STATUS

RUNNING · PARTIAL · STOPPED · UNKNOWN

From docker compose ps, with a per-service breakdown. Unknown is its own state — the daemon is unreachable, not "definitely stopped".

02 · PORTS

SERVICES & PORTS

Parsed straight from each compose file — both short "8081:8081" and long {target, published} syntax.

03 · ACTIONS

UP · DOWN · RESTART

Responsive even for slow pulls; a failed action shows a banner on the card instead of silently doing nothing.

04 · LOGS

SNAPSHOT + LIVE TAIL

Last 200 lines on demand, or a real Server-Sent-Events stream of docker compose logs -f.

05 · EDITOR

COMPOSE DOCTOR

Edit in place; Validate runs docker compose config on your edit before saving, so a typo is an inline error, not a broken file.

06 · HOUSEKEEPING

RESOURCES & ACTIVITY

Every image, volume and network with a scoped prune, plus a feed of every start/stop/save/prune — failures show the real command output.

02 / Security

Root-grade power,
loopback-tight.

Docker access is effectively root, and Dockspace has no login. So it binds to 127.0.0.1 only — and refuses the two tricks a web page can use to reach a localhost service.

● ● ●   guard / live testENFORCED
200  GET  dashboard200  POST from its own page (same-origin)403  POST from evil.example (cross-site form)403  POST with a foreign Origin403  Host: evil.example (DNS rebinding)200  curl, no browser headers
  • Cross-site requests refused: state-changing requests whose Sec-Fetch-Site or Origin isn't its own are blocked — no forged "save this compose file, now start it".
  • DNS rebinding refused: every request must carry a loopback Host for its port.
  • Least privilege: run it as a hardened service that gets the docker group itself, from a root-owned binary — so your login doesn't need Docker access at all.
  • Never expose it: no auth by design; reach it locally or over an SSH tunnel.

03 / Setup

Moor
the stacks.

Keep one folder per stack (compose.yaml + .env + config/), point Dockspace at the root, and open the dashboard.

BUILD + RUN
git clone https://github.com/cybercore-tech/dockspace
cd dockspace && cargo build --release

DOCKSPACE_ROOT=~/Containers DOCKSPACE_PORT=7070 \
  ./target/release/dockspace
# → http://127.0.0.1:7070
AS A HARDENED SERVICE (EXCERPT)
[Service]
User=youruser
SupplementaryGroups=docker
ExecStart=/usr/local/bin/dockspace
Environment=DOCKSPACE_ROOT=/home/youruser/Containers
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/youruser/Containers /home/youruser/.cache/dockspace
CapabilityBoundingSet=

04 / Theme matrix

Paint
the hulls.

Every Cybercore palette from the shared schema, grouped by family — plus Dockspace's own signature mashups. Your pick follows you across Cybercore sites.

NOW RUNNING · …
…
dev@cybercoretech.net