# claude-ssh-setup How Claude Code on this Windows machine reaches the `sae-engineering` server (`10.0.2.1`, user `sauer`) over SSH. ## TL;DR OpenSSH on Windows can't load the `.ppk` key (NTFS permissions block it from Git Bash, and the OpenSSH copy of the key fails the same way). PuTTY's `plink` reads the PuTTY keystore natively and the host key is already trusted in the Windows registry. `cmd.exe` mangles `user@host` (treats it as an `AT` job), so invoke plink through `powershell.exe` instead. ## Connection details | Field | Value | | -------- | ---------------------------------------------- | | Host | `10.0.2.1` | | User | `sauer` | | Key | `C:\Users\richa\.ssh\id_ed25519.ppk` (PuTTY) | | Plink | `C:\Program Files\PuTTY\plink.exe` | | pscp | `C:\Program Files\PuTTY\pscp.exe` | ## Single command ```bash powershell.exe -Command "& 'C:\Program Files\PuTTY\plink.exe' -i 'C:\Users\richa\.ssh\id_ed25519.ppk' -batch -l sauer 10.0.2.1 ''" ``` `-batch` disables interactive prompts so the call fails fast in automation instead of hanging. ## Multiple commands Chain with `;` and avoid single quotes inside the remote command (the outer single quotes are already in use): ```bash powershell.exe -Command "& 'C:\Program Files\PuTTY\plink.exe' -i 'C:\Users\richa\.ssh\id_ed25519.ppk' -batch -l sauer 10.0.2.1 '/bin/cmd1; /bin/cmd2'" ``` For anything more complex, write a script locally and run it with the file-transfer recipe below. ## File transfer (pscp) ```bash "/c/Program Files/PuTTY/pscp.exe" -i "C:/Users/richa/.ssh/id_ed25519.ppk" -batch \ localfile sauer@10.0.2.1:/remote/path ``` This is also the workaround when a remote command needs literal quotes or braces — PowerShell + plink eats them. Write the payload to a local file, `pscp` it across, then have plink consume it (e.g. `curl --data-binary @file`). ## "Ubuntu Server Mode" When the user says **"Ubuntu Server Mode"** (or "server mode"), Claude treats every shell command as if it were running on `10.0.2.1` as `sauer` — wrap each command with the plink invocation transparently and follow server-side conventions (`sudo docker compose`, Caddy reload paths, etc.). The server has its own memory at `~/.claude/projects/-home-sauer/memory/MEMORY.md` — read that index before making changes. Stay in this mode until told to exit ("back to local", "exit server mode"). ## Notifications (server side) ```bash claude-notify "message" # send to Telegram bridge claude-inbox --pop # read responses ```