ssh, scp & curl
Log into a remote GPU box, copy files to it, and hit a REST API — all from the terminal using ssh, scp, and curl.
What you'll learn
- How to open a shell on a remote machine with ssh and authenticate using key pairs
- How to copy files between machines with scp, and when to prefer rsync
- How to make HTTP requests from the terminal with curl and wget
Before you start
Why these three tools belong together
ssh (Secure Shell) gives you an encrypted interactive shell on any remote machine you have access to — as if you were sitting in front of it. Once you are logged in, scp (Secure Copy) lets you move files between your laptop and that machine over the same encrypted channel. And curl (Client URL) lets you speak HTTP directly from the terminal, which is how you call REST APIs, download files, and inspect web services. Together they cover almost every “talk to a server” task in data and AI work.
ssh — opening a shell on a remote machine
The basic command is:
ssh user@host
Replace user with your login name on the remote machine and host with its IP address or hostname.
ssh ubuntu@203.0.113.42
After connecting, your prompt changes to show the remote machine’s hostname. Everything you type now runs there, not on your laptop. Type exit (or press Ctrl-D) to disconnect.
Choosing a port
By default ssh listens on port 22. If the server uses a different port, pass -p:
ssh -p 2222 ubuntu@203.0.113.42
Running a single command without opening an interactive shell
Append the command in quotes:
ssh ubuntu@203.0.113.42 "nvidia-smi"
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 535.86.05 Driver Version: 535.86.05 CUDA Version: 12.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
...
The connection closes as soon as the command finishes.
SSH key authentication — why keys beat passwords
When you connect with a password, you type it every time and it travels over the network (even though it is encrypted). An SSH key pair is better: you prove who you are with mathematics instead of a secret string.
A key pair has two files:
- Private key — stays on your laptop, never leaves. Think of it as your house key.
- Public key — copied to every server you want to access. Think of it as the lock. The lock can only be opened by your key, but owning the lock does not help anyone open it.
Generating a key pair
ssh-keygen -t ed25519 -C "your@email.com"
-t ed25519 selects the modern Edwards-curve algorithm (faster and more secure than the older RSA default). -C adds a comment so you know which key this is.
You will be prompted for a passphrase — a local password that encrypts the private key on disk. Use one. If someone steals the file, the passphrase stops them from using it.
The files land in ~/.ssh/:
~/.ssh/id_ed25519 ← private key (keep this secret)
~/.ssh/id_ed25519.pub ← public key (safe to share)
Installing your public key on the server
ssh-copy-id ubuntu@203.0.113.42
ssh-copy-id appends your public key to ~/.ssh/authorized_keys on the remote machine. After that, ssh ubuntu@203.0.113.42 no longer asks for a password — it authenticates with your key pair automatically.
If ssh-copy-id is not available (some macOS setups), you can do it manually:
cat ~/.ssh/id_ed25519.pub | ssh ubuntu@203.0.113.42 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
A diagram of the connection
scp — copying files over SSH
scp (Secure Copy Protocol) uses the same encrypted channel as SSH to copy files. The syntax mirrors cp but every path can be prefixed with user@host: to target the remote machine.
Upload a file to the server
scp dataset.csv ubuntu@203.0.113.42:/home/ubuntu/data/
Download a file from the server
scp ubuntu@203.0.113.42:/home/ubuntu/results/output.json ./results/
Copy a whole directory with -r
scp -r ./my-project ubuntu@203.0.113.42:/home/ubuntu/
When to use rsync instead
scp copies everything every time. If you are syncing a large dataset and the transfer drops halfway, you start from scratch. rsync only transfers the difference:
rsync -avz ./data/ ubuntu@203.0.113.42:/home/ubuntu/data/
-aarchive mode: preserves permissions, timestamps, symlinks-vverbose: shows each file-zcompress data in transit
Use scp for quick one-off copies. Use rsync for anything large or repeated.
curl — making HTTP requests from the terminal
curl (Client URL) sends HTTP requests and prints the response. It is the standard tool for testing APIs, downloading files, and inspecting HTTP headers.
Download a URL
curl https://api.github.com/repos/astro-build/astro
This prints the JSON response body to stdout.
Save to a file with -o
curl -o astro.json https://api.github.com/repos/astro-build/astro
Follow redirects with -L
Many URLs redirect (HTTP 301/302) before landing on the final resource. Without -L, curl stops at the redirect and prints a short HTML page. With it, curl follows automatically:
curl -L -o model.tar.gz https://short.link/model-weights
See only the response headers with -I
-I sends a HEAD request — the server returns headers but no body. Useful to check content-type, content-length, or caching metadata before committing to a full download:
curl -I https://api.github.com/repos/astro-build/astro
HTTP/2 200
content-type: application/json; charset=utf-8
x-ratelimit-remaining: 59
...
Send a custom header with -H
APIs often require an Authorization header:
curl -H "Authorization: Bearer $MY_TOKEN" https://api.example.com/data
Use a shell variable ($MY_TOKEN) rather than pasting the token directly into your history.
POST JSON data with -X POST -d
curl -X POST \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "prompt": "Hello"}' \
https://api.example.com/v1/completions
Newer versions of curl accept --json as a shorthand that sets the content-type header and selects POST automatically:
curl --json '{"model": "gpt-4o", "prompt": "Hello"}' \
https://api.example.com/v1/completions
A realistic AI inference call
curl -X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"What is embeddings?"}]}' \
https://api.openai.com/v1/chat/completions
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"choices": [
{
"message": {
"role": "assistant",
"content": "Embeddings are numerical representations of text ..."
}
}
]
}
wget — the simpler download tool
wget is narrower than curl: it downloads URLs and saves them to files. It is pre-installed on most Linux servers and handles resuming broken downloads with -c:
wget https://example.com/large-dataset.tar.gz
wget -c https://example.com/large-dataset.tar.gz
Use curl when you need headers, POST data, or API calls. Use wget when you just want a file and want automatic retry built in.
Quick reference
| Task | Command |
|---|---|
| Open a remote shell | ssh user@host |
| Run one command remotely | ssh user@host "nvidia-smi" |
| Generate an SSH key | ssh-keygen -t ed25519 -C "you@email.com" |
| Install public key on server | ssh-copy-id user@host |
| Upload a file | scp local.csv user@host:/remote/path/ |
| Download a file | scp user@host:/remote/file.csv ./ |
| Copy a directory | scp -r ./dir user@host:/remote/ |
| Sync a directory (resumable) | rsync -avz ./dir/ user@host:/remote/ |
| Fetch a URL | curl URL |
| Save to file | curl -o file.json URL |
| Follow redirects | curl -L URL |
| Headers only | curl -I URL |
| Add a header | curl -H "Authorization: Bearer $TOKEN" URL |
| POST JSON | curl --json '{"key":"val"}' URL |
| Simple download | wget URL |