Coming from another GPU cloud
You already run jobs on another GPU cloud and want the same job running on Lium. This page maps what you know to Lium's names, then gives one recipe per step: bring your environment, move data in, run, get results out, check what it cost, clean up. Every command is the lium CLI; the first hour covers signup, top-up and lium init if you have not done them yet.
What maps to what
| What you used elsewhere | On Lium |
|---|---|
| Instance, pod, VM | Pod: a container on one node, with SSH. lium up creates it, lium rm removes it. |
| Instance type, GPU offer | Node: one provider machine. lium ls --gpu H100 lists them, with GPU count, CUDA ceiling, location and bandwidth. |
| Interruptible / spot instance | The spot tier in lium ls (may be reclaimed); secure is dedicated. |
| Machine image, container template | Template: a Docker image plus tag, env, ports and start command. See Templates. |
| Network volume, persistent disk | Volume: object-storage-backed, mounted at /mnt, survives the pod. See Volumes. |
| Stopped instance that keeps its disk | No stopped state: a pod bills until it is removed. Keep what must survive on a Volume or in a backup, then remove the pod. |
| Auto-shutdown, idle timeout | lium up --ttl 6h, --until "today 23:00" or --budget 12.50. See Scheduled termination. |
| Cluster, multi-node job | Clusters. |
| API token | An API key; the CLI reads it from ~/.lium/config.ini or LIUM_API_KEY. |
Billing: a pod's $/h price is charged per second from the deploy request until the pod is removed, with no minimum, once the pod reaches RUNNING (a start that fails is not charged). The full rule, status by status, is When a pod is charged. Prices are on lium.io and in lium ls.
Recipe 1 — Bring your environment
Pick one of three, from least to most work.
The default template. PyTorch with CUDA, Python, git, rsync, tmux and nvcc are already in it (what is on it). Install your requirements after the pod starts:
lium up --gpu H100 --name job --ttl 6h -y --no-ssh
lium rsync job ./requirements.txt /workspace/
lium exec job "pip install -r /workspace/requirements.txt"
Your existing image. If your job already runs from a Docker image, rent with it directly. --internal-ports exposes ports besides SSH (22 is always added):
lium up --gpu H100 --name job --image <registry>/<image>:<tag> --internal-ports 8000 --ttl 6h -y --no-ssh
A stock image that exits right after start (for example a bare nvidia/cuda image) needs a long-running command: add --cmd "sleep infinity". For an image in a private registry, or to pin a digest and reuse the setup, create a template in the dashboard (Create your own template) and rent with lium up -t <template_id>; lium templates --format json lists the ids.
A Dockerfile. lium up --gpu H100 --dockerfile ./Dockerfile builds the image remotely from the Dockerfile text. No build context is uploaded, so COPY of local files does not work; fetch code with git clone or RUN pip install inside the Dockerfile instead.
Blackwell GPUs (B200, B300, RTX 50x0) need an image built for CUDA 12.8 or later; lium templates --arch blackwell lists the templates that qualify.
Recipe 2 — Move code, data and weights in
| From | Command | Notes |
|---|---|---|
| Your laptop or a CI runner | lium rsync job ./data /workspace/data | Copies the contents of ./data. Resumes where it stopped: re-run after an interruption. --exclude, --bwlimit, --progress as in rsync. |
| A single file | lium scp job ./config.yaml /workspace/ | A path ending in / is created if missing. |
| Another Lium pod | lium cp old-pod:/workspace/ckpt/ job:/workspace/ckpt/ | Pod to pod, not through your machine. Both pods need rsync. |
| Hugging Face | lium exec job -e HF_TOKEN=$HF_TOKEN "pip install -U huggingface_hub && hf download <repo> --local-dir /workspace/models/<name>" | HF_TOKEN only for gated or private repos. |
| S3 or any S3-compatible store | see below | The pod downloads directly; nothing passes through your machine. |
For S3, create short-lived keys that can read only that bucket (for example with aws sts assume-role on a read-only role) and pass them to the one command that needs them, so they never land on the pod's disk and stop working soon after:
lium exec job -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN "pip install awscli && aws s3 sync s3://<bucket>/<prefix> /workspace/data"
Never copy ~/.aws/credentials to a pod: it holds every profile you have, and on a pod without confidential computing the provider can read the pod's files.
Where to put things on the pod:
/workspaceis the pod's local disk: the fastest place for datasets, weights and caches (export HF_HOME=/workspace/hf). It is gone when the pod is removed./mntis the Volume, if you attached one (lium up ... --volume new:name=my-data, or--volume id:<huid>for an existing one). It survives the pod and can be attached to the next one, so large datasets are copied in once. It is slower for random I/O than local disk: copy the working set to/workspacebefore a tight training loop.
Bandwidth differs between nodes. lium ls shows each provider's speed test; for a large transfer, rent first and measure inside the pod.
Recipe 3 — Run a training job
Start the job detached so it survives your terminal closing, with its output in a log file on the pod:
lium up --gpu H100 -c 8 --name train --ttl 12h --verify-gpus -y --no-ssh
lium rsync train ./src /workspace/src --exclude .git
lium rsync train ./data /workspace/data
lium exec train "pip install -r /workspace/src/requirements.txt"
lium exec train -d --log /workspace/train.log \
"cd /workspace/src && torchrun --nproc_per_node=8 train.py --data /workspace/data --out /workspace/out"
--verify-gpuscounts the GPUs the pod actually sees and compares them with the count you are billed for; add--strict-gpusto remove the pod on a mismatch. For more checks on multi-GPU nodes, see Multi-GPU checks.-dprints the remote PID and returns at once. Follow the job withlium exec train "tail -n 50 /workspace/train.log", orlium ssh trainandtail -fthere.--ttl 12hremoves the pod after 12 hours even if you forget it. Set it a little above the run's expected length, and write checkpoints to/mnt(or push them out, Recipe 5) so a removal does not lose them.
Recipe 4 — Serve a model for inference
Run an OpenAI-compatible server from its own image and reach it from your machine:
lium up --gpu H100 --name serve --image vllm/vllm-openai:<tag> --internal-ports 8000 \
-e HF_TOKEN=$HF_TOKEN \
--cmd "--model <hf_model_id> --host 0.0.0.0 --port 8000" \
--ttl 4h -y --no-ssh
lium logs serve -f # wait for the server to report it is listening
lium port-forward serve 8000 # localhost:8000 -> the pod's port 8000
curl http://localhost:8000/v1/models
lium port-forward only works for a port the pod exposes, which is what --internal-ports 8000 is for; lium ps serve --format json shows the public port each internal port is mapped to, if you would rather connect without the forward. The vLLM example does the same from Python.
Recipe 5 — Get results out
| To | Command |
|---|---|
| Your machine, one file | lium scp train /workspace/out/model.pt ./ -d |
| Your machine, a directory | lium exec train "tar czf /workspace/out.tgz -C /workspace out", then lium scp train /workspace/out.tgz ./ -d |
| S3 | lium exec train -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN "aws s3 sync /workspace/out s3://<bucket>/<prefix>" with short-lived keys that can write only that bucket |
| Hugging Face | lium exec train -e HF_TOKEN=$HF_TOKEN "hf upload <repo> /workspace/out" |
| The next pod | Leave it on the Volume at /mnt, or lium cp train:/workspace/out/ next:/workspace/out/ |
lium scp -d downloads one file at a time over SSH. For anything above a few hundred megabytes, push from the pod to object storage or Hugging Face instead.
Recipe 6 — Check what it cost
While pods run, lium spend shows the hourly burn, each pod's estimated spend so far and the runway your balance leaves. The billed figures come from the ledger:
lium billing history # every pod charged, removed ones included
lium billing history --from 2026-10-01 --to 2026-10-07
lium billing history --format json gives the same statement as JSON (total, and pods with their days). One pod's statement over the API:
curl https://lium.io/api/pods/<pod_id>/statement \
-H "X-API-Key: $LIUM_API_KEY"
A pod's statement stays available after the pod is removed; see Pod statements and Billing.
Recipe 7 — Tear down
lium rm train -y # irreversible; prints uptime and estimated spend
lium ps # confirm nothing is left running
lium volumes list # volumes outlive pods and are billed separately
lium volumes rm 1 # by index from the last 'lium volumes list'
lium rm exits non-zero when nothing matched, so a typo in a script does not look like a successful teardown. Removing a Volume destroys its data for every pod that uses it.
Next
- Your first hour — the whole path once, with timings
- AI agents — the same steps driven by an agent
- Train a model on a pod — Recipe 3 as a Python script
- Clusters — jobs across several nodes