From 8114c7c25290b1aa6538d147de416ca579a53d74 Mon Sep 17 00:00:00 2001 From: Ben Gauger Date: Thu, 12 Mar 2026 18:15:02 -0600 Subject: [PATCH] feat(install): add multi-distro Linux support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The install script was Debian-only but everything runs in Docker, so there's no reason it can't work on other distros. This swaps out the Debian check for distro detection via /etc/os-release and adds a pkg_install wrapper that calls the right package manager. get.docker.com doesn't support Arch or openSUSE so those install Docker from their own repos. NVIDIA toolkit setup is also handled per-distro since the repo config is different for deb/rpm/Arch. A couple of small fixups too — hostname isn't always available on minimal installs so there's a fallback to the ip command, and Arch needs iptables-nft for Docker networking. README updated to list supported distros. Tested on Debian 12, Arch, Fedora 42, and openSUSE Leap 15.6. Closes #235 --- README.md | 17 ++- admin/docs/release-notes.md | 2 +- install/install_nomad.sh | 216 +++++++++++++++++++++++++++++------- 3 files changed, 189 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index e2749d9..d4734c9 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,22 @@ Project N.O.M.A.D. is a self-contained, offline-first knowledge and education server packed with critical tools, knowledge, and AI to keep you informed and empowered—anytime, anywhere. ## Installation & Quickstart -Project N.O.M.A.D. can be installed on any Debian-based operating system (we recommend Ubuntu). Installation is completely terminal-based, and all tools and resources are designed to be accessed through the browser, so there's no need for a desktop environment if you'd rather setup N.O.M.A.D. as a "server" and access it through other clients. +Project N.O.M.A.D. can be installed on most Linux distributions. The install script automatically detects your distro and uses the appropriate package manager. Installation is completely terminal-based, and all tools and resources are designed to be accessed through the browser, so there's no need for a desktop environment if you'd rather setup N.O.M.A.D. as a "server" and access it through other clients. + +#### Supported Distributions +| Family | Distros | +|--------|---------| +| Debian/Ubuntu | Debian, Ubuntu, Raspbian, Linux Mint, Pop!_OS, Elementary, Zorin, Kali | +| Arch | Arch Linux, Manjaro, EndeavourOS, Garuda, CachyOS | +| Fedora/RHEL | Fedora, RHEL, CentOS, Rocky, AlmaLinux, Nobara | +| openSUSE | openSUSE Leap, openSUSE Tumbleweed, SLES | +| Other | Void Linux, Alpine Linux | *Note: sudo/root privileges are required to run the install script* ### Quick Install (Debian-based OS Only) ```bash -sudo apt-get update && sudo apt-get install -y curl && curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/install_nomad.sh -o install_nomad.sh && sudo bash install_nomad.sh +curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/install_nomad.sh -o install_nomad.sh && sudo bash install_nomad.sh ``` Project N.O.M.A.D. is now installed on your device! Open a browser and navigate to `http://localhost:8080` (or `http://DEVICE_IP:8080`) to start exploring! @@ -72,7 +81,7 @@ At it's core, however, N.O.M.A.D. is still very lightweight. For a barebones ins - Processor: 2 GHz dual-core processor or better - RAM: 4GB system memory - Storage: At least 5 GB free disk space -- OS: Debian-based (Ubuntu recommended) +- OS: Any supported Linux distribution (see [Supported Distributions](#supported-distributions)) - Stable internet connection (required during install only) To run LLM's and other included AI tools: @@ -82,7 +91,7 @@ To run LLM's and other included AI tools: - RAM: 32 GB system memory - Graphics: NVIDIA RTX 3060 or AMD equivalent or better (more VRAM = run larger models) - Storage: At least 250 GB free disk space (preferably on SSD) -- OS: Debian-based (Ubuntu recommended) +- OS: Any supported Linux distribution (see [Supported Distributions](#supported-distributions)) - Stable internet connection (required during install only) **For detailed build recommendations at three price points ($150–$1,000+), see the [Hardware Guide](https://www.projectnomad.us/hardware).** diff --git a/admin/docs/release-notes.md b/admin/docs/release-notes.md index 9c667f1..dc1a9a7 100644 --- a/admin/docs/release-notes.md +++ b/admin/docs/release-notes.md @@ -3,6 +3,7 @@ ## Version 1.30.3 - March 25, 2026 ### Features +- **Install**: Added multi-distro Linux support — the install script now detects and supports Arch, Fedora/RHEL, openSUSE, Void, and Alpine in addition to Debian/Ubuntu ### Bug Fixes - **Benchmark**: Fixed an issue where CPU and Disk Write scores could be displayed as 0 if the measured values was less than half of the reference mark. Thanks @bortlesboat for the fix! @@ -52,7 +53,6 @@ - **Utility Scripts**: Added an additional warning to the installation script to inform about potential overwriting of existing customized configurations and the importance of backing up data before running the installation script again. - **Documentation**: Updated installation instructions to reflect the new option for manual deployment via Docker Compose without the install script. - ## Version 1.29.0 - March 11, 2026 ### Features diff --git a/install/install_nomad.sh b/install/install_nomad.sh index c3f609b..f77bfa5 100644 --- a/install/install_nomad.sh +++ b/install/install_nomad.sh @@ -76,14 +76,101 @@ check_is_bash() { echo -e "${GREEN}#${RESET} This script is running in bash.\\n" } -check_is_debian_based() { - if [[ ! -f /etc/debian_version ]]; then - header_red - echo -e "${RED}#${RESET} This script is designed to run on Debian-based systems only.\\n" - echo -e "${RED}#${RESET} Please run this script on a Debian-based system and try again." - exit 1 +detect_distro() { + # Detect the Linux distribution family for package manager selection + DISTRO_FAMILY="unknown" + DISTRO_ID="unknown" + + if [[ -f /etc/os-release ]]; then + . /etc/os-release + DISTRO_ID="${ID}" + case "${ID}" in + debian|ubuntu|raspbian|linuxmint|pop|elementary|zorin|kali) + DISTRO_FAMILY="debian" + ;; + arch|manjaro|endeavouros|garuda|artix|cachyos) + DISTRO_FAMILY="arch" + ;; + fedora|rhel|centos|rocky|alma|ol|nobara) + DISTRO_FAMILY="rhel" + ;; + opensuse*|sles) + DISTRO_FAMILY="suse" + ;; + void) + DISTRO_FAMILY="void" + ;; + alpine) + DISTRO_FAMILY="alpine" + ;; + *) + # Fallback: check ID_LIKE for parent distro + case "${ID_LIKE}" in + *debian*|*ubuntu*) + DISTRO_FAMILY="debian" + ;; + *arch*) + DISTRO_FAMILY="arch" + ;; + *rhel*|*fedora*|*centos*) + DISTRO_FAMILY="rhel" + ;; + *suse*) + DISTRO_FAMILY="suse" + ;; + *) + DISTRO_FAMILY="unknown" + ;; + esac + ;; + esac fi - echo -e "${GREEN}#${RESET} This script is running on a Debian-based system.\\n" + + if [[ "$DISTRO_FAMILY" == "unknown" ]]; then + header_red + echo -e "${RED}#${RESET} Unable to detect your Linux distribution.\\n" + echo -e "${RED}#${RESET} Supported distro families: Debian/Ubuntu, Arch, Fedora/RHEL, openSUSE, Void, Alpine." + echo -e "${RED}#${RESET} You may try continuing, but package installation may fail." + read -p "Continue anyway? (y/N): " choice + case "$choice" in + y|Y ) echo -e "${YELLOW}#${RESET} Continuing with unknown distro...\\n" ;; + * ) exit 1 ;; + esac + else + echo -e "${GREEN}#${RESET} Detected distro: ${DISTRO_ID} (family: ${DISTRO_FAMILY})\\n" + fi +} + +# Distro-agnostic package install wrapper +pkg_install() { + case "$DISTRO_FAMILY" in + debian) + sudo apt-get update -qq && sudo apt-get install -y "$@" + ;; + arch) + sudo pacman -Sy --noconfirm "$@" + ;; + rhel) + if command -v dnf &> /dev/null; then + sudo dnf install -y "$@" + else + sudo yum install -y "$@" + fi + ;; + suse) + sudo zypper install -y "$@" + ;; + void) + sudo xbps-install -Sy "$@" + ;; + alpine) + sudo apk add "$@" + ;; + *) + echo -e "${RED}#${RESET} Cannot auto-install packages on this distro. Please install manually: $*" + return 1 + ;; + esac } ensure_dependencies_installed() { @@ -101,8 +188,7 @@ ensure_dependencies_installed() { if [[ ${#missing_deps[@]} -gt 0 ]]; then echo -e "${YELLOW}#${RESET} Installing required dependencies: ${missing_deps[*]}...\\n" - sudo apt-get update - sudo apt-get install -y "${missing_deps[@]}" + pkg_install "${missing_deps[@]}" # Verify installation for dep in "${missing_deps[@]}"; do @@ -140,11 +226,8 @@ ensure_docker_installed() { if ! command -v docker &> /dev/null; then echo -e "${YELLOW}#${RESET} Docker not found. Installing Docker...\\n" - # Update package database - sudo apt-get update - # Install prerequisites - sudo apt-get install -y ca-certificates curl + pkg_install ca-certificates curl # Create directory for keyrings # sudo install -m 0755 -d /etc/apt/keyrings @@ -165,18 +248,33 @@ ensure_docker_installed() { # # Install Docker packages # sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - # Download the Docker convenience script - curl -fsSL https://get.docker.com -o get-docker.sh - - # Run the Docker installation script - sudo sh get-docker.sh + # Install Docker using the best method for this distro + case "$DISTRO_FAMILY" in + arch) + # Arch has docker in the official repos; iptables-nft needed for networking + sudo pacman -Sy --noconfirm docker docker-compose docker-buildx iptables-nft + ;; + suse) + # openSUSE has docker in official repos + sudo zypper install -y docker docker-compose docker-buildx + ;; + *) + # For Debian, Fedora/RHEL, and others: use the convenience script + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + rm -f get-docker.sh + ;; + esac # Check if Docker was installed successfully if ! command -v docker &> /dev/null; then echo -e "${RED}#${RESET} Docker installation failed. Please check the logs and try again." exit 1 fi - + + # Enable and start Docker service + sudo systemctl enable --now docker + echo -e "${GREEN}#${RESET} Docker installation completed.\\n" else echo -e "${GREEN}#${RESET} Docker is already installed.\\n" @@ -242,26 +340,57 @@ setup_nvidia_container_toolkit() { fi echo -e "${YELLOW}#${RESET} Installing NVIDIA container toolkit...\\n" - - # Install dependencies per https://docs.ollama.com/docker - wrapped in error handling - if ! curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey 2>/dev/null | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg 2>/dev/null; then - echo -e "${YELLOW}#${RESET} Warning: Failed to add NVIDIA container toolkit GPG key. Continuing anyway...\\n" - return 0 - fi - - if ! curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list 2>/dev/null \ - | 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 2>&1; then - echo -e "${YELLOW}#${RESET} Warning: Failed to add NVIDIA container toolkit repository. Continuing anyway...\\n" - return 0 - fi - - if ! sudo apt-get update 2>/dev/null; then - echo -e "${YELLOW}#${RESET} Warning: Failed to update package list. Continuing anyway...\\n" - return 0 - fi - - if ! sudo apt-get install -y nvidia-container-toolkit 2>/dev/null; then + + # Add NVIDIA container toolkit repo and install - method varies by distro family + local nvidia_install_success=false + + case "$DISTRO_FAMILY" in + debian) + if curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey 2>/dev/null | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg 2>/dev/null \ + && curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list 2>/dev/null \ + | 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 2>&1 \ + && sudo apt-get update 2>/dev/null \ + && sudo apt-get install -y nvidia-container-toolkit 2>/dev/null; then + nvidia_install_success=true + fi + ;; + rhel) + if curl -fsSL https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo 2>/dev/null \ + | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo > /dev/null 2>&1; then + if command -v dnf &> /dev/null; then + sudo dnf install -y nvidia-container-toolkit 2>/dev/null && nvidia_install_success=true + else + sudo yum install -y nvidia-container-toolkit 2>/dev/null && nvidia_install_success=true + fi + fi + ;; + suse) + if curl -fsSL https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo 2>/dev/null \ + | sudo tee /etc/zypp/repos.d/nvidia-container-toolkit.repo > /dev/null 2>&1 \ + && sudo zypper install -y nvidia-container-toolkit 2>/dev/null; then + nvidia_install_success=true + fi + ;; + arch) + # nvidia-container-toolkit is available in the AUR or community repos + if command -v yay &> /dev/null; then + yay -S --noconfirm nvidia-container-toolkit 2>/dev/null && nvidia_install_success=true + elif command -v paru &> /dev/null; then + paru -S --noconfirm nvidia-container-toolkit 2>/dev/null && nvidia_install_success=true + elif sudo pacman -Sy --noconfirm nvidia-container-toolkit 2>/dev/null; then + nvidia_install_success=true + else + echo -e "${YELLOW}#${RESET} nvidia-container-toolkit requires an AUR helper (yay/paru) or manual install on Arch.\\n" + fi + ;; + *) + echo -e "${YELLOW}#${RESET} Automatic NVIDIA container toolkit installation not supported for ${DISTRO_FAMILY}.\\n" + echo -e "${YELLOW}#${RESET} Please install nvidia-container-toolkit manually: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html\\n" + ;; + esac + + if ! $nvidia_install_success; then echo -e "${YELLOW}#${RESET} Warning: Failed to install NVIDIA container toolkit. Continuing anyway...\\n" return 0 fi @@ -459,7 +588,12 @@ start_management_containers() { } get_local_ip() { - local_ip_address=$(hostname -I | awk '{print $1}') + # Try hostname -I first, fall back to ip command for distros without hostname + if command -v hostname &> /dev/null; then + local_ip_address=$(hostname -I | awk '{print $1}') + else + local_ip_address=$(ip -4 -o addr show scope global | awk '{print $4}' | cut -d/ -f1 | head -1) + fi if [[ -z "$local_ip_address" ]]; then echo -e "${RED}#${RESET} Unable to determine local IP address. Please check your network configuration." exit 1 @@ -533,8 +667,8 @@ success_message() { ################################################################################################################################################################################################### # Pre-flight checks -check_is_debian_based check_is_bash +detect_distro check_has_sudo ensure_dependencies_installed check_is_debug_mode