YeetLLM is a RunPod-ready inference appliance that keeps one or more Hugging Face models resident in separate vLLM engines and exposes all base models and static LoRA adapters through one OpenAI-compatible endpoint.
SSH -L 8000:127.0.0.1:8000
│
▼
127.0.0.1:8000 router
├── 127.0.0.1:8100 base A + LoRAs
├── 127.0.0.1:8101 base B + LoRAs
└── 127.0.0.1:8102 base C + LoRAs
There is no model swapping or eviction. Each configured base model has one long-lived vLLM process and stays loaded until that process or the container stops.
YeetLLM is currently on the
developmentline. Pushes to thedevelopmentbranch publish test images without creating a GitHub release.
YeetLLM does not compile vLLM. It derives from the official vLLM 0.27.0 CUDA 13 image, pinned by its immutable manifest digest. CUDA 12.6 is not supported.
| Image tag | Upstream base | CUDA userspace | Intended RunPod filter |
|---|---|---|---|
development |
vllm/vllm-openai:v0.27.0 |
13.0.2 | CUDA 13.0 |
The final Docker stage only adds YeetLLM and its SSH/runtime-tools overlay; it does not run package installation or compilation against the vLLM filesystem. Its linked overlay layers allow BuildKit exporters with lazy-base support to reuse the official layers without unpacking the full CUDA filesystem.
The pinned official amd64 vLLM manifest itself contains a 4.64 GB compressed layer. YeetLLM preserves that upstream layer verbatim. This avoids creating an additional oversized custom layer, but it cannot repair a RunPod host or registry path that rejects the official vLLM layer itself.
Expected development tags after the branch workflow runs:
ghcr.io/returnmoe/yeetllm:development
ghcr.io/returnmoe/yeetllm:dev-<commit SHA>
The immutable commit tag is pushed and checked first; only then does the
workflow advance the moving development tag. It never creates a release.
Filter the RunPod template for CUDA 13.0. The host driver comes from RunPod;
the container supplies the matching CUDA userspace.
YeetLLM logs both the host driver/capability and torch.version.cuda at boot.
Create persistent configuration at /workspace/yeetllm/config.yaml:
models:
- id: qwen
model: Qwen/Qwen3-0.6B
gpus: [0]
tensor_parallel_size: 1
pipeline_parallel_size: 1
trust_remote_code: false
dtype: auto
quantization: auto
gpu_memory_utilization: 0.90
ssh:
enable: auto
port: 22The complete annotated schema is in config.example.yaml.
Validate without loading or downloading a model:
yeetllm validateThe container command is yeetllm serve. Startup readiness stays unhealthy
until every configured engine is ready.
Assign independent engines to disjoint physical GPUs:
startup:
policy: all
parallelism: 1
models:
- id: qwen
model: Qwen/Qwen3-32B
gpus: [0, 1]
tensor_parallel_size: 2
pipeline_parallel_size: 1
- id: gemma
model: google/gemma-3-27b-it
gpus: [2, 3]
tensor_parallel_size: 2
pipeline_parallel_size: 1Both engines remain resident. Requests can alternate qwen, gemma, and back
again without reloading weights. See
examples/multiple-models.yaml.
GPU overlap is rejected unless the root option allow_shared_gpus: true is set.
Sharing only opts into contention; it does not reserve memory or make two
independent engines safe from OOM.
For a four-GPU tensor-parallel engine:
models:
- id: qwen
model: Qwen/Qwen3-32B
gpus: [0, 1, 2, 3]
tensor_parallel_size: 4
pipeline_parallel_size: 1Each process receives an argv array and an isolated
CUDA_VISIBLE_DEVICES=0,1,2,3; model IDs and extra_args are never interpolated
into a shell command. On one node vLLM uses its native multiprocessing path.
tensor_parallel_size × pipeline_parallel_size must match the allocated GPU
count (or the total count across nodes in an Instant Cluster).
For a concrete two-GPU DeepSeek V4 example, see
examples/deepseek-v4-flash-abliterated.yaml.
It targets the 0731 abliterated NVFP4 checkpoint on two 180 GB B200 GPUs. The
checkpoint is too close to a single B200's capacity to leave safe room for vLLM
workspaces and KV cache. The example deliberately starts with a 4K context,
eager execution, and target-only decoding; increase context and enable the
included DSpark drafter only after the conservative configuration is serving
correctly. It intentionally leaves B200's GPU interconnect enabled rather than
applying the PCIe-only workarounds previously required for RTX PRO 6000.
When a two-B200 allocation is unavailable, the sibling
examples/deepseek-v4-flash-abliterated-b300.yaml
targets one 288 GB B300 with TP=1. That leaves substantially more single-GPU
runtime headroom than attempting to fit the checkpoint on one 180 GB B200.
If datacenter Blackwell is unavailable, the separate
examples/deepseek-v4-flash-abliterated-h200.yaml
targets two 141 GB H200 SXM GPUs with TP=2. It switches to the 167 GB native
mixed-FP8 apetersson/DeepSeek-V4-Flash-0731-Abliterated-FP8 checkpoint because
the NVFP4 example is not a drop-in Hopper deployment. Its first boot excludes
expert parallelism, prefix caching and DSpark so basic generation can be
validated before adding independent optimization paths.
Static LoRA loading is enabled per base engine:
models:
- id: qwen
model: Qwen/Qwen3-32B
gpus: [0, 1]
tensor_parallel_size: 2
lora:
enabled: true
max_loras: 4
max_lora_rank: 64
max_cpu_loras: 8
fully_sharded_loras: false
adapters:
- id: qwen-code
model: organization/qwen-code-lora
- id: qwen-rp
model: organization/qwen-rp-loraAdapters are resolved into the persistent Hugging Face cache before that engine
starts and are passed with vLLM's current JSON --lora-modules form. YeetLLM
requires global uniqueness across base and adapter IDs, verifies
max_cpu_loras >= max(max_loras, number of static adapters), and checks cached
adapter rank against max_lora_rank. vLLM 0.27.0 accepts ranks
1, 8, 16, 32, 64, 128, 256, 320, 512.
The base and its LoRAs can serve concurrent requests according to vLLM's LoRA
scheduler. Upstream runtime load/unload endpoints are blocked and
VLLM_ALLOW_RUNTIME_LORA_UPDATING is removed from engine environments.
YeetLLM does not currently expose a runtime mutation API.
RunPod maps internal TCP 22 to a public port. Open exactly one tunnel:
ssh -N \
-L 8000:127.0.0.1:8000 \
-p "$RUNPOD_TCP_PORT_22" \
root@"$RUNPOD_PUBLIC_IP"The only client base URL is:
http://127.0.0.1:8000/v1
Python with the official OpenAI client:
from openai import OpenAI
client = OpenAI(
api_key="not-used-by-the-loopback-appliance",
base_url="http://127.0.0.1:8000/v1",
)
response = client.chat.completions.create(
model="qwen-code",
messages=[{"role": "user", "content": "Write a Python iterator."}],
stream=True,
)
for chunk in response:
print(chunk.choices[0].delta.content or "", end="", flush=True)GET /v1/models is assembled from the canonical YeetLLM registry:
{
"object": "list",
"data": [
{"id": "qwen", "object": "model", "owned_by": "yeetllm", "parent": null},
{"id": "qwen-code", "object": "model", "owned_by": "yeetllm", "parent": "qwen"},
{"id": "qwen-rp", "object": "model", "owned_by": "yeetllm", "parent": "qwen"},
{"id": "gemma", "object": "model", "owned_by": "yeetllm", "parent": null}
]
}The router proxies /v1/* generically, selecting an engine from the JSON,
form, multipart, or query-string model field. It preserves the original model
ID, upstream status, relevant headers, and streams SSE chunks without collecting
the full response. Response-ID affinity supports follow-up Responses API routes.
GET /health/live checks the router process. GET /health/ready succeeds only
when the supervisor heartbeat is fresh and every required engine is ready.
The current vLLM Production Stack router supports static backends, multiple models, and aliases, but its primary scope is cluster-wide/Kubernetes routing, replicas, and scheduling. YeetLLM needs one-to-one integration with a local process supervisor, a flattened base+LoRA catalog, exact adapter-ID preservation, Responses API affinity, and readiness without synthetic generation requests. The intentionally small proxy here owns only those appliance concerns; vLLM still owns all inference behavior.
ssh.enable: auto does not start sshd merely because the image runs on
RunPod. It starts only after a non-empty public-key source is detected and the
selected key passes ssh-keygen validation. Precedence is:
YEETLLM_SSH_AUTHORIZED_KEYSSSH_PUBLIC_KEY/root/.ssh/authorized_keysPUBLIC_KEY
This covers RunPod's current account-key injection, per-Pod key, and established
container conventions. If auto mode finds no key, it logs a diagnostic and
leaves SSH disabled—there is no port-22 listener. ssh.enable: true with no
valid key is a startup error. Worker nodes in an Instant Cluster never start
sshd.
At runtime YeetLLM generates fresh Ed25519 and RSA host private keys under
/run, then prints each public key and SHA256 fingerprint to container logs.
The image contains no host private keys. Root administration is public-key-only:
PermitRootLogin prohibit-password
AuthenticationMethods publickey
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowTcpForwarding local
GatewayPorts no
AllowAgentForwarding no
AllowStreamLocalForwarding no
X11Forwarding no
PermitTunnel no
PermitUserEnvironment no
Model engines and the router run as the unprivileged vllm account provided by
the official base image. sshd runs as root because root is the intended
administrator for the disposable Pod.
Model repositories are downloaded explicitly with vLLM's --download-dir to:
/workspace/yeetllm/cache/huggingface/hub
YeetLLM also pins HF_HOME, HUGGINGFACE_HUB_CACHE, and VLLM_CACHE_ROOT to
their /workspace/yeetllm/cache locations for every engine. This prevents an
engine from silently filling the image's smaller ephemeral root filesystem.
During startup, upstream vLLM/download output is prefixed with the engine ID and
sent to container stdout. An additional progress record is emitted every 30
seconds with elapsed time, engine PID, backend probe state, downloaded cache
bytes, and the number of incomplete cache files. The same snapshot appears in
yeetllm status --json.
- Choose the YeetLLM image and require CUDA 13.0 in the template's CUDA filter. Make the GHCR package public or configure matching private-registry credentials in RunPod, and allocate enough container disk for the roughly 9 GB uncompressed runtime image.
- Mount persistent storage at
/workspace. A Pod volume survives stop/start but is deleted with the Pod; a network volume persists independently. - Either put
config.yamlat/workspace/yeetllm/config.yaml, setYEETLLM_CONFIGto another path, or setYEETLLM_CONFIG_URLto fetch it automatically over HTTPS at every container start. - Add only
22/tcpto the template's exposed TCP ports. Do not expose 8000 or any 810x engine port. - Enable RunPod SSH (
startSsh: truewhere that deployment API exposes it) and configure an account public key before starting the Pod. YeetLLM does not depend on undocumentedstartSshruntime behavior; it still requires an actually injected key. - Set
HF_TOKENonly if a configured repository is gated/private. - Keep the image's default entrypoint and command. A RunPod template start
command overrides Docker
CMD, so leave it blank unless intentional.
RunPod's full SSH variables are RUNPOD_PUBLIC_IP and
RUNPOD_TCP_PORT_22. Account keys added after a Pod starts are not guaranteed to
appear until redeploy; inspect container logs for YeetLLM's selected key source.
For a basic one-GPU deployment, register your SSH key once:
runpodctl ssh add-key --key-file "$HOME/.ssh/id_ed25519.pub"Then create the Pod with the development image and the repository's prefilled one-GPU configuration:
runpodctl pod create --name yeetllm --image ghcr.io/returnmoe/yeetllm:development --gpu-id "NVIDIA GeForce RTX 4090" --gpu-count 1 --cloud-type SECURE --min-cuda-version 13.0 --container-disk-in-gb 30 --volume-in-gb 100 --volume-mount-path /workspace --ports 22/tcp --env '{"YEETLLM_CONFIG_URL":"https://raw.githubusercontent.com/returnmoe/yeetllm/development/config.example.yaml"}' --ssh=trueThat is the complete create command: it exposes only SSH, downloads the YAML at
startup, and starts sshd only if RunPod actually injects the registered public
key. Substitute another value from runpodctl gpu list if the prefilled GPU is
unavailable. Open the Pod's Logs pane in the RunPod Console to see the
runtime-generated SSH host public keys and SHA256 fingerprints.
The following more defensive script uses the same runpodctl pod create
interface, fetches the YAML from CONFIG_URL, requests RunPod-managed SSH
setup, exposes only 22/tcp, and also passes the same public key through
SSH_PUBLIC_KEY. No interactive Pod setup or pre-seeded configuration file is
required. The network volume persists model caches and the validated downloaded
configuration.
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
# Required inputs. runpodctl must already be configured with `runpodctl doctor`
# or `runpodctl config --apiKey ...`.
GPU_ID="${GPU_ID:?set GPU_ID to a value from: runpodctl gpu list}"
NETWORK_VOLUME_ID="${NETWORK_VOLUME_ID:?set NETWORK_VOLUME_ID}"
CONFIG_URL="${CONFIG_URL:?set CONFIG_URL to an HTTPS YAML URL}"
# Optional overrides.
GPU_COUNT="${GPU_COUNT:-1}"
IMAGE="${IMAGE:-ghcr.io/returnmoe/yeetllm:development}"
CONFIG_SHA256="${CONFIG_SHA256:-}"
SSH_PUBLIC_KEY_FILE="${SSH_PUBLIC_KEY_FILE:-${HOME}/.ssh/id_ed25519.pub}"
SSH_PRIVATE_KEY_FILE="${SSH_PRIVATE_KEY_FILE:-${SSH_PUBLIC_KEY_FILE%.pub}}"
for required_command in runpodctl jq ssh-keyscan ssh-keygen; do
command -v "${required_command}" >/dev/null || {
echo "${required_command} is required" >&2
exit 1
}
done
# Never print the Pod's env field: it can contain a signed configuration URL or
# HF_TOKEN. This summary includes only connection and scheduling information.
print_pod_summary() {
jq '{
id,
name,
image: (.image // .imageName),
desiredStatus,
runtimeStatus,
gpuCount,
machine,
ssh
}'
}
[[ -s "${SSH_PUBLIC_KEY_FILE}" ]] || {
echo "missing SSH public key: ${SSH_PUBLIC_KEY_FILE}" >&2
exit 1
}
[[ "${SSH_PRIVATE_KEY_FILE}" != "${SSH_PUBLIC_KEY_FILE}" ]] || {
echo "set SSH_PRIVATE_KEY_FILE explicitly when the public-key path has no .pub suffix" >&2
exit 1
}
[[ -s "${SSH_PRIVATE_KEY_FILE}" ]] || {
echo "missing SSH private key: ${SSH_PRIVATE_KEY_FILE}" >&2
exit 1
}
ssh-keygen -l -f "${SSH_PUBLIC_KEY_FILE}" >/dev/null || {
echo "invalid SSH public key: ${SSH_PUBLIC_KEY_FILE}" >&2
exit 1
}
[[ "${CONFIG_URL}" == https://* ]] || {
echo "CONFIG_URL must use HTTPS" >&2
exit 1
}
if [[ -n "${CONFIG_SHA256}" && ! "${CONFIG_SHA256}" =~ ^[[:xdigit:]]{64}$ ]]; then
echo "CONFIG_SHA256 must be a 64-character hexadecimal digest" >&2
exit 1
fi
# Register the public key with the RunPod account before Pod creation. Never
# pass the private-key file here.
runpodctl ssh add-key --key-file "${SSH_PUBLIC_KEY_FILE}"
ssh_public_key="$(<"${SSH_PUBLIC_KEY_FILE}")"
pod_env="$(jq -cn \
--arg ssh_public_key "${ssh_public_key}" \
--arg config_url "${CONFIG_URL}" \
--arg config_sha256 "${CONFIG_SHA256}" \
'{
SSH_PUBLIC_KEY: $ssh_public_key,
YEETLLM_SSH_ENABLE: "true",
YEETLLM_CONFIG_URL: $config_url
} + if $config_sha256 == "" then {} else {
YEETLLM_CONFIG_SHA256: $config_sha256
} end')"
# --ssh=true sets RunPod's startSsh deployment flag. YeetLLM independently
# requires the valid public key above before it starts its own hardened sshd.
pod_json="$(runpodctl pod create \
--name yeetllm-development \
--image "${IMAGE}" \
--gpu-id "${GPU_ID}" \
--gpu-count "${GPU_COUNT}" \
--cloud-type SECURE \
--min-cuda-version 13.0 \
--container-disk-in-gb 30 \
--network-volume-id "${NETWORK_VOLUME_ID}" \
--volume-mount-path /workspace \
--ports '22/tcp' \
--env "${pod_env}" \
--ssh=true \
--output=json)"
printf '%s\n' "${pod_json}" | print_pod_summary
POD_ID="$(jq -er '.id' <<<"${pod_json}")"
# Poll the released CLI until RunPod publishes the SSH mapping and sshd returns
# host keys. A cold pull of the large upstream vLLM image can take several
# minutes. The Pod is intentionally left running if this local wait is aborted.
deadline=$((SECONDS + 1200))
known_hosts="$(mktemp -t yeetllm-known-hosts.XXXXXX)"
while ((SECONDS < deadline)); do
pod_json="$(runpodctl pod get "${POD_ID}" --output=json)"
runtime_status="$(jq -r \
'(.runtimeStatus // .desiredStatus // .ssh.status // "unknown") | ascii_downcase' \
<<<"${pod_json}")"
RUNPOD_PUBLIC_IP="$(jq -r '.ssh.ip // empty' <<<"${pod_json}")"
RUNPOD_TCP_PORT_22="$(jq -r '.ssh.port // empty' <<<"${pod_json}")"
if [[ "${runtime_status}" == "stopped" || "${runtime_status}" == "exited" \
|| "${runtime_status}" == "terminated" ]]; then
printf '%s\n' "${pod_json}" | print_pod_summary >&2
echo "Pod stopped before SSH became ready" >&2
rm -f -- "${known_hosts}"
exit 1
fi
if [[ -n "${RUNPOD_PUBLIC_IP}" && -n "${RUNPOD_TCP_PORT_22}" ]] \
&& ssh-keyscan -T 5 -p "${RUNPOD_TCP_PORT_22}" \
"${RUNPOD_PUBLIC_IP}" >"${known_hosts}" 2>/dev/null \
&& [[ -s "${known_hosts}" ]]; then
break
fi
echo "Waiting for SSH on Pod ${POD_ID} (status: ${runtime_status})..." >&2
sleep 5
done
if [[ ! -s "${known_hosts}" ]]; then
echo "SSH did not become ready within 20 minutes; Pod ${POD_ID} is still allocated" >&2
echo "Inspect it with: runpodctl pod get ${POD_ID}" >&2
rm -f -- "${known_hosts}"
exit 1
fi
printf '%s\n' "${pod_json}" | print_pod_summary
console_url="https://console.runpod.io/pods"
echo
echo "Pod console: ${console_url}"
echo "Open Pod ${POD_ID}, select Logs, and inspect the container log for:"
echo " [sshd] host public key: ..."
echo " [sshd] host fingerprint: ..."
echo
echo "Fingerprints presented by the SSH endpoint (UNTRUSTED until compared):"
ssh-keygen -E sha256 -lf "${known_hosts}"
echo "Known-hosts file: ${known_hosts}"
echo
echo "After verifying that fingerprint, start the tunnel with:"
printf 'ssh -N -i %q -o UserKnownHostsFile=%q ' \
"${SSH_PRIVATE_KEY_FILE}" "${known_hosts}"
printf -- '-o StrictHostKeyChecking=yes '
printf -- '-L 8000:127.0.0.1:8000 -p %q root@%q\n' \
"${RUNPOD_TCP_PORT_22}" "${RUNPOD_PUBLIC_IP}"RunPod currently documents Pod container and system logs as a Console feature;
the current CLI has no supported runpodctl pod logs command. Consequently the
script prints the Pods Console URL and created Pod ID instead of depending on an
undocumented log endpoint. In the Console, expand the Pod, choose Logs,
select the container log, and save/copy it locally if a log dump is required.
The lines to retain are the generated host public keys and their SHA256
fingerprints—never a private key.
To verify the endpoint independently before the first SSH connection, scan its presented public keys and compare these fingerprints byte-for-byte with the Console output:
known_hosts="$(mktemp)"
ssh-keyscan -p "${RUNPOD_TCP_PORT_22}" "${RUNPOD_PUBLIC_IP}" >"${known_hosts}"
ssh-keygen -E sha256 -lf "${known_hosts}"
# Only after the fingerprints match:
ssh -N \
-i "${SSH_PRIVATE_KEY_FILE}" \
-o UserKnownHostsFile="${known_hosts}" \
-o StrictHostKeyChecking=yes \
-L 8000:127.0.0.1:8000 \
-p "${RUNPOD_TCP_PORT_22}" \
root@"${RUNPOD_PUBLIC_IP}"See RunPod's current
runpodctl pod reference,
SSH-key setup, and
Pod log documentation.
Expected listeners on a normal primary Pod:
0.0.0.0:22 sshd (only when a valid key was detected)
127.0.0.1:8000 YeetLLM router
127.0.0.1:8100 vLLM engine
127.0.0.1:8101 vLLM engine, if configured
Check with ss -ltnp. EXPOSE metadata contains port 22 only.
The image sets:
HF_HOME=/workspace/yeetllm/cache/huggingface
HUGGINGFACE_HUB_CACHE=/workspace/yeetllm/cache/huggingface/hub
VLLM_CACHE_ROOT=/workspace/yeetllm/cache/vllm
TRITON_CACHE_DIR=/workspace/yeetllm/cache/vllm/triton-v0.27.0
TORCHINDUCTOR_CACHE_DIR=/workspace/yeetllm/cache/vllm/torchinductor-v0.27.0
Additional persistent locations are /workspace/yeetllm/models and
/workspace/yeetllm/quantized. Restarting against the same volume reuses cached
weights and compiled kernels. trust_remote_code defaults to false and can only
be enabled explicitly per model.
Set quantization: auto (the default) for a repository whose metadata lets vLLM
detect its format, or set an explicit value such as the one documented for the
repository. YeetLLM queries the quantization registry in the installed vLLM
version during validation instead of maintaining a stale independent list. This
supports pre-quantized repositories in formats supported by the installed vLLM,
including the applicable AWQ, GPTQ, BitsAndBytes, FP8, GGUF, compressed-tensors,
and newer registered methods.
YeetLLM does not ship an offline quantizer in this release. Use an official
vLLM/LLM Compressor workflow and persist its output under
/workspace/yeetllm/quantized, then point model at that local directory.
Use the same image and configuration on every node. A RunPod network volume is
recommended because it is mounted at /workspace across the cluster; do not
assume ordinary per-Pod volume disks are shared.
YeetLLM detects and validates the current RunPod cluster contract:
PRIMARY_ADDR == MASTER_ADDR
PRIMARY_PORT == MASTER_PORT
NODE_ADDR
NODE_RANK
NUM_NODES
NUM_TRAINERS
HOST_NODE_ADDR == PRIMARY_ADDR:PRIMARY_PORT
WORLD_SIZE == NUM_NODES * NUM_TRAINERS
It also verifies that NODE_ADDR belongs to ens1, sets
NCCL_SOCKET_IFNAME=ens1, GLOO_SOCKET_IFNAME=ens1, and
VLLM_HOST_IP=NODE_ADDR, and refuses to route distributed traffic over eth0.
Set NCCL_DEBUG=INFO temporarily for diagnostics.
YeetLLM uses vLLM 0.27.0's supported multi-node native multiprocessing flags.
Rank 0 runs the private coordinator, each head engine, the router, and optional
SSH. Other ranks run only vllm serve --headless workers. Rank 0 releases model
startup in configured batches so startup.parallelism: 1 remains sequential
across all nodes. Every engine gets a unique rendezvous port derived from the
RunPod primary port.
This is a control/barrier service, not an inference transport; tensor/pipeline
traffic remains vLLM and NCCL. Ray is not forced. Native MP preserves explicit
per-node physical GPU assignment, whereas current vLLM documents that
--device-ids has no effect with the Ray executor.
Only rank 0 exposes the API or SSH. Do not publish the control, rendezvous, Ray,
8000, or 810x ports. RunPod's private high-bandwidth network must allow the
rendezvous range. See examples/instant-cluster.yaml.
Useful diagnostics:
env | grep -E '^(PRIMARY|MASTER|NODE|NUM_|WORLD_SIZE|HOST_NODE_ADDR)='
ip -br address show dev ens1
ss -ltnp
NCCL_DEBUG=INFO yeetllm serveGlobal fields:
server.hostis deliberately restricted to127.0.0.1; default port 8000.startup.policyis currentlyall;startup.parallelismcontrols how many expensive model loads begin together.allow_shared_gpusdefaults to false.cluster.modeisauto,off, orrunpod; interface defaults toens1.ssh.enableisauto, true, or false.
Per-model fields map closely to current vLLM arguments:
id,model,revision,tokenizer,trust_remote_codegpus,tensor_parallel_size,pipeline_parallel_sizedistributed_executor_backend(autoormp; Ray is rejected because its scheduler does not honor this appliance's physical per-engine GPU mapping)dtype,quantization,max_model_lengpu_memory_utilization,kv_cache_dtypeenvironment, a model-scoped string mapping for runtime tuning such asNCCL_P2P_DISABLE; GPU isolation, cache paths, cluster networking and secrets remain controlled by YeetLLMlora.enabled,max_loras,max_lora_rank,max_cpu_loras,fully_sharded_loras, and staticadaptersextra_args, an argv list for new vLLM options
YeetLLM rejects security/routing/process-owned flags in extra_args, including
host, port, TLS, served name, parallel topology, sleep mode, LoRA mutation, and
cluster rendezvous flags. Other entries are appended verbatim to the argv array.
Set YEETLLM_CONFIG_URL to boot directly from remotely hosted YAML. YeetLLM
downloads at most 1 MiB with bounded connect/read timeouts, permits only HTTPS
(including every redirect), keeps TLS certificate verification enabled, applies
the same safe YAML and schema validation as a local file, and only then
atomically replaces YEETLLM_CONFIG. The default destination remains
/workspace/yeetllm/config.yaml.
YEETLLM_CONFIG_URL=https://example.com/yeetllm/config.yaml
YEETLLM_CONFIG_SHA256=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
YEETLLM_CONFIG_SHA256 is optional and pins the downloaded bytes. Signed HTTPS
URLs are supported, but YeetLLM never prints their query strings. Embedded
https://user:password@... credentials are rejected. A failed fetch, digest
mismatch, or invalid document aborts startup before SSH, the router, or model
preparation; YeetLLM never silently falls back to a stale local file.
Precedence is: an explicit CLI --config path, then YEETLLM_CONFIG_URL, then
the local YEETLLM_CONFIG path. When the URL is used, YEETLLM_CONFIG is its
atomic persistence destination. On Instant Clusters, every node uses the same
URL and the existing configuration-hash check still prevents mismatched engine
startup.
Simple global environment overrides are intentionally limited:
YEETLLM_CONFIG
YEETLLM_CONFIG_URL
YEETLLM_CONFIG_SHA256
YEETLLM_SSH_ENABLE
YEETLLM_SSH_PORT
YEETLLM_SSH_AUTHORIZED_KEYS
HF_TOKEN
See .env.example.
yeetllm serve
yeetllm validate
yeetllm validate --gpu-count 4 # deterministic CI/off-host validation
yeetllm status
yeetllm status --json
yeetllm --versionvalidate performs no model download or load. status reads the atomic runtime
registry/state file and prints base/LoRA-to-engine health mappings.
If an engine exits or its local health endpoint fails, the canonical registry is marked failed immediately, router requests for its IDs receive a structured 503, and global readiness fails. YeetLLM does not enter an automatic restart loop. The router and detected-key SSH service remain available for debugging.
tini is the image init and registers as a child subreaper. It is PID 1 under
ordinary Docker; subreaper mode preserves zombie reaping when RunPod inserts a
platform wrapper above the image entrypoint. The Python supervisor launches
children in separate process groups, prefixes their stdout/stderr, forwards
shutdown, waits a grace period, then terminates stragglers. No systemd is
present.
The Docker health check verifies the supervisor heartbeat/phase, every required engine process, router readiness, and sshd process/configuration when SSH was actually enabled. It never generates tokens.
Use the RunPod CUDA filter matching the selected image. Compare boot diagnostics,
nvidia-smi, and:
python3 -c 'import torch; print(torch.__version__, torch.version.cuda)'Do not casually set VLLM_ENABLE_CUDA_COMPATIBILITY=1; NVIDIA forward
compatibility is limited to specific data-center/professional hardware.
Reduce gpu_memory_utilization, shorten max_model_len, choose a supported
quantized repository, or allocate more GPUs. With multiple resident engines,
confirm their GPU sets do not overlap. Sequential startup reduces host RAM and
download pressure but does not reduce steady-state VRAM.
For one node, TP × PP must equal len(gpus). Across a homogeneous Instant
Cluster, it must equal len(gpus) × NUM_NODES. YeetLLM rejects the mismatch
before weights load.
Choose an allowed max_lora_rank at least as high as every adapter's r and
rank_pattern. Cached/local adapters are checked before their base engine
starts.
Accept the repository license, create a read token, and set HF_TOKEN in the
RunPod secret environment. YeetLLM never prints it. Confirm files can be written
under HF_HOME.
If vLLM reports that the repository requires custom code, inspect that code and
then opt in with trust_remote_code: true for only that model. It is never
enabled automatically.
Verify NODE_ADDR is on ens1, all nodes have the same config and image, the
private rendezvous ports are reachable, and /workspace paths are identical.
Use NCCL_DEBUG=INFO; slow NET/Socket traffic or an eth0 address indicates
the wrong interface.
Logs include node rank, primary address, world size, interface, backend, and per-engine state. Initial coordinator discovery uses the configured startup timeout; after joining, a worker stops its engines after 60 seconds without the coordinator instead of spinning forever. Config hashes must match on every node.
Look for either authorized key detected from ... or SSH remains disabled in
container logs. RunPod account keys should exist before Pod creation. The log's
host-key fingerprints are the values to verify on first connection.
ss -ltnpOnly sshd may listen publicly. Router and engine listeners must show
127.0.0.1.
Build the thin derivative of the pinned official vLLM image:
./docker/build.sh --loadNo vLLM source compilation occurs. The upstream image reference and digest are
in Dockerfile; the small build definition is in
docker-bake.hcl. Pushes to development publish both the
moving development tag and an immutable dev-<commit> tag without creating a
release.
Run local checks with:
python -m pip install -e '.[dev]'
ruff check .
mypy
pytest
shellcheck docker/*.sh tests/docker/*.shGPU integration tests are designed for appropriately labeled self-hosted GitHub runners; normal CI covers schema, command construction, routing, streaming, process control, SSH policy, and image-level configuration.
- vLLM OpenAI-compatible server
- vLLM LoRA serving
- vLLM parallelism and scaling
- vLLM quantization
- vLLM Production Stack
- RunPod SSH
- RunPod exposed ports
- RunPod Instant Cluster configuration
- RunPod storage
YeetLLM does not train or quantize models, train LoRAs, expose public HTTP by default, provide a UI, implement model swapping, or replace vLLM's distributed inference transport. It is deliberately a configuration layer, supervisor, and small routing registry around upstream vLLM.