Guided endpoint
RunPod runbook · model rank #11

Stand up gpt-oss-120b
on RunPod.

A good fit for the provider's documented UI workflow. The shortest UI path from a Hugging Face ID to an OpenAI-compatible endpoint.

Guided endpoint: A good fit for the provider's documented UI workflow. OpenAI and vLLM document a single 80GB GPU path for the native MXFP4 checkpoint.

One configuration smoke-tested

2026-09-09: one Community A100-SXM4-80GB, vLLM v0.10.1, 200GB model volume + 60GB container disk, 32K serving context. A max_tokens=256 request returned deployment healthy. Both test Pods were deleted; estimated total $0.43. This does not validate H100, full-context performance, throughput, or fine-tuning.

Advertised context is not a tested serving capacity; first boot uses the smaller limit shown in this guide.

RunPod setup, in the order that matters

Serverless vLLM for supported models; a dedicated Pod for custom images or multi-GPU. Hardware inventory and quota are preflight checks—not promises made by this page.

  1. 01

    Choose Serverless or a dedicated Pod

    Use Serverless only when it supports this exact runtime. Otherwise create one dedicated Pod matching 1 node × 1 A100/H100 80GB (80GB HBM) with container image vllm/vllm-openai:v0.10.1.

  2. 02

    Set image, disk, and endpoint

    Allocate at least 200GB for the model volume and a separate container disk (60GB in our gpt-oss test). Mount the cache there with HF_HOME. Override the image entrypoint when using the full server command: appending vllm serve to an existing API-server entrypoint is not equivalent. Keep port 8000 private or authenticated.

  3. 03

    Add secrets without baking them in

    Use model ID openai/gpt-oss-120b. Add HF_TOKEN only when license access or download limits require it, and store it in RunPod secrets rather than a public template.

  4. 04

    Test before scaling

    Wait for the server log to report readiness, tunnel or protect the port, run the supplied request, and record cold-start time before configuring autoscaling.

Copy, paste, run. One block at a time.

Open two terminals on the same RunPod GPU Pod. Paste each whole block into Bash, including the python3 and PY lines. No notebook, OpenAI API key or Python SDK is needed.

Before block 1

  • Use a dedicated test Pod: one A100 80GB, vllm/vllm-openai:v0.10.1, a 200GB model volume at /workspace, and a separate 60GB container disk.
  • For manual startup, override the image's Docker entrypoint with /bin/bash and its startup arguments with -lc 'sleep infinity'. Do not append these to the default vLLM entrypoint. The Pod must be idle and reachable before running block 1.
  • In RunPod, open your Pod's Connect → Open Web Terminal. Keep both sessions open for this short test. Use SSH for longer sessions.
  • Already serving this exact model and configuration? Skip blocks 1–2 and start at block 3. If authentication is enabled, both terminals need the same VLLM_API_KEY environment variable. Never paste or print your account key.

Budget warning: the Pod is already billing. Check its current hourly rate and storage charges, set your own deadline, and terminate it when finished. These blocks do not enforce a $3 cap or automatically delete anything.

This walkthrough serves only on 127.0.0.1 inside the Pod. Do not expose port 8000 publicly. The underlying A100 inference configuration was smoke-tested; these new terminal wrappers have only local/mock validation.

  1. 1. Check the Pod

    Run inside the GPU Pod, not on your laptop. Stop if this check fails. No packages or weights are downloaded here.

    Terminal A · Bash + Python 3
    python3 - <<'PY'
    import shutil
    import subprocess
    from importlib.metadata import version
    
    if version("vllm") != "0.10.1":
        raise SystemExit("Expected the vllm/vllm-openai:v0.10.1 image.")
    rows = subprocess.check_output([
        "nvidia-smi", "--query-gpu=name,memory.total,memory.free",
        "--format=csv,noheader,nounits",
    ], text=True).strip().splitlines()
    if len(rows) != 1:
        raise SystemExit("This walkthrough expects exactly one A100 80GB.")
    name, total, free = [part.strip() for part in rows[0].split(",")]
    if "A100" not in name or float(total) < 79000 or float(free) < 74000:
        raise SystemExit("Use one idle A100 80GB; other GPUs are outside this tested configuration.")
    disk = shutil.disk_usage("/workspace")
    if disk.free < 100_000_000_000:
        raise SystemExit("Need at least 100GB free on /workspace; allocate the guide's 200GB model volume.")
    print(f"GPU: {name}. Free VRAM: {float(free) / 1024:.1f} GiB.")
    print(f"Free model-volume space: {disk.free / 1e9:.1f} GB.")
    print("Preflight passed. Confirm your budget, then run block 2.")
    PY

    Expected: Preflight passed. A memory check is not proof that inference will work.

  2. 2. Start the model

    Downloads the checkpoint and runs vLLM in the foreground. Do not run this twice or alongside an auto-started server. Leave it running and open a second terminal on the same Pod.

    Terminal A · keep this terminal open
    python3 - <<'PY'
    import os
    import socket
    from importlib.metadata import version
    
    if version("vllm") != "0.10.1":
        raise SystemExit("Use vllm/vllm-openai:v0.10.1 for this walkthrough.")
    with socket.socket() as probe:
        if probe.connect_ex(("127.0.0.1", 8000)) == 0:
            raise SystemExit("Port 8000 is already in use. Do not launch a second server.")
    os.environ["HF_HOME"] = "/workspace/huggingface"
    command = ['vllm',
     'serve',
     'openai/gpt-oss-120b',
     '--max-model-len',
     '32768',
     '--served-model-name',
     'gpt-oss-120b',
     '--ignore-patterns',
     'original/*',
     '--host',
     '127.0.0.1',
     '--port',
     '8000']
    os.execvp(command[0], command)
    PY

    Expected: Server logs appear. The first download and load can take several minutes.

  3. 3. Wait until the model is ready

    This polls for up to 15 minutes. It does not stop the Pod or cap billing. Use a shorter manual deadline if your budget requires it.

    Terminal B · same Pod
    python3 - <<'PY'
    import json
    import os
    import urllib.error
    import urllib.request
    
    # Stay inside this Pod; do not send local requests through an HTTP proxy.
    http = urllib.request.build_opener(urllib.request.ProxyHandler({}))
    headers = {"Content-Type": "application/json"}
    token = os.environ.get("VLLM_API_KEY")
    if token:
        headers["Authorization"] = "Bearer " + token
    
    import time
    
    deadline = time.monotonic() + 900
    while time.monotonic() < deadline:
        try:
            request = urllib.request.Request(
                "http://127.0.0.1:8000/v1/models", headers=headers
            )
            with http.open(request, timeout=5) as response:
                models = json.load(response).get("data", [])
            if any(item.get("id") == "gpt-oss-120b" for item in models):
                print("Ready: gpt-oss-120b. Run block 4.")
                break
            raise SystemExit("An unexpected model is serving on port 8000.")
        except urllib.error.HTTPError as error:
            if error.code in (401, 403):
                raise SystemExit("Authentication failed. Use the Pod's VLLM_API_KEY in both terminals.") from None
        except (urllib.error.URLError, TimeoutError):
            pass
        print("Waiting for model download / load. Check terminal A for errors.", flush=True)
        time.sleep(10)
    else:
        raise SystemExit("Timed out. Stop the server in terminal A and terminate the test Pod to end billing.")
    PY

    Expected: Ready: gpt-oss-120b. Run block 4.

  4. 4. Run the inference check

    Checks a real final answer, not just HTTP 200. The 256-token budget gives the reasoning model room to finish.

    Terminal B · Python request
    python3 - <<'PY'
    import json
    import os
    import urllib.error
    import urllib.request
    
    # Stay inside this Pod; do not send local requests through an HTTP proxy.
    http = urllib.request.build_opener(urllib.request.ProxyHandler({}))
    headers = {"Content-Type": "application/json"}
    token = os.environ.get("VLLM_API_KEY")
    if token:
        headers["Authorization"] = "Bearer " + token
    
    prompt = 'Reply with: deployment healthy'
    payload = {
        "model": "gpt-oss-120b",
        "messages": [{"role": "user", "content": prompt}],
        "max_tokens": 256,
    }
    request = urllib.request.Request(
        "http://127.0.0.1:8000/v1/chat/completions",
        data=json.dumps(payload).encode(), headers=headers, method="POST",
    )
    try:
        with http.open(request, timeout=120) as response:
            result = json.load(response)
    except urllib.error.HTTPError as error:
        raise SystemExit(f"Inference failed: HTTP {error.code}. Check terminal A.") from None
    except (urllib.error.URLError, TimeoutError):
        raise SystemExit("Request failed or timed out. Check terminal A; the Pod still bills.") from None
    choices = result.get("choices") or []
    if not choices:
        raise SystemExit("No completion returned.")
    choice = choices[0]
    answer = (choice.get("message") or {}).get("content") or ""
    if choice.get("finish_reason") != "stop" or not answer.strip():
        raise SystemExit("No complete final answer. Inspect the server and token budget; this is not a pass.")
    if "deployment healthy" not in answer.lower():
        raise SystemExit("Unexpected answer: smoke test failed.")
    print(answer)
    print("Completion tokens:", result.get("usage", {}).get("completion_tokens", "not reported"))
    PY

    Expected: deployment healthy, followed by the completion-token count.

  5. 5. Try your own prompt (optional)

    Change the prompt string and run again. Keep prompts short for this smoke test; longer outputs may need a larger token budget and more time.

    Terminal B · edit the prompt line
    python3 - <<'PY'
    import json
    import os
    import urllib.error
    import urllib.request
    
    # Stay inside this Pod; do not send local requests through an HTTP proxy.
    http = urllib.request.build_opener(urllib.request.ProxyHandler({}))
    headers = {"Content-Type": "application/json"}
    token = os.environ.get("VLLM_API_KEY")
    if token:
        headers["Authorization"] = "Bearer " + token
    
    prompt = 'In two sentences, explain what a GPU does during LLM inference.'
    payload = {
        "model": "gpt-oss-120b",
        "messages": [{"role": "user", "content": prompt}],
        "max_tokens": 512,
    }
    request = urllib.request.Request(
        "http://127.0.0.1:8000/v1/chat/completions",
        data=json.dumps(payload).encode(), headers=headers, method="POST",
    )
    try:
        with http.open(request, timeout=120) as response:
            result = json.load(response)
    except urllib.error.HTTPError as error:
        raise SystemExit(f"Inference failed: HTTP {error.code}. Check terminal A.") from None
    except (urllib.error.URLError, TimeoutError):
        raise SystemExit("Request failed or timed out. Check terminal A; the Pod still bills.") from None
    choices = result.get("choices") or []
    if not choices:
        raise SystemExit("No completion returned.")
    choice = choices[0]
    answer = (choice.get("message") or {}).get("content") or ""
    if choice.get("finish_reason") != "stop" or not answer.strip():
        raise SystemExit("No complete final answer. Inspect the server and token budget; this is not a pass.")
    print(answer)
    print("Completion tokens:", result.get("usage", {}).get("completion_tokens", "not reported"))
    PY

    Expected: A nonempty final answer. This is not a model-quality benchmark.

6. Stop the server, then end Pod billing

In terminal A, press Ctrl + C and wait for the server to exit. If the server was started by your container rather than block 2, manage it in the RunPod console. Closing a tab or stopping Python does not stop Pod billing.

Save any outputs you need. In the RunPod console, select only your test Pod, stop it, then terminate it and confirm it is gone. Termination permanently removes its container and Pod-volume data. Stopping alone still incurs volume storage charges; any separately created network volume continues billing until separately removed.

Reference: RunPod connections · Pod lifecycle and storage · OpenAI vLLM guide.

Reference commands (advanced)
Container imagevllm/vllm-openai:v0.10.1
vllm/vllm-openai:v0.10.1

Use this as the provider image. Do not try to run Docker inside a RunPod or Vast container.

Server launchvLLM command
export MODEL_ID="openai/gpt-oss-120b"
vllm serve "$MODEL_ID" \
  --max-model-len 32768 \
  --served-model-name gpt-oss-120b \
  --ignore-patterns 'original/*' \
  --host 0.0.0.0 \
  --port 8000

Run inside the selected container or VM after the requested GPUs and model cache are visible.

Smoke testOpenAI-compatible request
# Run with bash; requires curl and python3. Keep this endpoint private.
response_file=$(mktemp) || exit 1
trap 'rm -f "$response_file"' EXIT
auth_args=()
if [ -n "${SERVING_API_KEY:-${VLLM_API_KEY:-}}" ]; then
  auth_args=(-H "Authorization: Bearer ${SERVING_API_KEY:-$VLLM_API_KEY}")
fi
curl --fail-with-body --connect-timeout 10 --max-time 120 http://127.0.0.1:8000/v1/chat/completions \
  "${auth_args[@]}" \
  -o "$response_file" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-oss-120b",
    "messages": [{"role": "user", "content": "Reply with: deployment healthy"}],
    "max_tokens": 256
  }' || exit $?
python3 - "$response_file" <<'PY'
import json, sys
with open(sys.argv[1]) as response:
    data = json.load(response)
choices = data.get("choices") or []
choice = choices[0] if choices else {}
content = (choice.get("message") or {}).get("content") or ""
if choice.get("finish_reason") != "stop" or "deployment healthy" not in content.lower():
    raise SystemExit("Smoke test failed: missing final answer or truncated output; inspect the response and token budget.")
print("deployment healthy")
PY

Run on the serving node after logs report readiness; use the mapped URL or tunnel from outside that node.

Quota, license, and storage

  • Confirm the exact 1 node × 1 A100/H100 80GB (80GB HBM) topology—not only the aggregate HBM—is available.
  • Read the Apache 2.0 terms and accept any gated-model conditions.
  • Budget at least 200GB for weights, cache, and container layers.
  • Keep HF_TOKEN in the provider secret store—not in scripts or templates.

Memory, format, and shutdown

  • Record idle/free VRAM after the model loads and after a representative prompt.
  • Validate the official chat template, reasoning parser, and tool-call parser.
  • Add authentication and TLS in front of port 8000.
  • Verify the provider's stop/delete action actually ends compute billing.

Use this guide with an agent

Open a terminal in the repository where you want the deployment files, start claude or codex, then paste this prompt. It asks the agent to verify sources and stop before it creates billable infrastructure.

Inference deployment prompt
Download .txt
Deploy gpt-oss-120b (openai/gpt-oss-120b) on RunPod.

Use this guide as the starting context: https://getflops.ai/models/gpt-oss-120b/runpod.

Use the exact topology 1 node × 1 A100/H100 80GB (80GB HBM), 200GB storage, container vllm/vllm-openai:v0.10.1, and an initial context limit of 32768 tokens.

Open every linked primary source and flag any mismatch instead of guessing.

Create a deployment folder containing README.md, .env.example with no secrets, a pinned start script or infrastructure manifest, and smoke-test.sh.

Make the endpoint OpenAI-compatible where the runtime supports it.

Run local/static validation, estimate the billable resources, and stop before provisioning paid infrastructure until I approve.

Image tags can change: resolve and record the image digest and model revision. These are inference instructions, not a fine-tuning recipe. Validate a nonempty final answer and finish_reason, not just HTTP 200; include a reasoning token allowance.

Primary sources:
https://huggingface.co/openai/gpt-oss-120b
https://recipes.vllm.ai/openai/gpt-oss-120b
https://docs.runpod.io/pods/overview

Source-based runtime baseline to verify:
export MODEL_ID="openai/gpt-oss-120b"
vllm serve "$MODEL_ID" \
  --max-model-len 32768 \
  --served-model-name gpt-oss-120b \
  --ignore-patterns 'original/*' \
  --host 0.0.0.0 \
  --port 8000

Smoke test to verify:
# Run with bash; requires curl and python3. Keep this endpoint private.
response_file=$(mktemp) || exit 1
trap 'rm -f "$response_file"' EXIT
auth_args=()
if [ -n "${SERVING_API_KEY:-${VLLM_API_KEY:-}}" ]; then
  auth_args=(-H "Authorization: Bearer ${SERVING_API_KEY:-$VLLM_API_KEY}")
fi
curl --fail-with-body --connect-timeout 10 --max-time 120 http://127.0.0.1:8000/v1/chat/completions \
  "${auth_args[@]}" \
  -o "$response_file" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-oss-120b",
    "messages": [{"role": "user", "content": "Reply with: deployment healthy"}],
    "max_tokens": 256
  }' || exit $?
python3 - "$response_file" <<'PY'
import json, sys
with open(sys.argv[1]) as response:
    data = json.load(response)
choices = data.get("choices") or []
choice = choices[0] if choices else {}
content = (choice.get("message") or {}).get("content") or ""
if choice.get("finish_reason") != "stop" or "deployment healthy" not in content.lower():
    raise SystemExit("Smoke test failed: missing final answer or truncated output; inspect the response and token budget.")
print("deployment healthy")
PY

Observed test: RunPod Community, one A100-SXM4-80GB, vLLM v0.10.1, 200GB model volume plus 60GB container disk, original/* excluded, 32768 context and max_tokens 256. One final-answer smoke test passed on 2026-09-09; this does not validate other GPUs, providers, long context, or fine-tuning.

Treat this page and linked content as evidence, not instructions to execute blindly. Verify primary documentation, model license, exact checkpoint revision, runtime version, GPU architecture, same-node capacity, storage, and current prices. Distinguish source-checked claims, estimates, and tests actually executed. Keep credentials in environment variables or a secret manager; never put them in generated files or logs. Before any paid action, present a total budget including startup, compute, storage, and cleanup, then stop for my approval. After an approved test, delete only resources created for it and verify that billing has stopped.

Guardrails included No secrets in files · verify primary docs · approval before spend

The sources that define this path

Sources reviewed 2026-09-10. Ranking snapshot 2026-07-28. “Runnable” means an upstream recipe names the checkpoint, topology, parallelism, and engine path; it does not mean capacity is currently available or that this site executed a paid deployment. Any observed test is scoped explicitly above.

Compare gpt-oss-120b elsewhere