# SSH Access via Proxy Agents need to run commands on remote machines — deploy a container, read a log, fix a config. Handing raw SSH private keys to an LLM is a bad idea: keys end up in context windows, logs and transcripts. An SSH-Proxy solves this: it owns the credentials, the agent only speaks HTTP. ## The Model ``` LLM ──HTTPS──► SSH-Proxy ──SSH──► target machines (owns keys, audit log, rate limits) ``` The proxy exposes persistent sessions with a simple REST surface: | Endpoint | Purpose | |---|---| | `POST /connect?target=vps1` | open a session → `session_id` | | `POST //exec` `{command, timeout}` | run a command (async) → `exec_id` | | `GET //exec/` | poll for output | | SFTP endpoints | file up-/download, `ls`, `mkdir`, `rm` | Auth is a Bearer token — the same pattern as every other API you use. ## The Execution Pattern ```bash # 1. connect once, reuse the session for the whole task SID=$(curl -s -H "Authorization: Bearer $KEY" \ "https://ssh-proxy.example/connect?target=vps1" | jq -r .session_id) # 2. run a command EID=$(curl -s -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -X POST "https://ssh-proxy.example/$SID/exec" \ -d '{"command": "docker ps --format \"{{.Names}}\"", "timeout": 120}' | jq -r .exec_id) # 3. poll the result curl -s -H "Authorization: Bearer $KEY" "https://ssh-proxy.example/$SID/exec/$EID" ``` ## Rules of Engagement 1. **Reuse sessions.** Connecting per command wastes resources and trips rate limits. Store the `session_id` (e.g. `/tmp/vps1_sid`) and heartbeat it before reuse. 2. **Name targets, don't discover them.** Targets are pre-registered (`vps1`, `pi`, …). The proxy is the single source of truth — never hardcode IP addresses in agent code. 3. **Prefer SFTP over shell cat/heredoc for files.** Escaping binary data through `exec` corrupts payloads. Use the dedicated upload/download endpoints. 4. **Quote your commands.** The JSON body is parsed twice (HTTP + shell). Wrap remote commands in single quotes and keep them one-liners. 5. **Assume auditing.** Every exec lands in the proxy's audit log — behave as if the human reads everything (they can). ## When NOT to use exec - Reading structured state that has an API (Docker, databases, the Synapse Mind API) — always prefer the API over parsing CLI output. - Long-running interactive processes. `exec` is fire-and-forget with a timeout; use `nohup` + a status file on the target instead. - Anything destructive without an explicit instruction. The proxy gives you the power — the human gives you the permission. ## Error Recovery | Symptom | Fix | |---|---| | 401 on connect | token expired — re-read it from memory/settings, never from a transcript | | session 404 | session expired (24h cap) — reconnect | | exec timeout | raise `timeout` or split the command; check load on the target | | garbled file content | you used `exec` instead of SFTP — switch to the SFTP endpoints |