a5Pier

Notes · 2026-06-11

Agentless Docker monitoring over SSH

Most Docker monitoring setups ask you to install something on every server: an agent, an exporter, a dashboard container, sometimes a public port. For a handful of VPSes that's more moving parts than the thing being monitored. There is a simpler pattern: the SSH access you already have is the monitoring channel.

The whole trick

Everything a fleet overview needs is readable with a few commands you would type by hand anyway:

ssh myserver 'docker ps --format "{{json .}}"'
ssh myserver 'docker inspect <container>'
ssh myserver 'docker logs --tail 100 -f <container>'
ssh myserver 'cat /proc/loadavg /proc/meminfo; df -P'

Group containers by their com.docker.compose.project label and you get stacks instead of a flat container list. Poll on an interval, diff the results, and you have health transitions, restart detection, and disk-filling-up alerts — with zero server-side footprint. No agent to update, no exporter to secure, no extra port in the firewall.

Locking it down: the forced-command key

A monitoring tool holding general SSH access is a fat target. OpenSSH has a built-in answer: a dedicated key restricted in authorized_keys to a single wrapper command, with everything else disabled:

restrict,command="/usr/local/bin/probe-only.sh" ssh-ed25519 AAAA... pier-readonly

The wrapper inspects SSH_ORIGINAL_COMMAND and allows only an exact allowlist — docker ps, docker inspect, log tails, metric reads. Even if the monitoring machine were fully compromised, that key cannot restart a container, write a file, or open a shell. restrict additionally kills port forwarding, agent forwarding and PTY allocation in one word.

Image-update detection without pulling

Out-of-date images are the other thing worth watching. You can detect them without pulling anything: compare the running container's image digest against the registry's current digest for the same tag (a HEAD request to the registry API). If they differ, the tag moved — the container is behind. Updating is then a normal docker compose pull && docker compose up -d from the compose project the labels point at — an action you can keep behind explicit confirmation, separate from the read-only key.

Where this pattern shines (and where it doesn't)

Interval-polling over SSH is a glance layer, not an observability stack. No long-term metrics retention, no alert routing trees, no per-second resolution. For dozens of machines and the question "is everything up, is anything behind, is a disk filling", it is hard to beat: nothing to install, nothing new to trust, and the blast radius of the credentials can be cut to read-only at the OpenSSH level. Past a few hundred hosts, reach for Prometheus.

This is how Pier works

Pier is a macOS menu-bar app built on exactly this pattern: your existing ~/.ssh config and agent, read-only probes by default, a generator for the forced-command key, digest-based update hints, live logs, and a green/amber/red fleet dot in the menu bar. $4.99 one-time, macOS 14+, notarized.

brew install --cask andershfranzen/afive/pier