Run ComfyUI on a Lium GPU
Install ComfyUI on a Lium RTX 4090, load the openly licensed SDXL base checkpoint, open the UI through an SSH tunnel and generate an image through the ComfyUI HTTP API. 19 minutes of pod time, about 15 cents.
Lium team5 min read
comfyui
stable-diffusion
sdxl
image-generation
rtx-4090
ComfyUI is the node-based workbench many people use for Stable Diffusion: you wire models, prompts and samplers together in the browser, and the same graph can be sent to its HTTP API from a script. It wants a GPU with plenty of memory, which is exactly what you can rent on Lium for the length of a session.
In this guide we install ComfyUI on a Lium RTX 4090, download the Stable Diffusion XL base 1.0 checkpoint, open the UI on a laptop through an SSH tunnel, and generate a 1024x1024 image with a short Python script that calls the API. SDXL base is released under the CreativeML Open RAIL++-M license and downloads without a Hugging Face token.
Every command and number below comes from our test run on 15 October 2026: a 1x RTX 4090 at $0.48 per hour, ready 21 seconds after we asked for it, 6.1 seconds per image once the model was loaded, 19 minutes of pod time and about $0.15 in total.
1. Rent a GPU
You need a Lium account with a little balance and Python 3 on your laptop. Install the CLI and sign in once;
lium init opens the browser and saves your API key and SSH key.bash
curl -fsSL https://lium.io/install.sh | bash # or: pip install lium.io
lium initSDXL runs comfortably on a 24 GB card.
--gpu RTX4090 rents the cheapest matching node, --ttl 2h removes the pod two hours later even if you forget it, -y skips the confirmation and --no-ssh returns to your shell.bash
lium up --gpu RTX4090 --name comfy --ttl 2h -y --no-sshThe pod starts from the default PyTorch (CUDA + DinD) template, which already has a CUDA build of PyTorch, Python 3.12 and git.
2. Install ComfyUI
Clone ComfyUI and install its requirements into the pod's Python. The template pins
pip to the image's own torch build, so this keeps the CUDA-enabled PyTorch that came with the image and only adds what ComfyUI needs.bash
lium exec comfy 'cd /root && git clone https://github.com/comfyanonymous/ComfyUI && cd ComfyUI && git checkout -q ba994879 && pip install -q -r requirements.txt'This took just under two minutes. We tested ComfyUI at commit
ba994879 (14 October 2026).3. Download a checkpoint
Put the SDXL base checkpoint in ComfyUI's checkpoint folder:
bash
lium exec comfy 'cd /root/ComfyUI/models/checkpoints && curl -fsSL -o sd_xl_base_1.0.safetensors https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors && sha256sum sd_xl_base_1.0.safetensors'The file is 6.9 GB; its SHA-256 should be
31e35c80fc4829d14f90153f4c74cd59c90b779f6afe05a74cd6120b893f7e5b, the value Hugging Face lists for it. On our node the download took about 8 minutes. Download speed varies by node; lium ls --min-download 1000 lists only nodes that report at least 1 Gbps if you want a faster start.4. Start ComfyUI and open the UI
Start the server in the background with
lium exec -d. --listen 127.0.0.1 keeps it private to the pod; you'll reach it through SSH.bash
lium exec comfy -d --log /root/comfy.log 'cd /root/ComfyUI && python3 main.py --listen 127.0.0.1 --port 8188'A few seconds later the log ends with
To see the GUI go to: http://127.0.0.1:8188:bash
lium exec comfy 'tail -n 5 /root/comfy.log'Open a second terminal for an SSH tunnel. It sends your laptop's
127.0.0.1:8188 to the same address inside the pod without opening the port to the internet. The $(...) part prints the pod's SSH command from lium describe, and the flags after it turn that into a tunnel. Leave it running.bash
$(lium describe comfy --json | python3 -c 'import json,sys; print(json.load(sys.stdin)["access"]["ssh_cmd"])') \
-N -L 8188:127.0.0.1:8188Now open
http://127.0.0.1:8188 in your browser to use the ComfyUI editor. The page loads on your laptop, and every graph you queue runs on the pod's GPU; pick sd_xl_base_1.0.safetensors in the Load Checkpoint node.5. Generate an image through the API
The same server takes workflows over HTTP, so generation is easy to script. You
POST a graph to /prompt, wait until /history/<prompt_id> has the result, and fetch the image from /view. This script uses only the Python standard library. Save it as generate.py on your laptop:python
import json, time, urllib.parse, urllib.request
URL = "http://127.0.0.1:8188"
workflow = {
"1": {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": "sd_xl_base_1.0.safetensors"}},
"2": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["1", 1],
"text": "a lighthouse on a rocky coast at sunset, dramatic clouds, detailed oil painting"}},
"3": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["1", 1], "text": "blurry, low quality"}},
"4": {"class_type": "EmptyLatentImage", "inputs": {"width": 1024, "height": 1024, "batch_size": 1}},
"5": {"class_type": "KSampler", "inputs": {"model": ["1", 0], "positive": ["2", 0], "negative": ["3", 0],
"latent_image": ["4", 0], "seed": 42, "steps": 25, "cfg": 7.0,
"sampler_name": "euler", "scheduler": "normal", "denoise": 1.0}},
"6": {"class_type": "VAEDecode", "inputs": {"samples": ["5", 0], "vae": ["1", 2]}},
"7": {"class_type": "SaveImage", "inputs": {"images": ["6", 0], "filename_prefix": "lium"}},
}
def call(path, body=None):
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(URL + path, data=data, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req) as resp:
return resp.read()
start = time.time()
prompt_id = json.loads(call("/prompt", {"prompt": workflow}))["prompt_id"]
while True:
history = json.loads(call(f"/history/{prompt_id}"))
if prompt_id in history:
break
time.sleep(1)
print(f"done in {time.time() - start:.1f} s")
for output in history[prompt_id]["outputs"].values():
for image in output.get("images", []):
query = urllib.parse.urlencode(image)
with open(image["filename"], "wb") as f:
f.write(call(f"/view?{query}"))
print("saved", image["filename"])The keys
"1" to "7" are node IDs, and an input such as ["1", 1] means "output 1 of node 1" (the checkpoint's CLIP text encoder). It is the API format of the default text-to-image graph.Run it with the tunnel still open:
bash
python3 generate.pytext
done in 24.0 s
saved lium_00001_.pngThe first request includes loading SDXL onto the GPU. After that the 4090 sampled at about 5.7 steps per second: with a new seed, the next 25-step 1024x1024 image took 6.1 seconds end to end, 5.2 seconds of it on the GPU. ComfyUI caches results, so sending the exact same graph again returns almost instantly; change the seed or prompt to get a new image.
The script already saved the PNG on your laptop through the API. The images also stay on the pod in
/root/ComfyUI/output, and lium scp -d copies any of them back:bash
lium scp comfy /root/ComfyUI/output/lium_00001_.png . -dClean up
Stop the tunnel with Ctrl+C, then remove the pod. Billing stops the moment it is gone, and the two-hour TTL would have removed it anyway.
bash
lium rm comfy -yOur pod ran for 19 minutes at $0.48 per hour, about $0.15 for the whole test, most of it spent downloading the checkpoint.
Why Lium for this
Image generation is bursty: you want a strong GPU while you iterate on a workflow and nothing in between. Lium rents a single RTX 4090 by the second with no minimum, so a session costs what it actually ran. The pod was ready in about 20 seconds with CUDA PyTorch already installed, the UI stays private behind your own SSH tunnel, and the HTTP API turns the same workflow into a script once you are happy with it.
--ttl removes the pod on schedule, so a forgotten session never keeps billing.Run it on Lium
See RTX-4090 pricing and availability before you start.