jesseduffield/lazydocker · error
tunnel ssh docker host: %w
Error message
tunnel ssh docker host: %w
What it means
SSHHandler.LearnDockerHostShim wraps the whole tunnel-creation step: when DOCKER_HOST parses to a ssh:// URL, createDockerHostTunnel is invoked to forward the remote /var/run/docker.sock to a local unix socket via `ssh -L`. This error means that tunnel setup itself failed, with the underlying cause chained via %w (temp dir creation, ssh process start, or the 8-second socket-dial timeout).
Source
Thrown at pkg/commands/ssh/ssh.go:60
}
}
// HandleSSHDockerHost overrides the DOCKER_HOST environment variable
// to point towards a local unix socket tunneled over SSH to the specified ssh host.
func (self *SSHHandler) HandleSSHDockerHost() (io.Closer, error) {
const key = "DOCKER_HOST"
ctx := context.Background()
u, err := url.Parse(self.getenv(key))
if err != nil {
// if no or an invalid docker host is specified, continue nominally
return noopCloser{}, nil
}
// if the docker host scheme is "ssh", forward the docker socket before creating the client
if u.Scheme == "ssh" {
tunnel, err := self.createDockerHostTunnel(ctx, u.Host)
if err != nil {
return noopCloser{}, fmt.Errorf("tunnel ssh docker host: %w", err)
}
err = self.setenv(key, tunnel.socketPath)
if err != nil {
return noopCloser{}, fmt.Errorf("override DOCKER_HOST to tunneled socket: %w", err)
}
return tunnel, nil
}
return noopCloser{}, nil
}
type noopCloser struct{}
func (noopCloser) Close() error { return nil }
type tunneledDockerHost struct {
socketPath string
cmd *exec.CmdView on GitHub (pinned to 7e7aadc207)
Solutions
- Verify manual ssh works non-interactively: `ssh user@host echo ok` — fix keys/agent/config until it does.
- Confirm the remote socket path: `ssh user@host ls -l /var/run/docker.sock`; if docker is rootless or custom, point DOCKER_HOST at a URL whose tunnel target matches (or set DOCKER_HOST=unix:///... after forwarding yourself).
- Check the chained %w message to see which sub-step failed (tmp file / ssh start / socket timeout) and follow that specific fix.
- If the network is slow, pre-establish the tunnel yourself (`ssh -L /tmp/d.sock:/var/run/docker.sock host -N &`) and set DOCKER_HOST=unix:///tmp/d.sock.
Example fix
# before DOCKER_HOST=ssh://user@host lazydocker # tunnel fails: keys not loaded # after eval $(ssh-agent) && ssh-add ~/.ssh/id_ed25519 DOCKER_HOST=ssh://user@host lazydocker
Defensive patterns
Strategy: try-catch
Validate before calling
u, err := url.Parse(os.Getenv("DOCKER_HOST"))
if err == nil && u.Scheme == "ssh" {
// preflight: does non-interactive ssh work?
if err := exec.Command("ssh", "-o", "BatchMode=yes", u.Host, "echo", "ok").Run(); err != nil {
return fmt.Errorf("ssh to %s will fail: %w", u.Host, err)
}
} Try / catch
closer, err := sshHandler.LearnDockerHostShim()
if err != nil {
if strings.Contains(err.Error(), "tunnel ssh docker host") {
// inspect %w chain: tmp dir / ssh start / dial timeout, guide user accordingly
return guideUserThroughSSHSetup(err)
}
} Prevention
- Verify `ssh host echo ok` works non-interactively before pointing DOCKER_HOST at ssh://.
- Load keys in ssh-agent; avoid passphrase prompts in non-interactive tools.
- Confirm the remote socket path is /var/run/docker.sock, or forward it yourself and use unix://.
When it happens
Trigger: Launching lazydocker with DOCKER_HOST=ssh://user@host and any sub-step of createDockerHostTunnel failing: ssh binary missing, ssh authentication failure, unreachable host, or remote docker socket absent so the local socket never becomes dialable within the timeout.
Common situations: SSH keys not loaded (no agent, passphrase prompt fails in non-interactive mode); wrong user/host/port in the DOCKER_HOST URL; remote host has no /var/run/docker.sock (rootless docker uses a different socket path); firewall dropping the connection; 2FA/Interactive auth that cannot complete headlessly.
Related errors
- ssh tunneled socket never became available: %w
- override DOCKER_HOST to tunneled socket: %w
- create ssh tunnel tmp file: %w
- tunnel docker host over ssh: %w
- Cannot proceed until docker gives us more information about
AI-assisted analysis of jesseduffield/lazydocker@7e7aadc207 (2026-08-15).
Data as JSON: /api/errors/da4c9b98669b6c7f.
Report an issue: GitHub.