diff --git a/install_ollama_deb.sh b/install_ollama_deb.sh new file mode 100644 index 0000000..50866cb --- /dev/null +++ b/install_ollama_deb.sh @@ -0,0 +1,187 @@ +#!/usr/bin/env bash +# Debian 13: Ollama mit AMD-GPU-Unterstützung und API auf 0.0.0.0 +# +# Aufruf: +# sudo bash install-ollama-debian13-amd.sh +# +# Optional: +# sudo INSTALL_SYSTEM_ROCM=1 bash install-ollama-debian13-amd.sh +# sudo MODEL=gemma3:1b bash install-ollama-debian13-amd.sh +# sudo HSA_OVERRIDE_GFX_VERSION=10.3.0 bash install-ollama-debian13-amd.sh +# +# Die Firewall wird absichtlich NICHT verändert. + +set -Eeuo pipefail +IFS=$'\n\t' + +OLLAMA_PORT="${OLLAMA_PORT:-11434}" +INSTALL_SYSTEM_ROCM="${INSTALL_SYSTEM_ROCM:-0}" +ROCM_VERSION="${ROCM_VERSION:-7.2.4}" +MODEL="${MODEL:-}" +HSA_OVERRIDE_GFX_VERSION="${HSA_OVERRIDE_GFX_VERSION:-}" + +log() { printf '\n\033[1;32m==> %s\033[0m\n' "$*"; } +warn() { printf '\n\033[1;33mWARNUNG: %s\033[0m\n' "$*" >&2; } +die() { printf '\n\033[1;31mFEHLER: %s\033[0m\n' "$*" >&2; exit 1; } + +on_error() { + local exit_code=$? + printf '\nFehler in Zeile %s (Exit-Code %s).\n' "${BASH_LINENO[0]:-?}" "$exit_code" >&2 + if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files ollama.service >/dev/null 2>&1; then + journalctl -u ollama --no-pager -n 80 >&2 || true + fi + exit "$exit_code" +} +trap on_error ERR + +[[ $EUID -eq 0 ]] || die "Bitte als root starten: sudo bash $0" +[[ "$OLLAMA_PORT" =~ ^[0-9]{1,5}$ ]] || die "OLLAMA_PORT muss eine gültige Portnummer sein." +(( OLLAMA_PORT >= 1 && OLLAMA_PORT <= 65535 )) || die "OLLAMA_PORT muss zwischen 1 und 65535 liegen." +[[ "$INSTALL_SYSTEM_ROCM" == "0" || "$INSTALL_SYSTEM_ROCM" == "1" ]] || die "INSTALL_SYSTEM_ROCM muss 0 oder 1 sein." +[[ "$ROCM_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || die "Ungültige ROCM_VERSION: $ROCM_VERSION" +if [[ -n "$HSA_OVERRIDE_GFX_VERSION" ]]; then + [[ "$HSA_OVERRIDE_GFX_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || \ + die "HSA_OVERRIDE_GFX_VERSION muss das Format x.y.z haben." +fi + +[[ -r /etc/os-release ]] || die "/etc/os-release fehlt." +# shellcheck disable=SC1091 +source /etc/os-release +[[ "${ID:-}" == "debian" && "${VERSION_ID:-}" == "13" ]] || \ + die "Dieses Skript ist für Debian 13 vorgesehen. Erkannt: ${PRETTY_NAME:-unbekannt}" +[[ "$(dpkg --print-architecture)" == "amd64" ]] || \ + die "Dieses Skript unterstützt derzeit nur Debian amd64/x86_64." +command -v systemctl >/dev/null 2>&1 || die "systemd/systemctl wurde nicht gefunden." + +export DEBIAN_FRONTEND=noninteractive + +log "Basispakete installieren" +apt-get update +apt-get install -y --no-install-recommends \ + ca-certificates curl pciutils gpg wget jq zstd + +log "AMD-Grafikkarte prüfen" +AMD_GPU_INFO="$(lspci -nn | grep -Ei 'VGA compatible controller|3D controller|Display controller' | grep -i '1002:' || true)" +if [[ -n "$AMD_GPU_INFO" ]]; then + printf '%s\n' "$AMD_GPU_INFO" +else + warn "Keine AMD-GPU mit PCI-Hersteller-ID 1002 erkannt. Ollama wird trotzdem installiert." +fi + +modprobe amdgpu 2>/dev/null || warn "Das Kernelmodul amdgpu konnte nicht geladen werden." +[[ -e /dev/kfd ]] || warn "/dev/kfd ist nicht vorhanden. ROCm-Beschleunigung könnte dadurch ausfallen." +compgen -G '/dev/dri/renderD*' >/dev/null || warn "Kein /dev/dri/renderD*-Gerät gefunden." + +if [[ "$INSTALL_SYSTEM_ROCM" == "1" ]]; then + log "Optionales systemweites ROCm ${ROCM_VERSION} installieren" + install -d -m 0755 /etc/apt/keyrings + curl -fsSL https://repo.radeon.com/rocm/rocm.gpg.key \ + | gpg --dearmor --yes -o /etc/apt/keyrings/rocm.gpg + chmod 0644 /etc/apt/keyrings/rocm.gpg + + cat > /etc/apt/sources.list.d/rocm.list < /etc/apt/preferences.d/rocm-pin-600 <<'ROCM_PIN' +Package: * +Pin: release o=repo.radeon.com +Pin-Priority: 600 +ROCM_PIN + + apt-get update + apt-get install -y python3-setuptools python3-wheel rocm +else + log "Systemweites ROCm überspringen" + printf '%s\n' "Ollamas Installer bringt die benötigten ROCm-Laufzeitbibliotheken für AMD mit." + printf '%s\n' "Bei Treiber-/GPU-Erkennungsproblemen erneut mit INSTALL_SYSTEM_ROCM=1 starten." +fi + +log "Ollama mit dem offiziellen Linux-Installer installieren/aktualisieren" +INSTALLER="$(mktemp)" +trap 'rm -f "$INSTALLER"' EXIT +curl -fsSL https://ollama.com/install.sh -o "$INSTALLER" +sh "$INSTALLER" +rm -f "$INSTALLER" +trap - EXIT + +id ollama >/dev/null 2>&1 || die "Der Benutzer 'ollama' wurde nicht angelegt." + +log "GPU-Geräteberechtigungen setzen" +for group in render video; do + if getent group "$group" >/dev/null 2>&1; then + usermod -aG "$group" ollama + if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]] && id "$SUDO_USER" >/dev/null 2>&1; then + usermod -aG "$group" "$SUDO_USER" + fi + fi +done + +log "Ollama-API auf 0.0.0.0:${OLLAMA_PORT} konfigurieren" +install -d -m 0755 /etc/systemd/system/ollama.service.d +{ + printf '%s\n' '[Service]' + printf 'Environment="OLLAMA_HOST=0.0.0.0:%s"\n' "$OLLAMA_PORT" + if [[ -n "$HSA_OVERRIDE_GFX_VERSION" ]]; then + printf 'Environment="HSA_OVERRIDE_GFX_VERSION=%s"\n' "$HSA_OVERRIDE_GFX_VERSION" + fi +} > /etc/systemd/system/ollama.service.d/override.conf +chmod 0644 /etc/systemd/system/ollama.service.d/override.conf + +systemctl daemon-reload +systemctl enable ollama.service +systemctl restart ollama.service + +log "API-Verfügbarkeit prüfen" +API_OK=0 +for _ in $(seq 1 30); do + if curl -fsS "http://127.0.0.1:${OLLAMA_PORT}/api/tags" >/dev/null; then + API_OK=1 + break + fi + sleep 1 +done + +if [[ "$API_OK" != "1" ]]; then + systemctl status ollama.service --no-pager || true + die "Ollama antwortet nicht auf Port ${OLLAMA_PORT}. Siehe journalctl -u ollama." +fi + +if [[ -n "$MODEL" ]]; then + log "Modell herunterladen: ${MODEL}" + ollama pull "$MODEL" +fi + +log "Installation abgeschlossen" +printf 'Ollama-Version: %s\n' "$(ollama --version 2>/dev/null || true)" +printf 'API lokal: http://127.0.0.1:%s/api\n' "$OLLAMA_PORT" +printf 'OpenAI-API: http://127.0.0.1:%s/v1\n' "$OLLAMA_PORT" + +HOST_IPS="$(hostname -I 2>/dev/null | xargs || true)" +if [[ -n "$HOST_IPS" ]]; then + printf 'Server-IP(s): %s\n' "$HOST_IPS" + printf 'LAN-Beispiel: http://:%s/api/tags\n' "$OLLAMA_PORT" +fi + +printf '\nListener:\n' +ss -ltnp 2>/dev/null | grep -E ":${OLLAMA_PORT}([[:space:]]|$)" || true + +printf '\nAMD/ROCm-Geräte:\n' +ls -l /dev/kfd /dev/dri/renderD* 2>/dev/null || true +if command -v rocminfo >/dev/null 2>&1; then + rocminfo 2>/dev/null | grep -E -m 12 'Name:|Marketing Name:|gfx[0-9]+' || true +elif [[ -x /opt/rocm/bin/rocminfo ]]; then + /opt/rocm/bin/rocminfo 2>/dev/null | grep -E -m 12 'Name:|Marketing Name:|gfx[0-9]+' || true +fi + +printf '\nLetzte Ollama-Logzeilen (GPU-Erkennung):\n' +journalctl -u ollama --no-pager -n 100 \ + | grep -Ei 'gpu|rocm|amdgpu|vulkan|hip|device|library' \ + | tail -n 30 || true + +printf '\nSICHERHEITSHINWEIS:\n' +printf '%s\n' "Die API lauscht auf allen Interfaces und hat lokal keine eingebaute API-Authentifizierung." +printf '%s\n' "Port ${OLLAMA_PORT} nur in vertrauenswürdigen Netzen freigeben oder einen authentifizierenden Reverse-Proxy verwenden." +printf '%s\n' "Dieses Skript verändert keine Firewall-Regeln."