You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The socket forwarding mechanism differs by host operating system
Prerequisites (All Platforms)
Note: This guide is for local devcontainers running via Docker Desktop or Docker Engine. GitHub Codespaces uses different SSH forwarding mechanisms and is not covered here.
IDE Compatibility: While this guide references VS Code, it also applies to VS Code forks that support devcontainers, including Cursor and Windsurf.
Docker Desktop on macOS runs containers inside a Linux VM. Unix sockets cannot be directly mounted from macOS into this VM. Docker Desktop provides a special "magic" socket at /run/host-services/ssh-auth.sock that forwards to whatever SSH_AUTH_SOCK is set to on your Mac.
The catch: Docker Desktop is launched by launchd, which doesn't inherit your shell environment. You must configure SSH_AUTH_SOCK globally.
Host Setup
1. Enable 1Password SSH Agent
Open 1Password → Settings → Developer
Check "Use the SSH agent"
Optionally enable "Display key names when authorizing connections"
2. Create the Socket Symlink (Recommended)
1Password's actual socket path is unwieldy. Create a symlink:
Note: This must be run after every macOS restart, or you can add it to your login items. See 1Password's documentation for making it persistent.
4. Restart Docker Desktop
Quit Docker Desktop completely and reopen it. It will now pick up the SSH_AUTH_SOCK environment variable.
5. Verify Host Setup
# Should list your 1Password SSH keys
ssh-add -l
# Should also list your keys (proves Docker can see them)
docker run --rm -it \
-v /run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock \
-e SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock \
alpine:latest sh -c "apk add --no-cache openssh-client && ssh-add -l"
1Password on Windows uses a Windows named pipe (\\.\pipe\openssh-ssh-agent), not a Unix socket. WSL2 and Docker containers need a Unix socket. You must bridge between them using npiperelay and socat.
Host Setup
1. Enable 1Password SSH Agent (Windows Side)
Open 1Password → Settings → Developer
Check "Use the SSH agent"
Important: Disable the Windows OpenSSH Agent service to avoid conflicts:
# Run in PowerShell as AdministratorStop-Service ssh-agent
Set-Service ssh-agent -StartupType Disabled
2. Verify Windows Side
# In PowerShell (not WSL), should list your keys
ssh-add -l
3. Install npiperelay (Windows Side)
The npiperelay tool bridges Windows named pipes to WSL2. Install it using PowerShell:
# Run in PowerShell (as Administrator recommended)# Create bin directory
mkdir $env:USERPROFILE\bin -Force
# Download and extract npiperelay
cd $env:USERPROFILE\bin
Invoke-WebRequest-Uri "https://github.com/jstarks/npiperelay/releases/download/v0.1.0/npiperelay_windows_amd64.zip"-OutFile "npiperelay.zip"Expand-Archive npiperelay.zip -DestinationPath .-Force
# Add to PATH permanently
[Environment]::SetEnvironmentVariable("PATH","$env:PATH;$env:USERPROFILE\bin","User")
# Verify installation
.\npiperelay.exe-h
Note: winget install jstarks.npiperelay and scoop install npiperelay may not work reliably. The manual download method above is recommended.
Before configuring the bridge, verify WSL2 can access the Windows binary:
# Replace YOUR_WINDOWS_USERNAME with your actual Windows username
/mnt/c/Users/YOUR_WINDOWS_USERNAME/bin/npiperelay.exe -h
You should see the npiperelay help output.
6. Configure the SSH Agent Bridge
Add the following to your ~/.bashrc or ~/.zshrc:
# 1Password SSH Agent relay from Windows# IMPORTANT: Replace YOUR_WINDOWS_USERNAME with your actual Windows usernameexport 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:"/mnt/c/Users/YOUR_WINDOWS_USERNAME/bin/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &) >/dev/null 2>&1fi
Important: You must use the full path to npiperelay.exe (e.g., /mnt/c/Users/billb/bin/npiperelay.exe) because Windows executables are not in WSL2's PATH by default.
7. Verify WSL2 Setup
Open a new terminal (or run source ~/.zshrc / source ~/.bashrc), then:
# Should list your 1Password SSH keys
ssh-add -l
# Should authenticate successfully
ssh -T git@github.com
Alternative: Use systemd (if WSL has systemd enabled)
After the container starts, configure Git for SSH signing:
# Get your public key from the agent
SIGNING_KEY=$(ssh-add -L | head -1)# Configure git
git config --global gpg.format ssh
git config --global user.signingkey "$SIGNING_KEY"
git config --global commit.gpgsign true
git config --global tag.gpgsign true
Important: Remove op-ssh-sign from .gitconfig
If you previously configured 1Password on the host, your ~/.gitconfig may contain:
[gpg "ssh"]program = "/path/to/op-ssh-sign"
Remove or comment out this section. The op-ssh-sign binary doesn't exist inside the container, and it's not needed when using agent forwarding.
Verification
After rebuilding your devcontainer, verify everything works:
# 1. Check agent has keys
ssh-add -l
# Expected: Lists your SSH key(s)# 2. Test SSH connection to GitHub
ssh -T git@github.com
# Expected: "Hi username! You've successfully authenticated..."# 1Password should prompt you to authorize# 3. Check git config
git config --get gpg.format
# Expected: ssh
git config --get user.signingkey
# Expected: Your public key# 4. Test a signed commit
git commit --allow-empty -m "test: verify SSH signing"
git log --show-signature -1
# Expected: Shows "Good signature"
Troubleshooting
"The agent has no identities"
All platforms: Make sure 1Password is unlocked
All platforms: Check that your SSH key is enabled for the agent in 1Password (Key settings → "Use for SSH agent")
macOS: Did you run launchctl setenv? Did you restart Docker Desktop afterward?
Windows: Is the Windows OpenSSH Agent service disabled? (It conflicts with 1Password)
"Error connecting to agent: Connection refused" or "communication with agent failed"
macOS: The direct socket mount doesn't work. Use /run/host-services/ssh-auth.sock instead
Windows: The npiperelay bridge may not be running. Check with ps aux | grep socat
Windows: Verify npiperelay.exe path is correct: /mnt/c/Users/YOUR_USERNAME/bin/npiperelay.exe -h
Windows: Make sure you're using the full path to npiperelay.exe in your shell config (not just npiperelay.exe)
Linux: Check socket permissions: ls -la ~/.1password/agent.sock
"No such file or directory" for agent socket
Rebuild the devcontainer after adding the mount configuration
macOS: Make sure you're mounting /run/host-services/ssh-auth.sock, not the 1Password socket directly
Git commit fails with "cannot run op-ssh-sign"
Your .gitconfig has the [gpg "ssh"] program setting. Remove it — it's not needed with agent forwarding and the binary doesn't exist in the container.
1Password doesn't prompt for authorization
Check that "Require approval for each new application" is enabled in 1Password SSH agent settings
Try locking and unlocking 1Password
Cross-Platform devcontainer.json (Advanced)
If your team uses multiple operating systems, you can try mounting multiple socket paths. The ones that don't exist will fail silently, and you can detect which one works at runtime:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters