Use Docker Contexts over SSH for Safer Remote Admin

Control a remote Docker engine through the official SSH transport so day-two admin work stays cleaner and safer than exposing the daemon on the network.

Docker contextsSSH transportSafer remote admin
Illustrated guide cover for Use Docker Contexts over SSH for Safer Remote Admin
Docker contexts • SSH transport • Safer remote admin
What you learn

How to create an SSH-backed Docker context, verify which engine the CLI is targeting, inspect remote resources, and switch back to the local default safely.

Best for

Operators who already run Docker on a VPS and want cleaner remote control than ad hoc SSH wrappers or public TCP daemon exposure.

Risk to watch

The common mistake is forgetting which context is active and then running a destructive command against the wrong engine.

Before you begin

  • A local machine with a Docker CLI that supports the top-level docker context command.
  • SSH access to the remote Linux host.
  • Docker already installed and working on that host.
  • A remote user that can talk to the Docker socket on the host.

Docker's current documentation keeps the safest first recommendation simple: use the local Unix socket by default, and if you need remote access, prefer SSH or a TLS-protected socket instead of exposing an unauthenticated TCP daemon. Contexts build on that by storing the connection details and letting you switch targets cleanly with one command.

Expected outcome: By the end, your local CLI can target one remote Docker host through SSH with a named context, and you will have a repeatable habit for checking which engine is active before you run commands.

Step 1: Understand what a Docker context changes

A Docker context is just a named set of endpoint details and metadata. The Docker docs describe it as the information required to manage resources on a daemon. That matters because it lets you stop hard-coding connection details into shell history.

List the contexts you already have:

docker context ls
docker context inspect default

The active context is marked with an asterisk. Until you change it, that is usually default, which points at the local socket on your machine.

Warning: Treat context switching like switching Kubernetes clusters or production shells. Always confirm where you are before running docker rm, docker compose up, or image-prune commands.

Step 2: Confirm SSH and Docker access on the remote host

Before you create the context, prove the basics from your local machine:

ssh docker-user@host1.example.com
docker info
exit

If docker info fails on the host, fix that first. The SSH-backed context still relies on the remote user being allowed to reach Docker. Docker's daemon-protection docs explicitly note that the remote username must have permission to access the Docker socket.

If you use SSH often, add connection reuse settings to your local ~/.ssh/config so repeated Docker CLI calls are less expensive:

Host *
  ControlMaster auto
  ControlPath ~/.ssh/control-%C
  ControlPersist yes

Step 3: Create the SSH-backed context

Create a named context using the official SSH host syntax:

docker context create \
  --docker host=ssh://docker-user@host1.example.com \
  --description "Remote VPS engine" \
  my-remote-engine

Inspect what Docker stored:

docker context inspect my-remote-engine

You should see the Docker endpoint set to an ssh:// URL rather than a public TCP daemon address. That is the security win here: the Docker API stays behind SSH instead of being opened directly on the network.

Step 4: Use the remote context deliberately

Switch to the remote context:

docker context use my-remote-engine
docker context ls

Now verify that the CLI is really talking to the remote engine:

docker info
docker ps
docker image ls
docker network ls

If you only need the remote host for one command, you do not have to switch globally. The docs also support the global flag form:

docker --context my-remote-engine ps

That is a strong habit when you want explicitness in scripts or when you are bouncing between a laptop engine and one remote VPS in the same terminal session.

Step 5: Switch back to the local default context

When remote work is done, return to the local engine:

docker context use default
docker context ls
docker info

Do not normalize staying on a remote context all day unless you have a strong reason. Switching back reduces the chance that the next test command hits production infrastructure by accident.

If you prefer temporary shell scoping instead of changing the global active context, export DOCKER_CONTEXT only for the current shell:

export DOCKER_CONTEXT=my-remote-engine
docker ps
unset DOCKER_CONTEXT

Rollback and recovery notes

This workflow is easy to unwind because the context lives on your client, not the server. If the context points at the wrong host or user, remove it and recreate it:

docker context use default
docker context rm my-remote-engine
docker context create --docker host=ssh://docker-user@host1.example.com my-remote-engine

If you are troubleshooting production access, do that with ordinary SSH first. Contexts are an admin convenience layer, not a substitute for basic host reachability checks.

Troubleshooting common context mistakes

docker info fails only through the context.
The remote user may not be allowed to access the Docker socket, or SSH may be working but not loading the expected environment.

You forgot which engine is active.
Run docker context ls before any risky operation. Make it part of your muscle memory.

You are tempted to open port 2375 publicly.
Do not. Docker's own docs position SSH or TLS as the protected options. Public TCP daemon exposure is the wrong default for this guide.

The remote CLI feels slow.
Use SSH connection reuse with ControlMaster, ControlPath, and ControlPersist so multiple Docker calls do not rebuild the SSH session every time.

What to do next: After the remote-admin path feels clean, the next useful hardening step is reducing daemon privilege where practical. Continue with Run Docker in Rootless Mode on Ubuntu.