Ga naar inhoud

Installeren van NVIDIA GPU-drivers en CUDA op Ubuntu Linux en Alma/Rocky Linux

In dit artikel

We raden aan om NVIDIA-kaarten alleen te gebruiken op LTS-versies van Ubuntu 22.04/24.04/26.04. Om drivers te installeren op andere distributies, kunt u ons script voor CentOS-gebaseerde RPM-distributies gebruiken of de officiële instructies van de ontwikkelaar volgen:

Let op

Voor een correcte werking van Tesla-serie GPU's (bijv. NVIDIA Tesla T4), zorg ervoor dat de parameter 'above 4G decoding', 'large/64bit BARs' of 'Above 4G MMIO BIOS assignment' is ingeschakeld in het BIOS van de server.

Open de serverconsole (via de native console of SSH), log in als root, kopieer het onderstaande script, plak het in de command line en druk op Enter om de drivers en CUDA automatisch te installeren. Als u docker of docker compose nodig heeft voor uw software, installeer dit dan VOOR de installatie van de drivers, zodat het script de GPU-ondersteuning kan "doorgeven" aan de containers.

Opmerking

Als u een command-line shell gebruikt die niet bash is (bijv. zsh of een andere), schakel dan over naar bash om het script uit te voeren door exec bash uit te voeren.

Let op

Tijdens de installatie moet u mogelijk op Enter drukken om de installatie van nieuwe kernelmodules of het herstarten van services te bevestigen.

Installatiescript voor Ubuntu Linux

#!/bin/bash
#===============================================================================
# Universal NVIDIA Driver + CUDA Installer for Ubuntu 22.04/24.04/26.04 LTS
# - Legacy GPUs (CC < 7.5): pinned driver + CUDA 12.9 (last branch supporting Pascal/Volta)
# - Blackwell GPUs: open kernel modules + latest CUDA
# - All other GPUs (incl. RTX A5000, CC 8.6): proprietary driver 580 + latest CUDA
# - cuda-drivers meta-package is NEVER installed (avoids pulling open modules)
#===============================================================================
set -euo pipefail

#-------------------------------------------------------------------------------
# CONFIGURATION FLAGS
#-------------------------------------------------------------------------------
DO_OS_POLICY_CHECK=1
ALLOWED_UBUNTU_VERSIONS=("22.04" "24.04" "26.04")

DO_APT_UPGRADE=1
DO_INSTALL_HWE=1
DO_INSTALL_KERNEL_HEADERS=1
DO_INSTALL_BUILD_TOOLS=1

DO_PURGE_OLD_PACKAGES=1
DO_SETUP_CUDA_REPO=1
DO_INSTALL_CUDA_STACK=1

# Legacy GPUs: pinned driver per card (CC < 7.5, CUDA 12.x only)
LEGACY_GPUS=(
  "10de:1b06|GeForce GTX 1080 Ti|nvidia-driver-535"
  "10de:1db1|Tesla V100|nvidia-driver-535"
  "10de:1b80|GeForce GTX 1070|nvidia-driver-535"
  "10de:1c03|GeForce GTX 1060|nvidia-driver-535"
)

# Blackwell GPUs: require open kernel modules
BLACKWELL_GPUS=(
  "10de:2b85|GeForce RTX 5090"
  "10de:2b87|GeForce RTX 5090 D"
  "10de:2b84|GeForce RTX 5080"
  "10de:2b83|GeForce RTX 5070 Ti"
  "10de:2b82|GeForce RTX 5070"
  "10de:2f80|GeForce RTX 5070 Laptop GPU"
  "10de:2bb5|RTX PRO 6000 Blackwell Server Edition"
  "10de:2bb4|RTX PRO 6000 Blackwell Workstation Edition"
  "10de:2bb1|RTX PRO 6000 Blackwell Max-Q"
  "10de:2bb3|RTX PRO 5000 Blackwell"
  "10de:2c31|RTX PRO 4500 Blackwell"
  "10de:2c37|RTX PRO 4000 Blackwell"
  "10de:2c36|RTX PRO 3000 Blackwell"
  "10de:2d30|RTX PRO 2000 Blackwell"
  "10de:2c35|RTX PRO 2000 Blackwell (Alternative)"
  "10de:2c3a|RTX PRO 4500 Blackwell Server Edition"
  "10de:2c77|RTX PRO 5000 Blackwell Embedded GPU"
  "10de:2c38|RTX PRO 5000 Blackwell Generation Laptop GPU"
  "10de:2f38|RTX PRO 3000 Blackwell Generation Laptop GPU"
  "10de:2db8|RTX PRO 1000 Blackwell Generation Laptop GPU"
)

DO_BLACKLIST_NOUVEAU=1
DO_TRY_RMMOD_NOUVEAU=1
DO_USER_GROUPS=0
DO_BASHRC_CUDA_PATHS=1
DO_VERIFY_NVIDIA_SMI=1
DO_VERIFY_NVCC=1
DO_INSTALL_NVIDIA_CONTAINER_TOOLKIT=1
DO_CONFIGURE_DOCKER_RUNTIME=1
DO_RESTART_DOCKER=1

# ---- Start ----
echo "Starting NVIDIA driver + CUDA installation (Non-Interactive)..."

#-------------------------------------------------------------------------------
# DEPENDENCY CHECK
#-------------------------------------------------------------------------------
for cmd in lspci wget gpg curl sed awk uname; do
  command -v "$cmd" >/dev/null 2>&1 || { echo "Missing dependency: $cmd"; exit 1; }
done

#-------------------------------------------------------------------------------
# OS DETECTION
#-------------------------------------------------------------------------------
osr="/etc/os-release"
[[ -r "$osr" ]] || osr="/usr/lib/os-release"
[[ -r "$osr" ]] || { echo "Cannot read os-release file. Exiting."; exit 1; }

set -a
. "$osr"
set +a

[[ "${ID:-}" != "ubuntu" ]] && { echo "This script is intended for Ubuntu only. Exiting."; exit 1; }

UBUNTU_VERSION="${VERSION_ID:-}"
UBUNTU_CODENAME="${VERSION_CODENAME:-}"

if [[ -z "${UBUNTU_CODENAME}" ]]; then
  case "${UBUNTU_VERSION}" in
    "22.04") UBUNTU_CODENAME="jammy" ;;
    "24.04") UBUNTU_CODENAME="noble" ;;
    "26.04") UBUNTU_CODENAME="resolute" ;;
    *) UBUNTU_CODENAME="unknown" ;;
  esac
fi

[[ -z "${UBUNTU_VERSION}" ]] && { echo "Cannot detect Ubuntu VERSION_ID. Exiting."; exit 1; }

if [[ "${DO_OS_POLICY_CHECK:-0}" -eq 1 ]]; then
  ok=0
  for v in "${ALLOWED_UBUNTU_VERSIONS[@]}"; do
    [[ "${UBUNTU_VERSION}" == "${v}" ]] && { ok=1; break; }
  done
  [[ "${ok}" -ne 1 ]] && { echo "Unsupported Ubuntu version: ${UBUNTU_VERSION}"; exit 1; }
fi

RELEASE_VERSION="$(echo "${UBUNTU_VERSION}" | sed 's/\([0-9]\+\)\.\([0-9]\+\)/\1\2/')"
echo "OS: Ubuntu ${UBUNTU_VERSION} (${UBUNTU_CODENAME})"

#-------------------------------------------------------------------------------
# GPU DETECTION
#-------------------------------------------------------------------------------
NVIDIA_GPU_LINES="$(lspci -nn | grep -iE 'vga|3d' | grep -i '10de:' || true)"
[[ -z "${NVIDIA_GPU_LINES}" ]] && { echo "No NVIDIA GPU detected (vendor 10de). Exiting."; exit 1; }

echo "NVIDIA GPUs detected:"
echo "${NVIDIA_GPU_LINES}"

DETECTED_GPUS="$(lspci -nn)"
REBOOT_REQUIRED=0

#-------------------------------------------------------------------------------
# SYSTEM PREPARATION
#-------------------------------------------------------------------------------
export DEBIAN_FRONTEND=noninteractive
export NEEDRESTART_MODE=a

if [[ "${DO_APT_UPGRADE}" -eq 1 ]]; then
  echo "Updating system packages..."
  sudo -E apt-get update
  sudo -E apt-get upgrade -y \
    -o Dpkg::Options::="--force-confdef" \
    -o Dpkg::Options::="--force-confold"
fi

if [[ "${DO_INSTALL_HWE}" -eq 1 ]]; then
  case "${UBUNTU_VERSION}" in
    "22.04") HWE_PKG="linux-generic-hwe-22.04" ;;
    "24.04") HWE_PKG="linux-generic-hwe-24.04" ;;
    "26.04") HWE_PKG="" ;;
    *) HWE_PKG="" ;;
  esac
  if [[ -n "${HWE_PKG}" ]]; then
    echo "Installing HWE kernel: ${HWE_PKG}"
    sudo -E apt-get install -y \
      -o Dpkg::Options::="--force-confdef" \
      -o Dpkg::Options::="--force-confold" \
      "${HWE_PKG}"
    REBOOT_REQUIRED=1
  fi
fi

if [[ "${DO_INSTALL_KERNEL_HEADERS}" -eq 1 ]]; then
  CURRENT_KERNEL="$(uname -r)"
  echo "Installing kernel headers for: ${CURRENT_KERNEL}"
  sudo -E apt-get install -y \
    -o Dpkg::Options::="--force-confdef" \
    -o Dpkg::Options::="--force-confold" \
    "linux-headers-${CURRENT_KERNEL}" || {
    echo "Failed to install linux-headers. DKMS may fail."; exit 1; }
fi

if [[ "${DO_INSTALL_BUILD_TOOLS}" -eq 1 ]]; then
  case "${UBUNTU_VERSION}" in
    "22.04") GCC_PACKAGES=("gcc-12" "g++-12") ;;
    "24.04") GCC_PACKAGES=("gcc-13" "g++-13") ;;
    "26.04") GCC_PACKAGES=("gcc-15" "g++-15") ;;
    *) GCC_PACKAGES=("gcc" "g++") ;;
  esac
  echo "Installing build tools: ${GCC_PACKAGES[*]}"
  sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" "${GCC_PACKAGES[@]}"
fi

#-------------------------------------------------------------------------------
# PURGE OLD PACKAGES
#-------------------------------------------------------------------------------
if [[ "${DO_PURGE_OLD_PACKAGES}" -eq 1 ]]; then
  echo "Purging previous NVIDIA/CUDA installations..."
  sudo dpkg --configure -a || true
  sudo -E apt-get purge -y "nvidia-*" "libnvidia-*" "cuda-*" "nvidia-driver-*" "*cudnn*" "*nsight*" 2>/dev/null || true
  sudo -E apt-get remove --purge -y nvidia-cuda-toolkit nvidia-prime nvidia-settings 2>/dev/null || true
  sudo -E apt-get autoremove -y || true
  sudo -E apt-get --fix-broken install -y || true
  sudo -E apt-get clean -y || true
fi

#-------------------------------------------------------------------------------
# SETUP CUDA REPOSITORY
#-------------------------------------------------------------------------------
if [[ "${DO_SETUP_CUDA_REPO}" -eq 1 ]]; then
  echo "Setting up CUDA repo for ubuntu${RELEASE_VERSION}..."
  wget -q "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${RELEASE_VERSION}/x86_64/cuda-keyring_1.1-1_all.deb"
  sudo dpkg -i cuda-keyring_1.1-1_all.deb 2>/dev/null || true
  rm -f cuda-keyring_1.1-1_all.deb
  sudo -E apt-get update
fi

#-------------------------------------------------------------------------------
# BLACKLIST NOUVEAU
#-------------------------------------------------------------------------------
if [[ "${DO_BLACKLIST_NOUVEAU}" -eq 1 ]]; then
  BL_FILE="/etc/modprobe.d/blacklist-nouveau.conf"
  if [[ ! -f "${BL_FILE}" ]] || ! grep -q "^blacklist nouveau" "${BL_FILE}" 2>/dev/null; then
    echo "Blacklisting nouveau (requires reboot)..."
    sudo tee "${BL_FILE}" >/dev/null <<'EOF'
blacklist nouveau
options nouveau modeset=0
EOF
    sudo update-initramfs -u
    REBOOT_REQUIRED=1
  fi
fi

#-------------------------------------------------------------------------------
# INSTALL DRIVER
#-------------------------------------------------------------------------------
IS_BLACKWELL=0
IS_LEGACY=0
IS_PROPRIETARY=0

# 1) Blackwell: open modules
for gpu_spec in "${BLACKWELL_GPUS[@]}"; do
  IFS='|' read -r pci_id gpu_name <<< "$gpu_spec"
  if echo "$DETECTED_GPUS" | grep -q "$pci_id"; then
    echo "Detected Blackwell GPU: $gpu_name ($pci_id)"
    echo "Installing open kernel modules..."
    sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" \
      nvidia-open nvidia-driver-open nvidia-dkms-open
    IS_BLACKWELL=1
    break
  fi
done

# 2) Legacy GPUs: pinned driver
if [[ "$IS_BLACKWELL" -eq 0 ]]; then
  for gpu_spec in "${LEGACY_GPUS[@]}"; do
    IFS='|' read -r pci_id gpu_name driver_pkg <<< "$gpu_spec"
    if echo "$DETECTED_GPUS" | grep -q "$pci_id"; then
      echo "Detected legacy GPU: $gpu_name ($pci_id) -> $driver_pkg"
      sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" \
        "$driver_pkg" "nvidia-dkms-${driver_pkg#nvidia-driver-}"
      IS_LEGACY=1
      break
    fi
  done
fi

# 3) Everything else: PROPRIETARY driver 580 (RTX A5000 falls here)
if [[ "$IS_BLACKWELL" -eq 0 && "$IS_LEGACY" -eq 0 ]]; then
  echo "Detected non-Blackwell, non-legacy GPU (e.g., RTX A5000)."
  echo "Installing proprietary driver 580..."
  sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" \
    nvidia-driver-580 nvidia-dkms-580
  IS_PROPRIETARY=1
fi

#-------------------------------------------------------------------------------
# INSTALL CUDA TOOLKIT
# - Legacy (CC < 7.5): CUDA 12.9 (last branch supporting Pascal/Volta)
# - Blackwell / Proprietary (CC >= 7.5): latest cuda-toolkit meta-package
# - cuda-drivers is NEVER installed
#-------------------------------------------------------------------------------
if [[ "${DO_INSTALL_CUDA_STACK}" -eq 1 ]]; then
  if [[ "$IS_LEGACY" -eq 1 ]]; then
    echo "Installing CUDA Toolkit 12.9 (legacy path, last branch supporting Pascal/Volta)..."
    sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" cuda-toolkit-12-9
  else
    echo "Installing latest available CUDA Toolkit (Blackwell/proprietary path)..."
    sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" cuda-toolkit
  fi
fi

#-------------------------------------------------------------------------------
# POST-INSTALL STEPS
#-------------------------------------------------------------------------------
if [[ "${DO_TRY_RMMOD_NOUVEAU}" -eq 1 ]]; then
  sudo rmmod -f nouveau 2>/dev/null || true
fi

if [[ "${DO_USER_GROUPS}" -eq 1 ]]; then
  TARGET_USER="${SUDO_USER:-$USER}"
  sudo usermod -aG video,render "${TARGET_USER}" || true
  echo "User ${TARGET_USER} added to video/render groups."
  REBOOT_REQUIRED=1
fi

if [[ "${DO_BASHRC_CUDA_PATHS}" -eq 1 ]]; then
  TARGET_USER="${SUDO_USER:-$USER}"
  TARGET_HOME="$(getent passwd "${TARGET_USER}" | cut -d: -f6)"
  TARGET_BASHRC="${TARGET_HOME}/.bashrc"
  MARKER="NVIDIA CUDA Paths"

  [[ -f "${TARGET_BASHRC}" ]] || sudo -u "${TARGET_USER}" touch "${TARGET_BASHRC}" || true

  if ! grep -q "${MARKER}" "${TARGET_BASHRC}" 2>/dev/null; then
    cat >> "${TARGET_BASHRC}" <<'EOF'

# NVIDIA CUDA Paths
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
EOF
    echo "Added CUDA PATH to ${TARGET_BASHRC}"
  fi
fi

#-------------------------------------------------------------------------------
# VERIFICATION
#-------------------------------------------------------------------------------
if [[ "${DO_VERIFY_NVIDIA_SMI}" -eq 1 ]]; then
  echo "Verifying nvidia-smi..."
  nvidia-smi || true
fi

if [[ "${DO_VERIFY_NVCC}" -eq 1 ]]; then
  if command -v nvcc >/dev/null 2>&1; then
    echo "Verifying nvcc..."
    nvcc -V || true
  else
    echo "nvcc not found in PATH yet (re-login/reboot may be needed)"
  fi
fi

#-------------------------------------------------------------------------------
# NVIDIA CONTAINER TOOLKIT
#-------------------------------------------------------------------------------
if [[ "${DO_INSTALL_NVIDIA_CONTAINER_TOOLKIT}" -eq 1 ]]; then
  if command -v docker >/dev/null 2>&1; then
    echo "Docker detected: installing NVIDIA Container Toolkit..."
    sudo -E apt-get update
    sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" curl gnupg2

    sudo install -d -m 0755 /usr/share/keyrings
    curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
          | sudo gpg --dearmor --yes -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 >/dev/null

    sudo -E apt-get update
    sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" nvidia-container-toolkit

    if [[ "${DO_CONFIGURE_DOCKER_RUNTIME}" -eq 1 ]]; then
      command -v nvidia-ctk >/dev/null 2>&1 && sudo nvidia-ctk runtime configure --runtime=docker || true
    fi

    if [[ "${DO_RESTART_DOCKER}" -eq 1 ]]; then
      sudo systemctl restart docker || true
    fi
  else
    echo "Docker not found. Skipping container toolkit."
  fi
fi

#-------------------------------------------------------------------------------
# FINAL
#-------------------------------------------------------------------------------
echo ""
echo "========================================"
echo "Installation finished"
echo "========================================"

if [[ "${REBOOT_REQUIRED}" -eq 1 ]]; then
  echo ">> REBOOT REQUIRED: sudo reboot"
fi

echo "After reboot, verify with:"
echo "  nvidia-smi"
echo "  nvcc -V"

Let op

Na het uitvoeren van het script is een herstart van de server met het commando sudo reboot verplicht. Dit is nodig om de nieuwe kernelmodules te activeren.

Controleer na het herstarten de installatie van de drivers en CUDA met de commando's nvidia-smi en nvcc -V. U zou een output moeten zien die vergelijkbaar is met het volgende:

+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 595.71.05              Driver Version: 595.71.05      CUDA Version: 13.2     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 4090        On  |   00000000:07:00.0 Off |                  Off |
| 31%   27C    P8              7W /  450W |      33MiB /  24564MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

en

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2026 NVIDIA Corporation
Built on Thu_Mar_19_11:12:51_PM_PDT_2026
Cuda compilation tools, release 13.2, V13.2.78
Build cuda_13.2.r13.2/compiler.37668154_0

Installatiescript Alma/Rocky Linux

#!/bin/bash
#===============================================================================
# Universal NVIDIA Driver + CUDA Installer for AlmaLinux/Rocky Linux 9 & 10
# - Legacy GPUs (CC < 7.5): pinned proprietary driver + CUDA 12.x
# - Blackwell GPUs: open kernel modules + latest CUDA
# - All other GPUs (incl. RTX A5000, CC 8.6): proprietary driver + latest CUDA
# - cuda-drivers meta-package is NEVER installed (avoids pulling open modules)
#===============================================================================
set -euo pipefail

#-------------------------------------------------------------------------------
# CONFIGURATION FLAGS
#-------------------------------------------------------------------------------
DO_OS_POLICY_CHECK=1
ALLOWED_OS_MAJOR_VERSIONS=("9" "10")

DO_DNF_UPGRADE=1
DO_INSTALL_KERNEL_HEADERS=1
DO_INSTALL_BUILD_TOOLS=1

DO_PURGE_OLD_PACKAGES=1
DO_SETUP_CUDA_REPO=1
DO_INSTALL_CUDA_STACK=1

# Legacy GPUs: pinned driver per card (CC < 7.5, CUDA 12.x only)
# For RHEL 9, driver 535 is available via module stream. For RHEL 10,
# legacy support relies on whatever is available or RPM Fusion (not covered here).
LEGACY_GPUS=(
  "10de:1b06|GeForce GTX 1080 Ti|535"
  "10de:1db1|Tesla V100|535"
  "10de:1b80|GeForce GTX 1070|535"
  "10de:1c03|GeForce GTX 1060|535"
)

# Blackwell GPUs: require open kernel modules
BLACKWELL_GPUS=(
  "10de:2b85|GeForce RTX 5090"
  "10de:2b87|GeForce RTX 5090 D"
  "10de:2b84|GeForce RTX 5080"
  "10de:2b83|GeForce RTX 5070 Ti"
  "10de:2b82|GeForce RTX 5070"
  "10de:2f80|GeForce RTX 5070 Laptop GPU"
  "10de:2bb5|RTX PRO 6000 Blackwell Server Edition"
  "10de:2bb4|RTX PRO 6000 Blackwell Workstation Edition"
  "10de:2bb1|RTX PRO 6000 Blackwell Max-Q"
  "10de:2bb3|RTX PRO 5000 Blackwell"
  "10de:2c31|RTX PRO 4500 Blackwell"
  "10de:2c37|RTX PRO 4000 Blackwell"
  "10de:2c36|RTX PRO 3000 Blackwell"
  "10de:2d30|RTX PRO 2000 Blackwell"
  "10de:2c35|RTX PRO 2000 Blackwell (Alternative)"
  "10de:2c3a|RTX PRO 4500 Blackwell Server Edition"
  "10de:2c77|RTX PRO 5000 Blackwell Embedded GPU"
  "10de:2c38|RTX PRO 5000 Blackwell Generation Laptop GPU"
  "10de:2f38|RTX PRO 3000 Blackwell Generation Laptop GPU"
  "10de:2db8|RTX PRO 1000 Blackwell Generation Laptop GPU"
)

DO_BLACKLIST_NOUVEAU=1
DO_TRY_RMMOD_NOUVEAU=1
DO_USER_GROUPS=0
DO_BASHRC_CUDA_PATHS=1
DO_VERIFY_NVIDIA_SMI=1
DO_VERIFY_NVCC=1
DO_INSTALL_NVIDIA_CONTAINER_TOOLKIT=1
DO_CONFIGURE_DOCKER_RUNTIME=1
DO_RESTART_DOCKER=1

# ---- Start ----
echo "Starting NVIDIA driver + CUDA installation for RHEL-family (Non-Interactive)..."

#-------------------------------------------------------------------------------
# DEPENDENCY CHECK + AUTO-INSTALL (AlmaLinux 9/10)
#-------------------------------------------------------------------------------

# Mapping: command -> package in AlmaLinux 9/10
declare -A PKG_MAP=(
  [lspci]="pciutils"
  [wget]="wget"
  [curl]="curl"
  [sed]="sed"
  [awk]="gawk"
  [uname]="coreutils"
  [dnf]="dnf"
)

MISSING_CMDS=()
MISSING_PKGS=()

# 1. Check
for cmd in "${!PKG_MAP[@]}"; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "Missing dependency: $cmd"
    MISSING_CMDS+=("$cmd")
    MISSING_PKGS+=("${PKG_MAP[$cmd]}")
  fi
done

# 2. Install missing packages
if [ ${#MISSING_PKGS[@]} -gt 0 ]; then
  UNIQUE_PKGS=$(printf "%s\n" "${MISSING_PKGS[@]}" | sort -u | tr '\n' ' ')
  echo "Installing packages: $UNIQUE_PKGS"

  if ! command -v dnf >/dev/null 2>&1; then
    echo "ERROR: dnf is not available. Cannot install dependencies automatically." >&2
    exit 1
  fi

  if ! sudo dnf install -y $UNIQUE_PKGS; then
    echo "ERROR: Failed to install packages: $UNIQUE_PKGS" >&2
    exit 1
  fi

  echo "Re-checking dependencies..."
  for cmd in "${MISSING_CMDS[@]}"; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      echo "ERROR: '$cmd' still missing after installation." >&2
      exit 1
    fi
  done
  echo "All dependencies installed successfully."
else
  echo "All dependencies are present."
fi

#-------------------------------------------------------------------------------
# OS DETECTION
#-------------------------------------------------------------------------------
osr="/etc/os-release"
[[ -r "$osr" ]] || { echo "Cannot read os-release file. Exiting."; exit 1; }

set -a
. "$osr"
set +a

if [[ "${ID:-}" != "almalinux" && "${ID:-}" != "rocky" ]]; then
  echo "This script is intended for AlmaLinux or Rocky Linux only. Exiting."
  exit 1
fi

OS_MAJOR_VERSION="${VERSION_ID%%.*}"
OS_NAME="${ID}"

if [[ "${DO_OS_POLICY_CHECK:-0}" -eq 1 ]]; then
  ok=0
  for v in "${ALLOWED_OS_MAJOR_VERSIONS[@]}"; do
    [[ "${OS_MAJOR_VERSION}" == "${v}" ]] && { ok=1; break; }
  done
  [[ "${ok}" -ne 1 ]] && { echo "Unsupported OS major version: ${OS_MAJOR_VERSION}"; exit 1; }
fi

echo "OS: ${OS_NAME} ${VERSION_ID} (major ${OS_MAJOR_VERSION})"

#-------------------------------------------------------------------------------
# GPU DETECTION
#-------------------------------------------------------------------------------
NVIDIA_GPU_LINES="$(lspci -nn | grep -iE 'vga|3d' | grep -i '10de:' || true)"
[[ -z "${NVIDIA_GPU_LINES}" ]] && { echo "No NVIDIA GPU detected (vendor 10de). Exiting."; exit 1; }

echo "NVIDIA GPUs detected:"
echo "${NVIDIA_GPU_LINES}"

DETECTED_GPUS="$(lspci -nn)"
REBOOT_REQUIRED=0

#-------------------------------------------------------------------------------
# SYSTEM PREPARATION
#-------------------------------------------------------------------------------
if [[ "${DO_DNF_UPGRADE}" -eq 1 ]]; then
  echo "Updating system packages..."
  sudo dnf upgrade -y
fi

if [[ "${DO_INSTALL_KERNEL_HEADERS}" -eq 1 ]]; then
  CURRENT_KERNEL="$(uname -r)"
  echo "Installing kernel headers/devel for: ${CURRENT_KERNEL}"
  sudo dnf install -y "kernel-devel-${CURRENT_KERNEL}" "kernel-headers-${CURRENT_KERNEL}" || {
    echo "Failed to install kernel-devel/headers. DKMS may fail."; exit 1; }
fi

if [[ "${DO_INSTALL_BUILD_TOOLS}" -eq 1 ]]; then
  # RHEL 9/10 provide gcc via the base repo; specific versions are not strictly necessary for DKMS
  echo "Installing build tools: gcc, gcc-c++, make, dkms"
  sudo dnf install -y gcc gcc-c++ make dkms
fi

#-------------------------------------------------------------------------------
# PURGE OLD PACKAGES
#-------------------------------------------------------------------------------
if [[ "${DO_PURGE_OLD_PACKAGES}" -eq 1 ]]; then
  echo "Purging previous NVIDIA/CUDA installations..."
  # Disable module streams if they were previously enabled
  sudo dnf module reset -y nvidia-driver 2>/dev/null || true

  # Remove NVIDIA and CUDA packages
  sudo dnf remove -y '*nvidia*' '*cuda*' 2>/dev/null || true
  sudo dnf autoremove -y || true
  sudo dnf clean all || true
fi

#-------------------------------------------------------------------------------
# TEMPORARY SHA1 ENABLE (for old NVIDIA GPG keys)
#-------------------------------------------------------------------------------
echo "Temporarily enabling SHA1 crypto policy for NVIDIA repo compatibility..."
sudo update-crypto-policies --set DEFAULT:SHA1

#-------------------------------------------------------------------------------
# SETUP CUDA REPOSITORY
#-------------------------------------------------------------------------------
if [[ "${DO_SETUP_CUDA_REPO}" -eq 1 ]]; then
  # NVIDIA uses rhel9/rhel10 repo paths for all RHEL-compatible distros
  CUDA_REPO_DISTRO="rhel${OS_MAJOR_VERSION}"
  REPO_URL="https://developer.download.nvidia.com/compute/cuda/repos/${CUDA_REPO_DISTRO}/x86_64/cuda-${CUDA_REPO_DISTRO}.repo"

  echo "Setting up CUDA repo for ${CUDA_REPO_DISTRO}..."
  sudo dnf config-manager --add-repo "${REPO_URL}" 2>/dev/null || {
    # Fallback for dnf5 (RHEL 10) where config-manager syntax differs
    sudo dnf config-manager addrepo --from-repofile="${REPO_URL}" 2>/dev/null || true
  }

  # Disable the nvidia-driver module from the CUDA repo for RHEL 9 only.
  # RHEL 10 does not use module streams for NVIDIA drivers.
  if [[ "${OS_MAJOR_VERSION}" == "9" ]]; then
    sudo dnf module disable -y nvidia-driver 2>/dev/null || true
  fi

  sudo dnf clean all
  sudo dnf makecache
fi

#-------------------------------------------------------------------------------
# BLACKLIST NOUVEAU
#-------------------------------------------------------------------------------
if [[ "${DO_BLACKLIST_NOUVEAU}" -eq 1 ]]; then
  BL_FILE="/etc/modprobe.d/blacklist-nouveau.conf"
  if [[ ! -f "${BL_FILE}" ]] || ! grep -q "^blacklist nouveau" "${BL_FILE}" 2>/dev/null; then
    echo "Blacklisting nouveau (requires reboot)..."
    sudo tee "${BL_FILE}" >/dev/null <<'EOF'
blacklist nouveau
options nouveau modeset=0
EOF
    sudo dracut --force
    REBOOT_REQUIRED=1
  fi
fi

#-------------------------------------------------------------------------------
# INSTALL DRIVER
#-------------------------------------------------------------------------------
IS_BLACKWELL=0
IS_LEGACY=0
IS_PROPRIETARY=0

# Helper to install open modules (Blackwell)
install_open_driver() {
  echo "Installing open kernel modules..."
  if [[ "${OS_MAJOR_VERSION}" == "9" ]]; then
    # RHEL 9 uses module streams for NVIDIA drivers from the CUDA repo
    sudo dnf module install -y nvidia-driver:latest-open
  else
    # RHEL 10 uses direct packages
    sudo dnf install -y nvidia-open
  fi
}

# Helper to install proprietary driver (legacy or generic)
# $1: optional module stream (e.g., "535") for RHEL 9
install_proprietary_driver() {
  local stream="${1:-}"
  if [[ "${OS_MAJOR_VERSION}" == "9" ]]; then
    if [[ -n "${stream}" ]]; then
      echo "Installing proprietary driver stream ${stream}-dkms (RHEL 9)..."
      sudo dnf module install -y "nvidia-driver:${stream}-dkms"
    else
      echo "Installing proprietary driver stream latest-dkms (RHEL 9)..."
      sudo dnf module install -y "nvidia-driver:latest-dkms"
    fi
  else
    # RHEL 10: no module streams; install the driver package directly.
    # Note: cuda-drivers pulls proprietary modules; we avoid it per original logic.
    echo "Installing proprietary driver package (RHEL 10)..."
    sudo dnf install -y nvidia-driver
  fi
}

# 1) Blackwell: open modules
for gpu_spec in "${BLACKWELL_GPUS[@]}"; do
  IFS='|' read -r pci_id gpu_name <<< "$gpu_spec"
  if echo "$DETECTED_GPUS" | grep -q "$pci_id"; then
    echo "Detected Blackwell GPU: $gpu_name ($pci_id)"
    install_open_driver
    IS_BLACKWELL=1
    break
  fi
done

# 2) Legacy GPUs: pinned driver
if [[ "$IS_BLACKWELL" -eq 0 ]]; then
  for gpu_spec in "${LEGACY_GPUS[@]}"; do
    IFS='|' read -r pci_id gpu_name driver_stream <<< "$gpu_spec"
    if echo "$DETECTED_GPUS" | grep -q "$pci_id"; then
      echo "Detected legacy GPU: $gpu_name ($pci_id) -> stream $driver_stream"
      if [[ "${OS_MAJOR_VERSION}" == "9" ]]; then
        install_proprietary_driver "$driver_stream"
      else
        echo "Warning: Legacy driver streams (${driver_stream}) may not be available on RHEL 10. Attempting latest proprietary."
        install_proprietary_driver
      fi
      IS_LEGACY=1
      break
    fi
  done
fi

# 3) Everything else: PROPRIETARY driver (RTX A5000 falls here)
if [[ "$IS_BLACKWELL" -eq 0 && "$IS_LEGACY" -eq 0 ]]; then
  echo "Detected non-Blackwell, non-legacy GPU (e.g., RTX A5000)."
  echo "Installing proprietary driver..."
  install_proprietary_driver
  IS_PROPRIETARY=1
fi

#-------------------------------------------------------------------------------
# INSTALL CUDA TOOLKIT
# - Legacy (CC < 7.5): CUDA 12.x (last branch supporting Pascal/Volta)
# - Blackwell / Proprietary (CC >= 7.5): latest cuda-toolkit
# - cuda-drivers is NEVER installed
#-------------------------------------------------------------------------------
if [[ "${DO_INSTALL_CUDA_STACK}" -eq 1 ]]; then
  if [[ "$IS_LEGACY" -eq 1 ]]; then
    # For RHEL 9, CUDA 12.9 is available. On RHEL 10, only newer CUDA is available.
    if [[ "${OS_MAJOR_VERSION}" == "9" ]]; then
      echo "Installing CUDA Toolkit 12.9 (legacy path, last branch supporting Pascal/Volta)..."
      sudo dnf install -y cuda-toolkit-12-9
    else
      echo "Warning: CUDA 12.9 may not be available on RHEL 10. Installing latest cuda-toolkit."
      sudo dnf install -y cuda-toolkit
    fi
  else
    echo "Installing latest available CUDA Toolkit (Blackwell/proprietary path)..."
    sudo dnf install -y cuda-toolkit
  fi
fi

#-------------------------------------------------------------------------------
# POST-INSTALL STEPS
#-------------------------------------------------------------------------------
if [[ "${DO_TRY_RMMOD_NOUVEAU}" -eq 1 ]]; then
  sudo rmmod -f nouveau 2>/dev/null || true
fi

if [[ "${DO_USER_GROUPS}" -eq 1 ]]; then
  TARGET_USER="${SUDO_USER:-$USER}"
  sudo usermod -aG video,render "${TARGET_USER}" || true
  echo "User ${TARGET_USER} added to video/render groups."
  REBOOT_REQUIRED=1
fi

if [[ "${DO_BASHRC_CUDA_PATHS}" -eq 1 ]]; then
  TARGET_USER="${SUDO_USER:-$USER}"
  TARGET_HOME="$(getent passwd "${TARGET_USER}" | cut -d: -f6)"
  TARGET_BASHRC="${TARGET_HOME}/.bashrc"
  MARKER="NVIDIA CUDA Paths"

  [[ -f "${TARGET_BASHRC}" ]] || sudo -u "${TARGET_USER}" touch "${TARGET_BASHRC}" || true

  if ! grep -q "${MARKER}" "${TARGET_BASHRC}" 2>/dev/null; then
    cat >> "${TARGET_BASHRC}" <<'EOF'

# NVIDIA CUDA Paths
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
EOF
    echo "Added CUDA PATH to ${TARGET_BASHRC}"
  fi
fi

#-------------------------------------------------------------------------------
# VERIFICATION
#-------------------------------------------------------------------------------
if [[ "${DO_VERIFY_NVIDIA_SMI}" -eq 1 ]]; then
  echo "Verifying nvidia-smi..."
  nvidia-smi || true
fi

if [[ "${DO_VERIFY_NVCC}" -eq 1 ]]; then
  if command -v nvcc >/dev/null 2>&1; then
    echo "Verifying nvcc..."
    nvcc -V || true
  else
    echo "nvcc not found in PATH yet (re-login/reboot may be needed)"
  fi
fi

#-------------------------------------------------------------------------------
# NVIDIA CONTAINER TOOLKIT
#-------------------------------------------------------------------------------
if [[ "${DO_INSTALL_NVIDIA_CONTAINER_TOOLKIT}" -eq 1 ]]; then
  if command -v docker >/dev/null 2>&1 || command -v podman >/dev/null 2>&1; then
    echo "Container engine detected: installing NVIDIA Container Toolkit..."

    # Add repo (works for RHEL family)
    curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo \
      | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo >/dev/null

    sudo dnf install -y nvidia-container-toolkit

    if [[ "${DO_CONFIGURE_DOCKER_RUNTIME}" -eq 1 ]] && command -v docker >/dev/null 2>&1; then
      command -v nvidia-ctk >/dev/null 2>&1 && sudo nvidia-ctk runtime configure --runtime=docker || true
    fi

    if [[ "${DO_RESTART_DOCKER}" -eq 1 ]] && command -v docker >/dev/null 2>&1; then
      sudo systemctl restart docker || true
    fi
  else
    echo "Docker/Podman not found. Skipping container toolkit."
  fi
fi

#-------------------------------------------------------------------------------
# RESTORE DEFAULT CRYPTO POLICY
#-------------------------------------------------------------------------------
echo "Restoring default crypto policy (SHA1 disabled)..."
sudo update-crypto-policies --set DEFAULT

#-------------------------------------------------------------------------------
# FINAL
#-------------------------------------------------------------------------------
echo ""
echo "========================================"
echo "Installation finished"
echo "========================================"

if [[ "${REBOOT_REQUIRED}" -eq 1 ]]; then
  echo ">> REBOOT REQUIRED: sudo reboot"
fi

echo "After reboot, verify with:"
echo "  nvidia-smi"
echo "  nvcc -V"
question_mark
Is there anything I can help you with?
question_mark
AI Assistant ×