wsl-ssh-agent

rupor-githubGPL-3.0长期未更新

让 WSL 里的 ssh 命令直接复用 Windows 上 ssh-agent.exe 的密钥,省去重复加载私钥和输入密码的麻烦。

Helper to interface with Windows ssh-agent.exe service from Windows Subsystem for Linux (WSL)

v1.6.9发布于 2025-09-20 14:06 UTC574star21fork同步于 2026-11-07 07:33 UTC

怎么上手

由 README 提炼,执行前请确认
scoop install https://github.com/rupor-github/wsl-ssh-agent/releases/latest/download/wsl-ssh-agent.json
硬件要求按 README 说明

README 未说明;仅要求 Windows 10 1809 起(含 insider build 17063 的 AF_UNIX 支持),WSL2 场景改用 socat + npiperelay 方案

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

在 WSL1 里直接使用 Windows 自带 ssh-agent 的密钥,免去在 Linux 侧重复管理私钥

让 WSL 里的 ssh 命令直接复用 Windows 上 ssh-agent.exe 的密钥,省去重复加载私钥和输入密码的麻烦。

核心能力

  • 用 AF_UNIX 套接字把 WSL 请求代理到 Windows 命名管道
  • 托盘程序 wsl-ssh-agent-gui.exe 维护套接字并转发到 ssh-agent.exe
  • 用 -setenv 自动写入 SSH_AUTH_SOCK 并修改 WSLENV
  • 可兼作远程剪贴板服务器,把 tmux/neovim 剪贴板回传 Windows
  • 会话锁定时默认拒绝访问 ssh-agent,可用 -nolock 关闭

容易踩的坑

项目只对 WSL1 有意义,WSL2 应改用 socat + npiperelay 中继方案;需先在 Windows 启动 ssh-agent 服务并导入密钥;Linux 侧 OpenSSH 版本高于 Windows 自带版本时通信会失败,需升级 Windows OpenSSH;在 Windows 侧设置 SSH_AUTH_SOCK 会干扰 System32\OpenSSH 工具,建议用 -envname 换变量名

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.6.9
  1. v1.6.9最新正式版2025-09-20 · 2025-09-20 14:06 UTC

    Switching to go1.25.1 with dependencies update

    Full Changelog: https://github.com/rupor-github/wsl-ssh-agent/compare/v1.6.8...v1.6.9

  2. v1.6.82025-03-30 · 2025-03-30 12:43 UTC
    查看更新说明

    Maintenance - switch back to vendoring in release build.

    Full Changelog: https://github.com/rupor-github/wsl-ssh-agent/compare/v1.6.7...v1.6.8

  3. v1.6.72025-03-29 · 2025-03-29 20:34 UTC
    查看更新说明

    New Contributors

    Full Changelog: https://github.com/rupor-github/wsl-ssh-agent/compare/v1.6.6...v1.6.7

  4. v1.6.62023-03-13 · 2023-03-13 17:30 UTC
    查看更新说明
    • Moving releases to GitHub Action pipeline
    • Moving to go 1.20 reruning dependencies
    • Using up to date gclpr
    • Vendoring npiperelay
    • Linting with latest staticcheck

    Full Changelog: https://github.com/rupor-github/wsl-ssh-agent/compare/v1.6.3...v1.6.6

  5. v1.6.3Maintenance2022-10-02 · 2022-10-02 13:18 UTC
    查看更新说明

    Recompiling with go 1.19.1

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    IMPORTANT NOTE ON PROJECT HISTORY

    This project was started at the time when WSL2 did not exist and Microsoft just implemented AF_UNIX socket support. Today it is useful only when WSL1 is being required - which is really rare. Sharing Windows side ssh-agent with WSL2 does not need wsl-ssh-agent.exe at all! Please, read on next section on how to setup WSL2 and only continue after that if you really working with WSL1.

    WSL2 compatibility

    At the moment AF_UNIX interop does not seem to be working with WSL2 VMs. Hopefully this will be sorted out eventually. Meantime there is an easy workaround (proposed by multiple people) which does not use wsl-ssh-agent.exe and relies on combination of linux socat tool from your distribution and npiperelay.exe. For example put npiperelay.exe on drvfs for interop to work its magic (I have winhome ⇒ /mnt/c/Users/rupor, copy wsl-ssh-agent-relay into your ~/.local/bin directory, and add following 2 lines to your .bashrc/.zshrc file:

    ${HOME}/.local/bin/wsl-ssh-agent-relay start
    export SSH_AUTH_SOCK=${HOME}/.ssh/wsl-ssh-agent.sock
    

    NOTE: If you are having issues using wsl-ssh-agent-relay with systemd try adding :WSLInterop:M::MZ::/init:PF to /usr/lib/binfmt.d/WSLInterop.conf. For example (thanks to rkl110 - Microsoft/WSL - Issue 8843):

    sudo sh -c 'echo :WSLInterop:M::MZ::/init:PF > /usr/lib/binfmt.d/WSLInterop.conf'
    

    Alternatively if you prefer to directly use systemd support in WSL2 /etc/wsl.conf:

    [boot]
    systemd = true
    

    you could create wsl-ssh-agent.service unit in /usr/lib/systemd/user, something similar to:

    [Unit]
    Description=Windows SSH Agent Proxy via npiperelay
    StartLimitIntervalSec=0
    
    [Service]
    Delegate=true
    Type=exec
    KillMode=process
    ExecStart=/usr/bin/socat UNIX-LISTEN:'/run/user/<user id, usually 1000>/wsl-ssh-agent.sock',fork EXEC:'/home/<user name>/winhome/.wsl/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent',nofork
    
    [Install]
    WantedBy=default.target
    

    and then enable it:

    systemctl --user daemon-reload
    systemctl --user enable --now wsl-ssh-agent.service
    
    export SSH_AUTH_SOCK=${XDG_RUNTIME_DIR}/wsl-ssh-agent.sock
    

    You really have to be on WSL 2 in order for all of this to work - if you see errors like Cannot open netlink socket: Protocol not supported - you probably are under WSL 1 and should not use this workaround. Run wsl.exe -l --all -v to check what is going on. When on WSL 2 make sure that npiperelay.exe is on windows partition and path is right. For convenience I will be packing pre-build npiperelay.exe with wsl-ssh-agent. Please also ensure that socat is installed: sudo apt install socat.

    NOTE: You may be running Linux distribution with OpenSSH version more recent than your Windows host has out of the box. Presently Ubuntu 22.04 and Arch both demonstrate this - communication with ssh-agent will fail. In such cases please visit Windows OpenSSH development and update your Windows OpenSSH with latest release.

    Helper to interface with Windows ssh-agent.exe service from WSL1 (replacement for ssh-agent-wsl).

    GitHub Release

    Windows has very convenient ssh-agent service (with support for persistence and Windows security). Unfortunately it is not accessible from WSL. This project aims to correct this situation by enabling access to SSH keys held by Windows own ssh-agent service from inside the Windows Subsystem for Linux.

    My first attempt - ssh-agent-wsl was successful, but due to Windows interop restrictions it required elaborate life-time management on the WSL side. Starting with build 17063 (which was many updates ago) Windows implemented AF_UNIX sockets. This makes it possible to remove all trickery from WSL side greatly simplifying everything.

    NOTE: If you need access to more functionality (smard cards, identity management) provided by GnuPG set of tools on Windows or if you are looking for compatibility with wider set of utilities, like Git for Windows, Putty, Cygwin - you may want to take a look at win-gpg-agent instead.

    wsl-ssh-agent-gui.exe is a simple "notification tray" applet which maintains AF_UNIX ssh-agent compatible socket on Windows end. It proxies all requests from this socket to ssh-agent.exe via named pipe. The only thing required on WSL end for it to work is to make sure that WSL SSH_AGENT_SOCK points to proper socket path. The same socket could be shared by any/all WSL sessions.

    As an additional bonus wsl-ssh-agent-gui.exe could work as remote clipboard server so you could send your clipboard from tmux or neovim remote session back to your windows box over SSH secured connection easily.

    NOTE: BREAKING CHANGE Version 1.5.0 introduces breaking change. If you were not using wsl-ssh-agent-gui.exe as lemonade clipboard backend - this should not concern you at the slightest. Otherwise lemonade support no longer - it has been replaced with gclpr which is more secure.

    NOTE: BREAKING CHANGE Version 1.6.0 introduces breaking change. If you were not using wsl-ssh-agent-gui.exe as gclpr clipboard backend - this should not concern you at the slightest. Otherwise starting with v1.1.0 gclpr server backend (included with v1.6.0) enforces protocol visioning and may require upgrade of gclpr tools.

    SECURITY NOTICE: All the usual security caveats applicable to WSL apply. Most importantly, all interaction with the Win32 world happens with the credentials of the user who started the WSL environment. In practice, if you allow someone else to log in to your WSL environment remotely, they may be able to access the SSH keys stored in your ssh-agent. This is a fundamental feature of WSL; if you are not sure of what you're doing, do not allow remote access to your WSL environment (i.e. by starting an SSH server).

    COMPATIBILITY NOTICE: wsl-ssh-agent-gui was tested on Windows 10 1903 with multiple distributions and should work on anything starting with 1809 - beginning with insider build 17063 and would not work on older versions of Windows 10, because it requires AF_UNIX socket support feature.

    Installation

        scoop install https://github.com/rupor-github/wsl-ssh-agent/releases/latest/download/wsl-ssh-agent.json
    

    and updating:

        scoop update wsl-ssh-agent
    

    Alternatively download from the releases page and unpack it in a convenient location.

    Starting with v1.5.1 releases are packed with zip and signed with minisign. Here is public key for verification:

    Usage

    1. Ensure that on Windows side ssh-agent.exe service (OpenSSH Authentication Agent) is started and has your keys. (After adding keys to Windows ssh-agent.exe you may remove them from your wsl home .ssh directory - just do not forget to adjust IdentitiesOnly directive in your ssh config accordingly. Keys are securely persisted in Windows registry, available for your account only). You may also want to switch its startup mode to "automatic". Using powershell with elevated privileges (admin mode):
    	Start-Service ssh-agent
    	Set-Service -StartupType Automatic ssh-agent
    
    1. Run wsl-ssh-agent-gui.exe with arguments which make sense for your usage. Basically there are several ways:

      • Using -socket option specify "well known" path on Windows side and then properly specify the same path in every WSL session:

        Windows: cmd wsl-ssh-agent-gui.exe -socket c:\wsl-ssh-agent\ssh-agent.sock

        WSL: bash export SSH_AUTH_SOCK=/mnt/c/wsl-ssh-agent/ssh-agent.sock

      • You could avoid any actions on WSL side by manually setting SSH_AUTH_SOCK and WSLENV=SSH_AUTH_SOCK/up on Windows side (see note below).

      • Using -setenv option allows application automatically modify user environment, so every WSL session started while wsl-ssh-agent-gui.exe is running will have proper SSH_AUTH_SOCK available to it (using WSLENV). By default socket path points to user temporary directory. Usual Windows user environment modification rules are applicable here (see note below).

    NOTE: Setting SSH_AUTH_SOCK environment on Windows side may (and probably will) interfere with some of Windows OpenSSH. As far as I could see presently utilities in Windows\System32\OpenSSH expect this environment variable to be either empty or set to proper ssh-agent.exe pipe, otherwise they cannot read socket:

    	if (getenv("SSH_AUTH_SOCK") == NULL)
    		_putenv("SSH_AUTH_SOCK=\\\\.\\pipe\\openssh-ssh-agent");
    

    To avoid this and still be able to use -setenv and automatically generated socket path use -envname to specify variable name to set. Later on WSL side you could use:

    export SSH_AUTH_SOCK=${<<YOUR-NAME-HERE>>}
    

    When wsl-ssh-agent-gui.exe is running you could see what it is connected to by clicking on its icon in notification tray area and selecting About. At the bottom of the message you would see something like:

    Socket path:
      C:\Users\rupor\AppData\Local\Temp\ssh-273683143.sock
    Pipe name:
      \\.\pipe\openssh-ssh-agent
    Remote clipboard:
      gclpr is serving 2 key(s) on port 2850
    

    For security reasons unless -nolock argument is specified program will refuse access to ssh-agent.exe pipe when user session is locked, so any long running background jobs in WSL which require ssh may fail.

    Options

    Run wsl-ssh-agent-gui.exe -help

    ---------------------------
    wsl-ssh-agent-gui
    ---------------------------
    
    Helper to interface with Windows ssh-agent.exe service from WSL
    
    Version:
    	1.5.0 (go1.15.6)
    
    Usage:
    	wsl-ssh-agent-gui [options]
    
    Options:
    
      -debug
        	Enable verbose debug logging
      -envname name
        	Environment variable name to hold socket path (default "SSH_AUTH_SOCK")
      -help
        	Show help
      -line-endings string
        	Remote clipboard convert line endings (LF/CRLF)
      -nolock
        	Provide access to ss-agent.exe even when user session is locked
      -pipe name
        	Pipe name used by Windows ssh-agent.exe
      -port int
        	Remote clipboard port (default 2850)
      -setenv
        	Export environment variable with 'envname' and modify WSLENV
      -socket path
        	Auth socket path (max 108 characters)
    

    Example

    Putting it all together nicely - remote here refers to your wsl shell or some other box or virtual machine you could ssh to.

    For my WSL installations I always create ~/winhome and link it to my Windows home directory (where I have .wsl directory with various interoperability tools from Windows side). I am assuming that gclpr is in your path on remote and you installed it's Windows counterpart somewhere in drvfs location (~/winhome/.wsl is a good place).

    I auto-start wsl-ssh-agent-gui.exe on logon on my Windows box using following command line:

    wsl-ssh-agent-gui.exe -setenv -envname=WSL_AUTH_SOCK
    

    In my .bashrc I have:

    [ -n ${WSL_AUTH_SOCK} ] && export SSH_AUTH_SOCK=${WSL_AUTH_SOCK}
    

    and my .ssh/config entries used to ssh to remote have port forwarding enabled:

    RemoteForward 2850 127.0.0.1:2850
    

    On remote my tmux.conf includes following lines:

    set -g set-clipboard off
    if-shell 'if [ -n ${WSL_DISTRO_NAME} ]; then true; else false; fi' \
      'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "~/winhome/.wsl/gclpr.exe copy" ; bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "~/winhome/.wsl/gclpr.exe copy"' \
      'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "gclpr copy" ; bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "gclpr copy"'
    

    And my neovim configuration file init.vim on remote has following lines:

    set clipboard+=unnamedplus
    if has("unix")
    	" ----- on UNIX ask lemonade to translate line-endings
    	if empty($WSL_DISTRO_NAME)
    		if executable('gclpr')
    			let g:clipboard = {
    				\   'name': 'gclpr',
    				\   'copy': {
    				\      '+': 'gclpr copy',
    				\      '*': 'gclpr copy',
    				\    },
    				\   'paste': {
    				\      '+': 'gclpr paste --line-ending lf',
    				\      '*': 'gclpr paste --line-ending lf',
    				\   },
    				\   'cache_enabled': 0,
    				\ }
    		endif
    	else
    		" ---- we are inside WSL - reach out to the Windows side
    		if executable($HOME . '/winhome/.wsl/gclpr.exe')
    			let g:clipboard = {
    				\   'name': 'gclpr',
    				\   'copy': {
    				\      '+': $HOME . '/winhome/.wsl/gclpr.exe copy',
    				\      '*': $HOME . '/winhome/.wsl/gclpr.exe copy',
    				\    },
    				\   'paste': {
    				\      '+': $HOME . '/winhome/.wsl/gclpr.exe paste --line-ending lf',
    				\      '*': $HOME . '/winhome/.wsl/gclpr.exe paste --line-ending lf',
    				\   },
    				\   'cache_enabled': 0,
    				\ }
    		endif
    	endif
    endif
    

    Now you could open your WSL in terminal of your choice - mintty, cmd, Windows terminal, ssh to your remote using keys stored in Windows ssh-agent.exe without entering any additional passwords and have your clipboard content back on Windows transparently.

    Credit


    Licensed under the GNU GPL version 3 or later, http://gnu.org/licenses/gpl.html

    This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.