> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livepeer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Requirements

> GPU support policy, NVENC session limits by card tier, VRAM requirements by AI pipeline, system stack minimums, capacity testing with livepeer_bench, and a pre-launch readiness checklist.

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

export const TableCell = ({children, align = "left", header = false, style = {}, className = "", ...rest}) => {
  const Component = header ? "th" : "td";
  return <Component className={className} style={{
    padding: "0.75rem 1rem",
    textAlign: align,
    border: header ? "none" : "1px solid var(--lp-color-border-default)",
    ...style
  }} {...rest}>
      {children}
    </Component>;
};

export const TableRow = ({children, header = false, hover = false, style = {}, className = "", ...rest}) => {
  const rowId = `table-row-${Math.random().toString(36).substr(2, 9)}`;
  return <>
      {hover && <style>{`
          #${rowId}:hover {
            background-color: var(--lp-color-bg-card);
          }
        `}</style>}
      <tr id={rowId} className={className} style={{
    ...header && ({
      backgroundColor: "var(--lp-color-accent-strong)",
      color: "var(--lp-color-on-accent)",
      fontWeight: "bold"
    }),
    ...style
  }} {...rest}>
        {children}
      </tr>
    </>;
};

export const StyledTable = ({children, variant = "default", style = {}, className = "", ...rest}) => {
  const wrapperVariants = {
    default: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "var(--lp-color-bg-card)",
      overflow: "hidden"
    },
    bordered: {
      border: "2px solid var(--lp-color-accent)",
      backgroundColor: "var(--lp-color-bg-page)",
      overflow: "hidden"
    },
    minimal: {
      border: "none",
      backgroundColor: "transparent",
      overflow: "visible"
    }
  };
  return <div data-docs-styled-table-shell className={className} style={{
    width: "100%",
    padding: 0,
    margin: 0,
    ...wrapperVariants[variant],
    ...style
  }} {...rest}>
      <table data-docs-styled-table style={{
    width: "100%",
    borderCollapse: "collapse",
    borderSpacing: 0,
    margin: 0,
    backgroundColor: "transparent"
  }}>
        {children}
      </table>
    </div>;
};

export const StyledStep = ({title, icon, titleSize = 'h3', iconColor = null, titleColor = null, children, className = '', style = {}, ...rest}) => {
  const styledTitle = titleColor ? <span style={{
    color: titleColor
  }}>{title}</span> : title;
  return <Step title={styledTitle} icon={icon} iconColor={iconColor || undefined} titleSize={titleSize} className={className} style={style} {...rest}>
      {children}
    </Step>;
};

export const StyledSteps = ({children, iconColor, titleColor, lineColor, iconSize = '24px', className = '', style = {}, ...rest}) => {
  const resolvedIconColor = iconColor || 'var(--accent-dark, #18794E)';
  const resolvedTitleColor = titleColor || 'var(--lp-color-accent)';
  const resolvedLineColor = lineColor || 'var(--lp-color-accent)';
  return <div className={['docs-styled-steps', className].filter(Boolean).join(' ')} style={style} {...rest}>
      <style>{`
        .docs-styled-steps .steps > div > div.absolute > div {
          background-color: ${resolvedIconColor};
        }
        .docs-styled-steps .steps > div > div.w-full > p {
          color: ${resolvedTitleColor};
        }
        .docs-styled-steps .steps > div > div.absolute.w-px {
          background-color: ${resolvedLineColor};
        }
        .docs-styled-steps .steps > div:last-child > div.absolute.w-px::after {
          content: '';
          position: absolute;
          bottom: 0;
          left: 50%;
          transform: translateX(-50%);
          width: 6px;
          height: 6px;
          background-color: ${resolvedLineColor};
          transform: translateX(-50%) rotate(45deg);
        }
      `}</style>
      <div>
        <Steps>{children}</Steps>
      </div>
    </div>;
};

export const LinkArrow = ({href, label, description, newline = true, borderColor, className = '', style = {}, ...rest}) => {
  const linkArrowStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: "var(--lp-spacing-1)",
    width: 'fit-content',
    ...borderColor && ({
      borderColor
    })
  };
  return <span className={className} style={style} {...rest}>
      {newline && <br />}
      <span style={linkArrowStyle}>
        <a href={href} target="_blank" rel="noopener noreferrer">
          {label}
        </a>
        <Icon icon="arrow-up-right" size={14} color="var(--lp-color-accent)" />
      </span>
      {description && description}
      {description && <div style={{
    height: "var(--lp-spacing-3)"
  }} />}
    </span>;
};

<CustomDivider />

Use this page as a readiness filter before investing more time in setup. It is here to answer a
simple question: does your machine, network, and system stack actually support the workload path you
want to run on Livepeer?

<CustomDivider />

## GPU Vendor Support

NVIDIA is the supported vendor line for go-livepeer. AMD and Intel
GPUs are not supported for hardware-accelerated transcoding or AI inference, and NVIDIA CUDA is
required for both NVENC video transcoding and AI pipelines.

### Driver requirements

Start here, because every other requirement is irrelevant if the GPU is not visible to the host:

```bash icon="terminal" filename="check-gpu" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
nvidia-smi
# Output shows: driver version, CUDA version, GPU name, memory
# e.g. NVIDIA-SMI 550.54.14    Driver Version: 550.54.14    CUDA Version: 12.4
```

If `nvidia-smi` fails or is missing, install NVIDIA drivers for the target OS before proceeding.
Go-livepeer cannot use the GPU without working NVIDIA drivers.

**Minimum CUDA version:** 12.0. Earlier versions are not supported by the AI Runner containers.

<CustomDivider />

## NVENC/NVDEC Session Limits

NVIDIA consumer GPUs enforce **concurrent encoding session limits** via NVENC (hardware video
encoder) and NVDEC (hardware video decoder). For many video-first operators, this is the first hard
capacity ceiling that matters.

<Warning>
  Consumer NVIDIA cards (GeForce RTX series) are capped at a small number of concurrent NVENC sessions
  by default. Data centre cards (A-series, L-series, H-series) have no such cap.
</Warning>

Consumer cards are typically limited to **2-3 concurrent NVENC encode sessions** before throttling
or failing with `NvEncOpenEncodeSessionEx` errors. This is a hardware-enforced licensing restriction,
not a software limitation in go-livepeer.

Check the official NVIDIA matrix for exact limits per generation:

**[developer.NVIDIA.com/video-encode-decode-GPU-support-matrix](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix)**

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>GPU tier</TableCell>
      <TableCell header>NVENC session cap</TableCell>
      <TableCell header>Notes</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**GeForce RTX (consumer)**</TableCell>
      <TableCell>2-3 concurrent sessions</TableCell>
      <TableCell>Hardware licensing cap; check matrix for exact figure per generation</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**RTX Workstation / Quadro**</TableCell>
      <TableCell>Uncapped</TableCell>
      <TableCell>Commercial hardware, no artificial limit</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**NVIDIA A-series (A100, A4000, A5000)**</TableCell>
      <TableCell>Uncapped</TableCell>
      <TableCell>Data centre; full concurrent session headroom</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**NVIDIA L-series (L4, L40)**</TableCell>
      <TableCell>Uncapped</TableCell>
      <TableCell>Data centre</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**NVIDIA H-series (H100)**</TableCell>
      <TableCell>Uncapped</TableCell>
      <TableCell>Data centre; highest throughput tier</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

Exact session counts can vary by GPU generation and NVIDIA policy. Treat the NVIDIA matrix as the
source of truth and the table below as a planning shortcut. For most consumer-card operators, this
cap is the binding limit until benchmarking proves otherwise.

<CustomDivider />

## Hardware Tiers by Workload

### Video transcoding

Video transcoding is primarily a throughput problem. You care about encoder sessions, sustained
throughput, and stability far more than you care about large VRAM pools.

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Hardware tier</TableCell>
      <TableCell header>Example GPUs</TableCell>
      <TableCell header>Transcoding suitability</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**Consumer (NVENC-capped)**</TableCell>
      <TableCell>RTX 3060, 3070, 3080, 4070, 4080, 4090</TableCell>
      <TableCell>2-3 concurrent sessions (NVENC hardware cap). Verify in NVIDIA matrix.</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Data centre / workstation**</TableCell>
      <TableCell>A4000, A5000, RTX 6000, L4</TableCell>
      <TableCell>Uncapped - 10-20+ concurrent sessions depending on compute</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**High-end data centre**</TableCell>
      <TableCell>A100, H100</TableCell>
      <TableCell>Uncapped - maximum concurrent session headroom</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

**CPU transcoding:** Possible without a GPU, but throughput is significantly lower. Practical
capacity is low single-digit concurrent sessions, varies heavily by CPU generation and codec mix.
Not competitive at scale.

### Batch AI inference

AI inference flips the constraint. The first question is whether the model fits in memory at all.
Full pipeline-by-pipeline VRAM figures are in
<LinkArrow href="/v2/orchestrators/guides/ai-and-job-workloads/model-demand-reference" label="Models and VRAM Reference" newline={false} />.

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>VRAM tier</TableCell>
      <TableCell header>GPU examples</TableCell>
      <TableCell header>Pipelines available</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**8-12 GB**</TableCell>
      <TableCell>RTX 3060 12GB, RTX 3060 Ti 8GB, RTX 2060 Super 8GB</TableCell>
      <TableCell>`audio-to-text` (Whisper), `image-to-text` (BLIP), `segment-anything-2` (base), small LLMs via Ollama</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**24 GB**</TableCell>
      <TableCell>RTX 3090, RTX 4090, A5000</TableCell>
      <TableCell>All diffusion pipelines (`text-to-image`, `image-to-image`, `image-to-video`, `upscale`); full model access</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**40-80 GB**</TableCell>
      <TableCell>A100 40GB, A100 80GB, H100</TableCell>
      <TableCell>Multiple large models simultaneously; highest-throughput AI operation</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

### Cascade AI inference

Cascade video AI is a latency problem before it is a raw-throughput problem, so the hardware
requirements are stricter than they are for batch AI:

* **Minimum VRAM:** 12-16 GB (StreamDiffusion with SD 1.5)
* **Competitive VRAM:** 24 GB (StreamDiffusion with SDXL)
* **Frame buffer overhead:** add 1-2 GB on top of the model's base VRAM footprint
* **Additional requirements:** fast PCIe bandwidth; low-latency memory

Cascade pipelines require models warm at all times. A cold start during an active stream causes
visible interruption. See <LinkArrow href="/v2/orchestrators/guides/ai-and-job-workloads/realtime-ai-setup" label="Realtime AI Setup" newline={false} /> for full runtime requirements.

<CustomDivider />

## System Requirements

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Component</TableCell>
      <TableCell header>Minimum</TableCell>
      <TableCell header>Recommended</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**CPU**</TableCell>
      <TableCell>4 cores</TableCell>
      <TableCell>8-16 cores</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**RAM**</TableCell>
      <TableCell>16 GB</TableCell>
      <TableCell>32-64 GB</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Storage**</TableCell>
      <TableCell>100 GB SSD</TableCell>
      <TableCell>1 TB NVMe SSD (more for AI model weights)</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Network**</TableCell>
      <TableCell>100 Mbps symmetric</TableCell>
      <TableCell>1 Gbps symmetric</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**OS**</TableCell>
      <TableCell>Ubuntu 22.04 LTS</TableCell>
      <TableCell>Ubuntu 22.04 or 24.04 LTS</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**CUDA**</TableCell>
      <TableCell>12.0</TableCell>
      <TableCell>12.4+</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Docker**</TableCell>
      <TableCell>Required for AI Runner</TableCell>
      <TableCell>Required for AI Runner</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**NVIDIA Container Toolkit**</TableCell>
      <TableCell>Required for AI Runner</TableCell>
      <TableCell>Required for AI Runner</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

**Storage note:** A single SDXL model is approximately 7-8 GB. Running multiple pipelines requires
fast NVMe storage to load models without latency spikes. Budget at least 100 GB per 4-5 models
served simultaneously.

**Network note:** Latency to Gateways matters more than raw throughput for AI jobs. A 100 Mbps
connection with sub-20ms latency to major regions outperforms a 1 Gbps connection with high
latency for Cascade AI workloads.

<CustomDivider />

## Testing Your Capacity

Do not set `-maxSessions` from guesswork or marketing specs. Run `livepeer_bench` to find the GPU's
actual concurrent transcoding ceiling after hardware is confirmed and before activation.

`livepeer_bench` ships with go-livepeer. Verify it is on PATH:

```bash icon="terminal" filename="livepeer-bench-help" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer_bench -help
```

**Step 1 - Download the test stream:**

```bash icon="terminal" filename="download-test-stream" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget -c https://storage.googleapis.com/lp_testharness_assets/bbb_1080p_30fps_1min_2sec_hls.tar.gz
tar -xvf bbb_1080p_30fps_1min_2sec_hls.tar.gz
```

**Step 2 - Run the scaling test:**

```bash icon="code" title="bench-scale.sh" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
for i in {1..20}
do
    livepeer_bench \
        -in bbb/source.m3u8 \
        -nvidia 0 \
        -concurrentSessions $i |& grep "Duration Ratio" >> bench.log
done
```

This appends one result line per session count to `bench.log`. Increase the range to `{1..40}`
if the ratio is still below 1.0 at 20 sessions.

**Step 3 - Read the result:**

The **Duration Ratio** is total transcoding time divided by total source duration.

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Ratio</TableCell>
      <TableCell header>Meaning</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**\< 1.0**</TableCell>
      <TableCell>Transcoding faster than source duration - headroom available</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**= 1.0**</TableCell>
      <TableCell>Matches source duration - no headroom; any spike causes lag</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**> 1.0**</TableCell>
      <TableCell>Slower than source duration - overloaded at this session count</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

The last concurrent session count at which ratio ≤ 0.8 is the practical **hardware limit** many
operators use. That threshold keeps some headroom for upload/download overhead and short spikes.

Take this number to <LinkArrow href="/v2/orchestrators/setup/configure" label="Configure" newline={false} /> and set it as the input for the `-maxSessions` calculation.

<CustomDivider />

## Checklist Before Going Live

Activate only after the checklist below passes. It covers the basics that fail first most often.

<StyledSteps>
  <StyledStep title="Verify GPU is visible">
    ```bash icon="terminal" filename="verify-nvidia-smi" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    nvidia-smi
    # Should output: GPU name, driver version, CUDA version, memory used/total
    # If this fails: drivers are not installed correctly
    ```
  </StyledStep>

  <StyledStep title="Verify Docker can access the GPU">
    ```bash icon="terminal" filename="verify-docker-gpu" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi
    # Should output the same as nvidia-smi above
    # If this fails: NVIDIA Container Toolkit is not installed or configured
    ```
  </StyledStep>

  <StyledStep title="Install NVIDIA Container Toolkit if needed">
    ```bash icon="terminal" filename="install-nvidia-container-toolkit" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    # Ubuntu 22.04 / 24.04
    curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
      sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
    curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
      sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
      sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
    sudo nvidia-ctk runtime configure --runtime=docker
    sudo systemctl restart docker
    ```

    See the [NVIDIA Container Toolkit install guide](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) for other distributions.
  </StyledStep>

  <StyledStep title="Confirm required ports are open">
    ```bash icon="terminal" filename="check-firewall" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    # 8935 - Orchestrator RPC (must be reachable from the internet)
    # 7935 - CLI HTTP interface (localhost only)
    sudo ufw status
    ```

    Port 8935 must be reachable from the internet. If behind NAT, configure port forwarding.
  </StyledStep>

  <StyledStep title="Confirm Arbitrum RPC access">
    ```bash icon="terminal" filename="check-arbitrum-rpc" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    curl -s https://arb1.arbitrum.io/rpc \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | python3 -m json.tool
    ```

    For production, use a dedicated RPC endpoint via Alchemy, Infura, or QuickNode. Treat the
    public endpoint as a quick validation target.
  </StyledStep>

  <StyledStep title="Check static IP or DDNS">
    The `serviceAddr` must be stable. Home connections with dynamic IPs need DDNS or a static
    IP via the ISP. Changing IP without updating `serviceAddr` causes Gateways to lose contact.
  </StyledStep>

  <StyledStep title="Run the capacity test">
    Run the `livepeer_bench` scaling test above to find the hardware session limit. Record the
    number - it is required for the `-maxSessions` calculation in Configure.
  </StyledStep>

  <StyledStep title="Confirm ETH balance on Arbitrum">
    The Orchestrator wallet needs ETH on Arbitrum One before activation. Budget at least 0.01 ETH
    for the activation transaction and initial reward calls. See
    <LinkArrow href="/v2/orchestrators/guides/payments-and-pricing/payment-receipts" label="Payments" newline={false} /> for ongoing ETH requirements.
  </StyledStep>
</StyledSteps>

<CustomDivider />

## Related Pages

<CardGroup cols={2}>
  <Card title="Configure" icon="sliders" href="/v2/orchestrators/setup/configure" arrow horizontal>
    Set `-maxSessions`, `-pricePerUnit`, `-nvidia`, and all other go-livepeer flags before activation.
  </Card>

  <Card title="Models and VRAM Reference" icon="memory" href="/v2/orchestrators/guides/ai-and-job-workloads/model-demand-reference" arrow horizontal>
    Full VRAM table by AI pipeline and model, warm strategy, and multi-GPU configuration.
  </Card>

  <Card title="Alternate Deployments" icon="diagram-project" href="/v2/orchestrators/guides/deployment-details/setup-options" arrow horizontal>
    Pool worker, O-T split, and Siphon - the alternatives to the combined single-machine setup.
  </Card>

  <Card title="Operating Rationale" icon="scale-balanced" href="/v2/orchestrators/guides/operator-considerations/operator-rationale" arrow horizontal>
    Cost and revenue breakdown before committing hardware.
  </Card>
</CardGroup>
