You installed k-docker-launcher.exe, your k-docker environment is running as a
WSL2 distribution, and the first thing you try is git push to a private
repository — or signing a commit. Both need your SSH key, and your key lives in
Windows. This is the companion how-to: reuse those Windows keys from inside your
k-docker distro, so git-over-SSH just works and your private key never leaves
Windows.
What you'll learn
- Why copying your
id_ed25519into WSL is the wrong move — technically and for security - How k-docker bridges the Windows OpenSSH agent into your distro so you barely have to do anything
- The one small Windows helper you provide —
npiperelay1 — and where to put it - The zero-install fallback for git, using the Windows
ssh.exe2 - How to wire the same bridge by hand on a plain Ubuntu 26.04 WSL2 distro
- How to confirm your keys are available and push over SSH
Where your keys are — and why WSL can't just use them
On Windows your keys sit in C:\Users\<you>\.ssh\. Inside your k-docker distro
that path is visible at /mnt/c/Users/<you>/.ssh/, so the obvious move is to
point ssh at it — or copy the files into ~/.ssh. Both are traps:
- Permissions. WSL mounts the Windows drive with metadata that presents your
private key as world-readable (
0644). OpenSSH refuses it outright:UNPROTECTED PRIVATE KEY FILE. - Security. Copying a private key into the Linux filesystem duplicates your
most sensitive secret into a
.vhdxthat is trivially exportable and easy to forget about. The key should stay in exactly one place: Windows.
The right model is to borrow the agent, not the key. Your Windows OpenSSH agent already holds the unlocked key and exposes it over a named pipe. We forward that pipe into WSL — the private key bytes never cross the boundary.
What k-docker already does for you
k-docker's WSL distribution ships the bridge pre-wired. On an interactive shell it
runs a small, idempotent snippet that relays the Windows agent pipe
(\\.\pipe\openssh-ssh-agent) into a Unix socket and points SSH_AUTH_SOCK at
it — using socat3 on the Linux side and npiperelay1 on the
Windows side. It is careful to do nothing when it should not: it stays silent
outside WSL, and it never overrides an SSH_AUTH_SOCK that VS Code Remote-WSL has
already forwarded.
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#edb059',
'primaryTextColor': '#222222',
'primaryBorderColor': '#c8951f',
'lineColor': '#5a5450',
'secondaryColor': '#ede9e4',
'secondaryTextColor': '#2d2a26',
'tertiaryColor': '#222222',
'tertiaryTextColor': '#edb059',
'background': '#faf8f5',
'mainBkg': '#faf8f5',
'noteBkgColor': '#f2c880',
'noteTextColor': '#222222',
'clusterBkg': '#faf8f5',
'clusterBorder': '#ede9e4',
'titleColor': '#2d2a26'
}}}%%
flowchart LR
subgraph WIN["Windows"]
AGENT["OpenSSH agent\n(holds your key)"]
PIPE["named pipe\nopenssh-ssh-agent"]
NPR["npiperelay.exe"]
AGENT --> PIPE --> NPR
end
subgraph WSL["k-docker on WSL2"]
SOCAT["socat\nUNIX-LISTEN"]
SOCK["~/.ssh/agent.sock\n= SSH_AUTH_SOCK"]
GIT["git / ssh"]
NPR -. "interop (stdio)" .-> SOCAT --> SOCK --> GIT
endThe bridge: git in WSL talks to a Unix socket, socat forwards each request through npiperelay to the Windows agent, which signs with a key that never leaves Windows.
That means the only things left for you to do are the two things k-docker cannot do on your behalf: run the Windows agent, and provide the one Windows helper binary.
Step 1 — load your key into the Windows agent
In an ordinary Windows PowerShell (not inside WSL), enable the agent service and add your key once:
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add # adds %USERPROFILE%\.ssh\id_ed25519 by default
ssh-add -l # confirm the key is loaded
The agent now holds your unlocked key and will keep serving it across reboots.
Step 2 — provide npiperelay.exe
npiperelay1 is a tiny Windows utility that relays a Windows named
pipe to standard I/O, which is exactly what lets WSL talk to the agent pipe.
Download npiperelay.exe from its releases page and drop it where k-docker looks
for it — %USERPROFILE%\.k-docker\bin\, or anywhere on your Windows PATH:
# example: place it in the k-docker tools dir
mkdir "$env:USERPROFILE\.k-docker\bin" -Force
# ...copy the downloaded npiperelay.exe into that folder
k-docker-launcher.exe reminds you of this and pauses if npiperelay.exe is
missing, so you cannot miss the step. Open a fresh shell in your k-docker distro
and the bridge activates automatically.
The fallback: let git call ssh.exe
If you would rather not install anything, and you only need git over SSH (not
a bare ssh command in WSL), delegate git's transport to the Windows OpenSSH
client2, which already knows your keys, agent, and known_hosts:
git config --global core.sshCommand ssh.exe
This works because k-docker's distro appends the Windows PATH into WSL, so
ssh.exe is directly callable. It is the zero-setup option; the agent bridge above
is the more complete one, because it also covers plain ssh, scp, and anything
else that reads SSH_AUTH_SOCK.
Not using k-docker? Wire the bridge yourself on Ubuntu 26.04
The same technique works on any ordinary WSL2 distro — k-docker just does the plumbing for you. Here is the manual setup on a stock Ubuntu 26.04 distribution, so you understand exactly what the automatic bridge does under the hood.
1. Install socat on the Linux side. This is the only Linux package you need:
sudo apt-get update
sudo apt-get install -y socat
2. Provide npiperelay.exe on the Windows side. Download it from its releases
page1 and put it on your Windows PATH (or note its full path). From
WSL it is reachable as a Windows executable — for example
/mnt/c/Users/<you>/bin/npiperelay.exe.
3. Confirm PATH interop is on. Ubuntu on WSL2 enables Windows-PATH interop
by default, so npiperelay.exe on your Windows PATH is callable straight from the
shell. If you previously disabled it, re-enable it in /etc/wsl.conf:
[interop]
enabled = true
appendWindowsPath = true
Then wsl --shutdown from Windows and reopen the distro.
4. Add the bridge to your shell startup. Append this to ~/.bashrc (or
~/.zshrc). It relays the Windows agent pipe into a Unix socket and points
SSH_AUTH_SOCK at it, but only when needed — it stays out of the way if a socket
is already forwarded (e.g. by VS Code Remote-WSL):
# Reuse the Windows OpenSSH agent from WSL2
if [ -z "$SSH_AUTH_SOCK" ] && command -v npiperelay.exe >/dev/null 2>&1; then
export SSH_AUTH_SOCK="$HOME/.ssh/agent.sock"
if ! ss -a 2>/dev/null | grep -q "$SSH_AUTH_SOCK"; then
rm -f "$SSH_AUTH_SOCK"
( setsid socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork \
EXEC:'npiperelay.exe -ei -s //./pipe/openssh-ssh-agent',nofork \
>/dev/null 2>&1 & )
fi
fi
Open a fresh shell, run ssh-add -l, and you should see the same key as on
Windows — identical to what k-docker gives you out of the box.
Why this is the secure choice
- Your private key never enters Linux. It stays in the Windows agent; only signing requests and responses cross the bridge.
- Hardware and FIDO keys work. Because signing happens in Windows, a security-key or TPM-backed credential is used exactly as it is on the Windows side — no special handling in WSL.
- Nothing to clean up. There is no key file inside the exportable
.vhdxto leak or forget.
Verify it works
Inside your k-docker distro:
ssh-add -l # should list the same key as on Windows
ssh -T git@your-git-host # authenticates using the Windows agent
git push # from a repo with an SSH remote
If ssh-add -l shows your key, you are done — every SSH-aware tool in the distro
now uses it.
Troubleshooting
| Symptom | Fix |
|---|---|
ssh-add -l says "no identities" | Run ssh-add in Windows PowerShell; confirm the ssh-agent service is running. |
Could not open a connection to your authentication agent | npiperelay.exe is missing or not on PATH — place it in %USERPROFILE%\.k-docker\bin\. |
| Works in a plain WSL shell but not the VS Code terminal | VS Code Remote-WSL forwards its own agent socket; that is fine — the bridge respects an existing SSH_AUTH_SOCK. |
ssh.exe fallback not found | Ensure Windows PATH interop is enabled (appendWindowsPath=true, the k-docker default). |
Key takeaways
- Reuse the Windows OpenSSH agent from WSL; never copy the private key across.
- k-docker pre-wires the
socat+npiperelaybridge — you only load your key into the Windows agent and dropnpiperelay.exein place. - For a git-only, zero-install path,
git config --global core.sshCommand ssh.exeis enough. - The bridge is transport-agnostic and safe by default: silent outside WSL, and it never clobbers a socket VS Code already forwarded.
Related reading
- k-docker — download the launcher
- npiperelay — releases
- Microsoft — OpenSSH in Windows
- WSL interop and
wsl.conf
Third-party tools used in this guide are the property of their respective authors and are used under their stated licenses:
npiperelay — © John Starks, MIT License. Source and releases: https://github.com/jstarks/npiperelay.
socat — © Gerhard Rieger and contributors, GNU GPL v2. http://www.dest-unreach.org/socat/.
OpenSSH (the ssh.exe client and ssh-agent) — © the OpenBSD project, BSD-style license; distributed for Windows by Microsoft as the Win32-OpenSSH port. https://github.com/PowerShell/Win32-OpenSSH.