COMPOSE CONTROL / RUST / LOCAL FIRST

DS / 001 YOUR MACHINE. YOUR STACKS.

DOCK
SPACE.

Your containers.
Your command center.

Turn a folder of Compose stacks into a living control surface. Inspect services, follow logs, validate edits, and bring your stack online—without leaving your machine.

◆ 127.0.0.1 ONLY◆ LIVE TAIL (SSE)◆ COMPOSE DOCTOR◆ MIT
DOCKSPACE / CONTROL SURFACEINTERACTIVE DEMO
LOCAL HARBOR~/ContainersSimulated stacks · click to inspect
2 RUNNING3 STACKS127.0.0.1 / 7070
SELECT A STACK TO ENTER THE PLAYGROUND
COMPOSE → DISCOVER → CONTROLRUST / AXUM / HTMXOPEN SOURCE / MIT

01 / INTERACTIVE PLAYGROUND

Bring it up.
Watch it work.

Explore a simulated harbor. Start and stop stacks, inspect service logs, or edit a sample Compose file. Everything runs in this page.

SELECTED STACK

signal-web

RUNNING
Browser simulation · no Docker connection
LOG SNAPSHOT / SAMPLE DATA

02 / CAPABILITIES

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.

03 / LOCAL BOUNDARY

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.

04 / BOOT SEQUENCE

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/cybercoretech/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=

05 / CYBERGRID

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
SEARCH DOCKSPACE

Tab to navigate · Enter to open · Esc to close