How to Manage Multiple Docker Hosts From One Place
To manage multiple Docker hosts from one place, put every server behind a named Docker context (docker context create) or a tidy ~/.ssh/config, then run the same docker CLI against any host by switching context instead of SSH-ing in manually. That gives you one command surface for every machine. Add central monitoring and alerts on top so you find out a host is down before your users do.
If you run more than two or three Docker servers, you already know the pain. One terminal tab per box, a sticky note of IP addresses, and no idea which container died until someone complains. Here is how to consolidate that.
Start with SSH config
Everything begins with clean SSH access. Before you touch Docker contexts, give each host a short alias in ~/.ssh/config:
Host prod-web
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
Host prod-db
HostName 203.0.113.11
User deploy
IdentityFile ~/.ssh/id_ed25519
Host staging
HostName 198.51.100.5
User deploy
IdentityFile ~/.ssh/id_ed25519_staging
Now ssh prod-web just works. No IP, no -i flag, no -l user. This file is the foundation everything else leans on, so spend five minutes getting it right. Test each entry:
ssh prod-web docker ps
If that returns a container list, you are ready for the real trick.
Use Docker contexts to switch hosts
Docker has a built-in feature for exactly this problem, and most people never touch it. A context is a saved connection to a Docker daemon. You create one per host, then point the CLI at whichever one you want.
docker context create prod-web --docker "host=ssh://prod-web"
docker context create prod-db --docker "host=ssh://prod-db"
docker context create staging --docker "host=ssh://staging"
Notice the ssh://prod-web part reuses the SSH alias from above. That is why the config file comes first. List what you have:
docker context ls
Switch to a host and run commands as if you were local:
docker context use prod-web
docker ps
docker logs -f api
Or skip the switch entirely and target a host inline with --context:
docker --context prod-db ps
docker --context staging image ls
This is the whole game for CLI work. One binary, one set of commands, any host. No eval $(docker-machine env) nonsense, no editing DOCKER_HOST by hand. If you want a deeper look at the day-to-day commands themselves, our guide on running docker ps from anywhere covers the reads you will use most.
Run a command across every host at once
Contexts are per-command, so a quick shell loop fans a check out to all of them:
for h in prod-web prod-db staging; do
echo "== $h =="
docker --context "$h" ps --format '{{.Names}}\t{{.Status}}'
done
That single loop is often all the "dashboard" a small fleet needs. Drop it in a script named dps on your PATH and you have a fleet-wide docker ps in one keystroke.
What contexts do not solve
Contexts make you the operator sitting at a keyboard. They do nothing when you are asleep, on the train, or away from your laptop. And they answer "what is running right now" but not "was this container restarting in a loop for the last hour."
Two gaps show up fast once you have real traffic:
- You are not always at a terminal. A container OOM-kills at 2am and the loop above only tells you at 9am when you run it.
- No history.
docker statsis a live snapshot. It cannot tell you the host hit 95% memory an hour ago and recovered.
This is where you either build something or use a tool that already did. Prometheus plus cAdvisor plus Grafana is the classic self-hosted answer, and it is a genuinely good stack if you want to run it. It is also three more services to deploy, secure, and keep alive on top of the hosts you are already managing.
For a lot of teams the honest trade is: you do not want to babysit a monitoring stack just to watch a handful of Docker boxes. That is the exact case Docker HQ was built for. It keeps the SSH-context model (your servers, your keys, no agent to install on the host) and adds the two things the CLI loop lacks: a live view of every host in one screen, and a push notification to your phone when a host or container goes down. You can read logs, open a shell, and restart a stuck container from the same place. The multi-host and team-access side of that is on the pricing page.
Managing hosts from your phone
The SSH-context approach has one more limit worth naming. It assumes you are on a machine with your keys and your docker binary. When the pager goes off and you are holding a phone, that assumption breaks.
You have a few options. You can SSH from a mobile terminal app and type docker --context prod-web restart api on a tiny keyboard, which works but is miserable at 3am. You can set up a jump host and a web terminal. Or you can use an app that speaks the same SSH-and-context language but gives you buttons instead of a command line. We wrote up the full workflow in how to manage Docker containers from your phone, and the narrower case of restarting a container remotely if that is the specific fire you keep fighting.
Whatever you pick, the principle holds: the phone should hit the same daemons your laptop does, over SSH, with no daemon exposed to the public internet.
A note on daemon exposure
Some guides tell you to bind the Docker daemon to a TCP port so remote clients can reach it:
# Do not do this on a public network
dockerd -H tcp://0.0.0.0:2375
Do not. An unauthenticated Docker socket on the network is root on the box for anyone who finds it, and scanners find it in minutes. If you must expose TCP, use 2376 with TLS client certificates and mutual auth. But you rarely need to. SSH already gives you an authenticated, encrypted channel, and ssh:// contexts ride on it for free. Keep the daemon bound to its local socket and let SSH do the transport.
How to manage multiple Docker hosts without losing sleep
The minimum setup that scales cleanly:
- One
~/.ssh/configentry per host with a short alias and the right key. - One
docker context create ... --docker host=ssh://<alias>per host. - A small
forloop or script for fleet-wide reads. - Real monitoring with alerting for anything you cannot afford to notice late.
Steps 1 through 3 cost you an afternoon and pay off every day after. Step 4 is where you decide between running your own stack and offloading it. Neither is wrong. Just do not pretend a manual docker ps loop is monitoring, because it is not, and the gap between the two is exactly the incident you will be explaining on Monday.
Frequently asked questions
Do Docker contexts work over SSH without extra setup?
Yes, as long as you can already ssh <alias> into the host and the remote user can run docker. The ssh:// context reuses your existing SSH config, keys, and agent. There is no daemon to expose and no certificate to generate. If passwordless SSH works, the context works.
How many Docker hosts can I manage this way?
There is no hard limit on the number of contexts. The CLI stays fine into the dozens. What breaks down first is human attention, not the tooling. Somewhere past a handful of hosts a manual loop stops being enough and you want a single screen plus alerts rather than eyeballing text output.
Is exposing the Docker daemon on a TCP port ever safe?
Only with TLS mutual authentication on port 2376, and even then you are adding attack surface for little gain. Plain tcp://0.0.0.0:2375 with no TLS is remote root access to the host, so never use it on any network you do not fully control. SSH contexts avoid the whole question.
Can I switch between hosts without changing my active context?
Yes. Use the --context flag on any command, like docker --context staging ps. It targets that host for that one command and leaves your default context untouched. This is the safest way to poke at production while your shell still points at staging.