Skip to content

Docker on hosts

What this is

When Docker / containers is enabled for a server, PiHerder can list compose projects, stream logs, edit multi-file compose, build, check/update images, and redeploy — all over SSH as the server’s configured user.

Why it exists

Homelab hosts often run many stacks. SSHing into each machine for docker compose ps does not scale, and ad-hoc edits leave no version history. The Docker UI is the day-to-day surface for free-form stacks; templates cover desired-state managed stacks.

Server detail Docker card

Docker dest card on server detail.

End-to-end: open a stack and redeploy

  1. Enable Docker / containers; set Docker base dir correctly.
  2. Confirm dependency check for docker is green (SSH access).
  3. Open Docker — inventory snapshot appears immediately (Inventory).
  4. Expand a project; open logs if needed.
  5. Check updates vs Deploy when you want pull-only vs pull+up (Updates).
  6. For compose edits, use Compose edit (quick modal or full editor with history).
  7. For a sidecar / log sitting next to the stack, or to copy a file out of a container, use Host Files (jailed SFTP; flag PIHERDER_HOST_FILES).
  8. Hardware-bound stacks: ⋯ → Lock to this host. Optional Move to another host…Move a service.

Prerequisites

  1. Feature flag Docker / containers on.
  2. Remote docker usable by the SSH user (group/socket).
  3. Docker base dir set correctly (absolute path if using least-priv).
  4. Dependency check green for docker — SSH troubleshooting.

What you can do

Action Notes
Browse projects / containers From inventory snapshot (Inventory); search + status chips + pager are server-side (see below); containers as dense rows
Runtime stack / Path map Project Stack / Path map pills → Network stack panel + map expand (Network maps)
Logs Per container / service (modal or full page). Multi-service projects: pick a service or All services (project-level docker compose logs). Live SSE requires a signed-in session
Stop / Start / Restart all Project ⋯ menu → confirm → Job with live log (docker_stack_stop / _start / _restart) — operator+
Lock to this host Project ⋯ — Move a service. Hardware / operator / infra. HAOS always locked. Operator+.
Move to another host… Flag PIHERDER_SERVICE_MIGRATE (default off). Preflight then Job: stop → copy → dest up → DNS/NPM. NPM proxy-host binding is enough (no fabric row required). Optional leftover: leave stopped, compose down, or remove source + named volumes. Move a service.
Container start / stop / restart Row ⋯ on a single service (immediate; not a full-stack job) — operator+; actions allowlisted (start/stop/restart)
Quick edit / Full editor ⋯ menu — quick modal is compose (± Dockerfile) only; .env and sidecars are full editor — Compose edit
Multi-file compose edit primary compose + override + .env + Dockerfile + compose sets
Compose sets Extra docker-compose.<name>.yml in the same project folder — see below
Version history Snapshots; rollback
Build / redeploy POST-only SSE stream of docker compose build for a named project (operator+). Paths are quoted; there is no GET /path fallback. Redeploy as Jobs.
Check updates vs Deploy Pull-only vs pull+up as JobsUpdates
Cleanup unused List dangling images / exited containers (escaped HTML); optional prune
New project wizard Create a stack on the host
Template-managed stacks Badge + gated full editor — Templates

Browser Back on Docker

Leaving Docker for another tool (template deployment, full editor) and pressing Back must not leave a stuck “Collecting information from host via SSH” overlay. The page clears the wait chrome when the stack is already loaded (bfcache-safe).

Compose sets (same folder, one project card)

One directory under the Docker base dir is still one project in the Docker list. You may keep more than one compose file there:

File Role
docker-compose.yml / compose.yml Primary (main set)
docker-compose.override.yml Compose auto-merge — multi-file editor, not a separate set
docker-compose.<name>.yml Compose set (e.g. docker-compose.e2e.yml → set e2e)

UI: under the project header, pills All · main · e2e · … filter which services are listed inside a visible project. This is not a second stack card and stays client-side.

Filter and page stacks

Status chips (All / Running / Stopped / Not created / Updates) and the name box are GET query params (q, status, page, per_page). A project stays if its name or any service/image matches the search (same aliases as Servers — ha → Home Assistant). Page size is the shared 10 / 20 / 50 / 100 cookie. Hero totals stay the unfiltered inventory.

HTMX refresh keeps the query so filters do not reset. ?project=foo after Deploy still jumps to that stack. Compose-set pills are unchanged.

Deploy: project ⋯ → Deploy runs the whole project (default Compose resolution). Deploy \<set> set runs docker compose -f <that-file> up -d still under the same project name / directory.

vs fabric view groups: compose sets are files on disk / deploy slices. Network view groups (Main / custom) are presentation only on the stack panel and map — Network maps.

Project lifecycle (stop, start, restart all)

From a compose project menu:

  1. Choose Stop all services…, Start all services…, or Restart all services…
  2. Confirm — host + project name; Stop uses danger styling.
  3. A Job runs docker compose stop|start|restart over SSH with a live log (same JobHold pattern as Deploy).
  4. Success refreshes inventory; Jobs / Audit record docker_stack_stop / _start / _restart.

Only one stack mutation runs at a time per host (shared lane with Deploy and template deploy/redeploy). Operator+ only. Single-container start/stop/restart stay on the service row ⋯ menu.

Docker project lifecycle

Project ⋯ **Lock to this host…** / **Move to another host…** plus Stop / Start / Restart all.

Template vs free-form stacks

Kind Edit path Why
Template-managed Desired state / redeploy / Accept host as desired on deployment page; host file editor gated Template desired state is source of truth
Free-form Full compose multi-file editor (compose, .env, sidecars, sets) Bring-your-own stacks