{"record":{"id":"da4c9b98669b6c7f","repo":"jesseduffield/lazydocker","slug":"tunnel-ssh-docker-host-w","errorCode":null,"errorMessage":"tunnel ssh docker host: %w","messagePattern":"tunnel ssh docker host: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/ssh/ssh.go","lineNumber":60,"sourceCode":"\t}\n}\n\n// HandleSSHDockerHost overrides the DOCKER_HOST environment variable\n// to point towards a local unix socket tunneled over SSH to the specified ssh host.\nfunc (self *SSHHandler) HandleSSHDockerHost() (io.Closer, error) {\n\tconst key = \"DOCKER_HOST\"\n\tctx := context.Background()\n\tu, err := url.Parse(self.getenv(key))\n\tif err != nil {\n\t\t// if no or an invalid docker host is specified, continue nominally\n\t\treturn noopCloser{}, nil\n\t}\n\n\t// if the docker host scheme is \"ssh\", forward the docker socket before creating the client\n\tif u.Scheme == \"ssh\" {\n\t\ttunnel, err := self.createDockerHostTunnel(ctx, u.Host)\n\t\tif err != nil {\n\t\t\treturn noopCloser{}, fmt.Errorf(\"tunnel ssh docker host: %w\", err)\n\t\t}\n\t\terr = self.setenv(key, tunnel.socketPath)\n\t\tif err != nil {\n\t\t\treturn noopCloser{}, fmt.Errorf(\"override DOCKER_HOST to tunneled socket: %w\", err)\n\t\t}\n\n\t\treturn tunnel, nil\n\t}\n\treturn noopCloser{}, nil\n}\n\ntype noopCloser struct{}\n\nfunc (noopCloser) Close() error { return nil }\n\ntype tunneledDockerHost struct {\n\tsocketPath string\n\tcmd        *exec.Cmd","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jesseduffield/lazydocker/blob/7e7aadc2071d58031bf2daafca1fbd4093efc23f/pkg/commands/ssh/ssh.go#L42-L78","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nDOCKER_HOST=ssh://user@host lazydocker   # tunnel fails: keys not loaded\n\n# after\neval $(ssh-agent) && ssh-add ~/.ssh/id_ed25519\nDOCKER_HOST=ssh://user@host lazydocker","handlingStrategy":"try-catch","validationCode":"u, err := url.Parse(os.Getenv(\"DOCKER_HOST\"))\nif err == nil && u.Scheme == \"ssh\" {\n    // preflight: does non-interactive ssh work?\n    if err := exec.Command(\"ssh\", \"-o\", \"BatchMode=yes\", u.Host, \"echo\", \"ok\").Run(); err != nil {\n        return fmt.Errorf(\"ssh to %s will fail: %w\", u.Host, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"closer, err := sshHandler.LearnDockerHostShim()\nif err != nil {\n    if strings.Contains(err.Error(), \"tunnel ssh docker host\") {\n        // inspect %w chain: tmp dir / ssh start / dial timeout, guide user accordingly\n        return guideUserThroughSSHSetup(err)\n    }\n}","preventionTips":["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://."],"tags":["docker","ssh","network","docker-host","tunnel"],"backgroundTag":null,"analyzedSha":"7e7aadc2071d58031bf2daafca1fbd4093efc23f","analyzedAt":"2026-08-15T09:51:48.093Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}