Create an SSH key and connect to your Spark
This guide gets you from no key to ssh spark on your own computer in about two minutes. You do not need an SSH key to deploy: GPUwerk configures the machine, and the browser terminal in the console works without one. Add a key when you want SSH, scp, port forwarding or VS Code Remote-SSH from your own machine. SSH on an instance accepts keys only (the image sets PasswordAuthentication no), so there is no password to fall back on.
You need: a terminal with OpenSSH (macOS, Linux, or Windows 10/11 PowerShell) and a GPUwerk account. A running instance helps for step 4, but you can add the key before or after you deploy.
1. Generate the key
A key pair is two files. The private key stays on your laptop forever and is the actual secret. The public key, the file ending in .pub, is safe to paste anywhere. It is the one you give GPUwerk.
Use ed25519. It is the modern default, the keys are short, and OpenSSH has supported it since version 6.5 in 2014, so nothing you will connect to is too old for it.
ssh-keygen -t ed25519 -C "[email protected]"
# PowerShell, OpenSSH ships with Windows ssh-keygen -t ed25519 -C "[email protected]"
- Press Enter to accept the default path (
~/.ssh/id_ed25519, orC:\Users\you\.ssh\id_ed25519on Windows). - When it asks for a passphrase, set one. Without a passphrase the private key is a plaintext credential in your home directory, and after the next step you type the passphrase only once per session anyway.
Result: two new files, id_ed25519 and id_ed25519.pub, in your .ssh folder, and a fingerprint line starting with SHA256: in the terminal.
Already have a key? Run ls ~/.ssh/*.pub first. If you see id_ed25519.pub or id_rsa.pub, reuse it. There is no benefit to a fresh key per provider, and a second key is a second thing to lose.
2. Load it into the agent
The ssh-agent holds your unlocked private key in memory, so you type the passphrase once instead of on every connection. Run the block for your system; ssh-add -l should then list your key.
# --apple-use-keychain stores the # passphrase across reboots ssh-add --apple-use-keychain ~/.ssh/id_ed25519
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519
# once, as Administrator
Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
3. Give the public key to your instance
Print the public key and copy the whole line, from ssh-ed25519 through the trailing comment:
# macOS, straight to the clipboard pbcopy < ~/.ssh/id_ed25519.pub # Linux cat ~/.ssh/id_ed25519.pub # Windows PowerShell Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard
It is one line, and it looks like this:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7f...4mQ2 [email protected]
Where you paste it depends on whether the instance exists yet:
- New instance: paste it into the optional SSH key field when you deploy in the console. If you saved a key on your account earlier, the newest one is used automatically.
- Instance already running without a key: open the instance in the console and use Reset SSH access, pasting the key there (or call
POST /v1/instances/<id>/reset-accesswith{"ssh_public_key": "..."}). Nothing else on the instance changes.
GPUwerk accepts ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256/384/521 and FIDO (sk-) keys. The key goes into /root/.ssh/authorized_keys when the container starts and is stored with the instance, so a rebuild keeps it.
Paste the public key, never the private one. If the text you copied starts with -----BEGIN OPENSSH PRIVATE KEY-----, you have the wrong file. The right one is the same name with .pub on the end.
4. Connect
Every instance gets its own hostname, <instance-name>.gpuwerk.com, and its own public IPv4, shown on the instance page in the console. Connect straight to it on the standard SSH port:
ssh [email protected]
Result: the first connection asks you to confirm a host key fingerprint. Type yes once and it is saved in ~/.ssh/known_hosts. You then get a root prompt (cd /workspace for your persistent files).
Host keys live in the instance workspace, so a stop and start does not change them. The hostname follows the instance even if its IPv4 changes on start, so connect by hostname, not by address.
/workspace is the part that survives a stop. Anything you install outside it lives on the container filesystem and is gone after a rebuild, so keep models, checkouts and datasets under /workspace.
5. Make it one word to type
Add this to ~/.ssh/config (create the file if it is missing; on Windows it is C:\Users\you\.ssh\config), with your instance's hostname:
Host spark
HostName my-instance.gpuwerk.com
User root
IdentityFile ~/.ssh/id_ed25519
# keeps an idle session from being dropped
ServerAliveInterval 60
Now ssh spark is the whole command, and scp bigfile.jsonl spark:/workspace/ works the same way. The Remote-SSH extensions in VS Code and Cursor read this file too, so the host appears in their picker with no extra configuration.
6. Reach a web UI over the tunnel
When you run something with a browser interface on the instance (Open WebUI, a Jupyter server, a vLLM server you would rather not publish), do not open it to the internet. Forward the port over SSH instead:
# -N means "no shell, just the tunnel"
ssh -N -L 8080:localhost:8080 spark
Leave that running, and http://localhost:8080 in your browser is the instance's port 8080: encrypted, authenticated by your key, invisible to everyone else. Chain more -L flags for more ports.
Model presets (for example Qwen3 Coder 30B or GPT-OSS 120B) also get a public HTTPS endpoint, shown as HTTPS endpoint on the instance page and as https_endpoint in the API, and it requires an API key with the inference scope. Base images (DGX OS, Ubuntu) get no public HTTPS endpoint, so use the SSH tunnel for anything you run on them.
When it does not work
The browser terminal does not depend on your key, so you can always get a shell there while you fix SSH.
Permission denied (publickey).
- Cause: the server did not accept your key.
- Check: run
ssh -v [email protected]and read theOffering public keylines. - Fix: if your key is never offered, the agent does not have it: run
ssh-add -land add it. If it is offered and refused, the instance has a different key. Use Reset SSH access (below) with the key you hold.
Bad permissions, or UNPROTECTED PRIVATE KEY FILE.
- Cause: other users on your machine can read the private key, so OpenSSH refuses it. Common after copying a key over a USB stick or cloud drive.
- Fix:
chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519.
REMOTE HOST IDENTIFICATION HAS CHANGED.
- Cause: a new instance reused a released hostname or IPv4 and presents a different host key. Expected after you terminate an instance and deploy another with the same name.
- Fix:
ssh-keygen -R my-instance.gpuwerk.com(and the IP, if you connected by address), then reconnect. - Careful: do this only when you know the instance changed. On a host you did not change, the same warning is what an interception looks like.
Locked out from the inside.
- Cause: you deleted or overwrote
/root/.ssh/authorized_keys, broke/etc/ssh/sshd_config, or lost the private key you deployed with. - Fix: start the instance if it is stopped. Then open it in the console and use Locked out? Reset SSH access in its SSH section, or call
POST /v1/instances/<id>/reset-access. It reinstalls every SSH key on your account, plus a new one if you paste it, and restores the defaultsshd_config. - Result: SSH works again. Your workspace, running processes and data are untouched.