CertGrid CertGrid
Hands-on Lab·Docker

Docker Contexts and Remote Hosts

Drive a Docker host across the network from your own machine, using SSH rather than an exposed daemon port. Includes the host-key failure you will hit first, and why opening port 2375 is the mistake to avoid.

Operations and Troubleshooting Guide 35 of 46 Intermediate

Tested on the versions above. Captured between two real hosts - commands were issued on ahm-docker03 and executed by the daemon on ahm-docker02.

Two hosts, which is the whole point of this guide: commands are typed on DOCKER01 and executed by the daemon on DOCKER02, so the output comes from a machine you are not logged in to. The transcripts run `hostname` and print the lab machine's own name, which is how you can tell which end answered.
Server NameIP AddressOSRolesCPURAMHDD
DOCKER01192.168.0.21Ubuntu 26.04 LTSDocker Host (client)2 Core4 GB50 GB
DOCKER02192.168.0.22Ubuntu 26.04 LTSRemote Docker Host (daemon)2 Core4 GB50 GB

Before you start

  1. What a context is

    A context is a named endpoint the CLI talks to. You always have one - default, pointing at the local Unix socket. Adding contexts lets one CLI drive several hosts, and switching between them changes where every subsequent command runs.

    bash
    docker context lsNAME        DESCRIPTION                               DOCKER ENDPOINTdefault *   Current DOCKER_HOST based configuration   unix:///var/run/docker.sockdocker context inspect default --format "{{.Endpoints.docker.Host}}"unix:///var/run/docker.sock

    Expected resultOne context, marked active with an asterisk, pointing at the local socket.

    Success conditionYou can see where your commands currently go. The asterisk is the active context.

  2. Create a context for a remote host over SSH

    SSH is the right transport: it authenticates, encrypts, and reuses access you already manage. There is no daemon port to expose and no certificate to issue. The remote host needs nothing configured beyond an SSH login that can reach its Docker socket.

    bash
    docker context create cg-remote --docker host=ssh://sysadmin@192.168.0.22 --description "docker02 over SSH"cg-remoteSuccessfully created context "cg-remote"

    Expected resultThe context created immediately - note it does not connect yet.

    Success conditionCreation always succeeds because nothing is validated at this point. The first command that uses it is where problems surface.

  3. The failure you will hit first

    Creating the context does not test it. The first real command does, and on a host that has never connected to the target this is what you get. It is SSH's host-key check, not a Docker problem at all - which is why the message is easy to misread.

    bash
    docker --context cg-remote info --format "{{.Name}}"error during connect: ... command [ssh -l sysadmin -o ConnectTimeout=30 -T -- 192.168.0.22 docker system dial-stdio] has exited with exit status 255, make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=Host key verification failed.# the operative words are at the very end: Host key verification failed

    Expected resultA long error whose real cause is the last line.

    Success conditionYou read to the end. Docker shells out to ssh, so anything SSH cannot do becomes a Docker error - fix it by making plain ssh to that host work first.

  4. Make plain SSH work, then retry

    The rule for every context problem: if ssh user@host docker version does not work from a terminal, the context will not work either. Fix the SSH layer on its own, then come back.

    bash
    ssh sysadmin@192.168.0.22 docker version --format "{{.Server.Version}}"# make this succeed first - key auth, known host, user in the docker groupdocker --context cg-remote info --format "remote: {{.Name}} / Docker {{.ServerVersion}} / {{.OperatingSystem}}"remote: ahm-docker02 / Docker 29.7.2 / Ubuntu 26.04 LTS

    Expected resultThe remote host identifying itself.

    Success conditionThe name returned is the REMOTE host, not yours. That is the confirmation the context is genuinely connected.

  5. Run commands against the remote host

    --context applies to a single command, which is the safest way to work: no ambiguity about where it landed. Note the local hostname and the reported Docker host differ - that contrast is the whole point.

    bash
    hostnameahm-docker03docker --context cg-remote info --format "{{.Name}}"ahm-docker02docker --context cg-remote images --format "{{.Repository}}:{{.Tag}}" | head -3nginx:alpinenginx:alpinealpine:3.22

    Expected resultLocal hostname one thing, Docker host another, and the remote host's images listed.

    Success conditionYou are administering another machine with no shell session open on it. The images listed are the remote host's.

  6. Switching the active context, and why to be careful

    docker context use changes the default for every subsequent command in every terminal. It is convenient and it is how people accidentally run docker rm -f against production. Prefer --context per command, and if you do switch, switch back.

    bash
    docker context use cg-remoteCurrent context is now "cg-remote"# every plain docker command now targets the REMOTE hostdocker info --format "commands now run against: {{.Name}}"commands now run against: ahm-docker02docker context use defaultback to: ahm-docker03

    Expected resultThe active context switching the target of an otherwise identical command.

    Success conditionYou switched and switched back. docker context ls shows the asterisk - check it before anything destructive.

  7. Do not expose the daemon on a TCP port

    The alternative to SSH is binding the daemon to a TCP port, and 2375 is plain HTTP with no authentication whatsoever. Anyone who can reach that port has root on the host, because they can mount the root filesystem into a container. Confirm yours is not listening.

    bash
    sudo ss -ltn | grep -E ":2375|:2376" || echo "no TCP daemon socket listening - correct"no TCP daemon socket listening - correct

    Expected resultNothing listening on either port.

    Success conditionYour daemon is not reachable over the network except through SSH. If you find 2375 open, treat it as an incident rather than a configuration preference.

  8. Clean up

    Contexts persist in your CLI configuration until removed. Remove any you created for a one-off task, particularly ones pointing at production.

    bash
    docker context rm cg-remotecg-remotedocker context ls --format "{{.Name}}"default

    Expected resultOnly the default context remaining.

    Success conditionThe context is gone. You cannot remove the context that is currently active - switch to default first, which is why the previous step mattered.

Troubleshooting

Official sources