#!/usr/bin/env bash # ============================================================================== # Irbis OS - Installateur Automatisé pour Raspberry Pi OS (Raspberry Pi 4 & 5) # Dépôt Officiel : https://git.nebulia.tech/SlyderSlash/Irbis_OS-Release # # Utilisation : # curl -fsSL https://git.nebulia.tech/SlyderSlash/Irbis_OS-Release/releases/download/v1.9.5.9.6/install-rpi.sh | sudo bash # ============================================================================== set -euo pipefail # 0. Couleurs et En-tête CYAN='\033[0;36m' GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' BOLD='\033[1m' NC='\033[0m' clear || true echo -e "${CYAN}${BOLD}" cat << 'EOF' _____ _ _ ____ _____ |_ _| | | (_) / __ \ / ____| | | _ __| |__ _ ___ | | | | (___ | | | '__| '_ \| / __| | | | |\___ \ _| |_| | | |_) | \__ \ | |__| |____) | |_____|_| |_.__/|_|___/ \____/|_____/ EOF echo -e "${NC}" echo -e "${GREEN}${BOLD}======================================================================${NC}" echo -e "${GREEN}${BOLD} 🐾 INSTALLATEUR IRBIS OS POUR RASPBERRY PI OS (RPi 4 & 5) ${NC}" echo -e "${GREEN}${BOLD}======================================================================${NC}" echo -e " Architecture cible : ${BOLD}ARM64 (aarch64)${NC}" echo -e " Version recommandée: ${BOLD}v1.9.5.13${NC}" echo -e " Support officiel : Raspberry Pi 4 Model B, Pi 400 & Raspberry Pi 5" echo -e "${GREEN}${BOLD}======================================================================${NC}\n" # 1. Vérification des Privilèges Root if [ "$EUID" -ne 0 ]; then echo -e "${RED}${BOLD}[ERREUR]${NC} Ce script doit être exécuté avec les privilèges d'administrateur (root)." echo -e "Veuillez relancer avec : ${BOLD}sudo bash install-rpi.sh${NC} ou via curl avec ${BOLD}| sudo bash${NC}." exit 1 fi # 2. Vérification de l'Architecture Matérielle ARCH="$(uname -m)" if [ "$ARCH" != "aarch64" ] && [ "$ARCH" != "arm64" ]; then echo -e "${YELLOW}[ATTENTION]${NC} Architecture détectée : ${ARCH}." echo -e "Raspberry Pi OS 64-bit (aarch64) est fortement recommandé pour Irbis OS." fi # Détection du modèle de Raspberry Pi RPI_MODEL="Inconnu" if [ -f /proc/device-tree/model ]; then RPI_MODEL="$(tr -d '\0' < /proc/device-tree/model)" fi echo -e "${CYAN}[*]${NC} Matériel détecté : ${BOLD}${RPI_MODEL}${NC} (${ARCH})" TARGET_VERSION="${IRBIS_VERSION:-1.9.5.13}" INSTALL_DIR="/opt/irbis-os" STORAGE_DIR="/mnt/storage" GITEA_BASE_URL="https://git.nebulia.tech/SlyderSlash/Irbis_OS-Release/releases/download/v${TARGET_VERSION}" ARCHIVE_NAME="irbis-os-update-${TARGET_VERSION}.tar.gz" DOWNLOAD_URL="${GITEA_BASE_URL}/${ARCHIVE_NAME}" # 3. Mise à jour des paquets et dépendances système echo -e "\n${GREEN}${BOLD}[1/6] Mise à jour du système et installation des dépendances...${NC}" export DEBIAN_FRONTEND=noninteractive apt-get update -y apt-get install -y --no-install-recommends \ curl \ wget \ ca-certificates \ gnupg \ lsb-release \ git \ tar \ unzip \ rsync \ jq \ htop \ btrfs-progs \ util-linux \ e2fsprogs \ parted \ smartmontools \ mdadm \ avahi-daemon \ avahi-utils \ libnss-mdns \ samba \ samba-common-bin \ apparmor \ apparmor-utils \ nginx \ certbot \ python3-certbot-nginx \ libheif-examples \ imagemagick \ ffmpeg \ mpg123 \ alsa-utils \ pulseaudio-utils \ smbclient # Installation / Configuration de Docker & Docker Compose echo -e "\n${GREEN}${BOLD}[+] Configuration et installation de Docker & Docker Compose...${NC}" DOCKER_OK=false if command -v docker >/dev/null 2>&1 && (docker compose version >/dev/null 2>&1 || docker-compose version >/dev/null 2>&1); then DOCKER_OK=true echo -e " ✅ Docker et Docker Compose sont déjà installés." fi if [ "$DOCKER_OK" = false ]; then echo -e " ⚙️ Installation de Docker officiel via get.docker.com..." if curl -fsSL https://get.docker.com -o /tmp/get-docker.sh; then sh /tmp/get-docker.sh rm -f /tmp/get-docker.sh else echo -e " ⚠️ Fallback : configuration manuelle du dépôt Docker Debian..." install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable" > /etc/apt/sources.list.d/docker.list apt-get update -y apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || apt-get install -y docker.io docker-compose fi fi # Création du lien symbolique docker-compose pour compatibilité if command -v docker >/dev/null 2>&1 && ! command -v docker-compose >/dev/null 2>&1; then if [ -f /usr/libexec/docker/cli-plugins/docker-compose ]; then ln -sf /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose fi fi # Activation et démarrage de Docker et Avahi systemctl enable --now docker.service || true systemctl enable --now avahi-daemon.service || true # 4. Installation de Node.js 24 LTS et PNPM echo -e "\n${GREEN}${BOLD}[2/6] Vérification et installation de Node.js 24 LTS...${NC}" NODE_OK=false if command -v node >/dev/null 2>&1; then NODE_VER="$(node -v | sed 's/v//' | cut -d'.' -f1)" if [ "$NODE_VER" -ge 24 ]; then NODE_OK=true echo -e " ✅ Node.js $(node -v) déjà installé et conforme (>= 24)." fi fi if [ "$NODE_OK" = false ]; then echo -e " ⚙️ Installation de Node.js 24.x depuis le dépôt officiel NodeSource..." mkdir -p /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg 2>/dev/null || true echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main" > /etc/apt/sources.list.d/nodesource.list apt-get update -y apt-get install -y --allow-downgrades nodejs echo -e " ✅ Node.js $(node -v) installé avec succès !" fi # Installation globale de PNPM if ! command -v pnpm >/dev/null 2>&1; then echo -e " ⚙️ Installation globale de pnpm..." npm install -g pnpm@10.33.2 || npm install -g pnpm fi echo -e " ✅ PNPM $(pnpm -v 2>/dev/null || echo 'ok') prêt." # 5. Création des Répertoires et Montage Automatique du Stockage echo -e "\n${GREEN}${BOLD}[3/6] Préparation de l'arborescence et détection du stockage (${STORAGE_DIR})...${NC}" mkdir -p "${INSTALL_DIR}" mkdir -p "${INSTALL_DIR}/config" mkdir -p "${INSTALL_DIR}/logs" mkdir -p "${STORAGE_DIR}" # Vérification et montage automatique de la partition de données si /mnt/storage n'est pas encore monté if ! findmnt -n /mnt/storage >/dev/null 2>&1; then DATA_PART=$(lsblk -rn -o NAME,FSTYPE | awk '$2=="btrfs" {print "/dev/"$1; exit}') if [ -z "$DATA_PART" ]; then DATA_PART=$(lsblk -rn -o NAME,LABEL | awk '$2 ~ /(data|storage|irbis)/ {print "/dev/"$1; exit}') fi if [ -n "$DATA_PART" ] && [ -b "$DATA_PART" ]; then echo -e " 💾 Partition de données détectée : ${DATA_PART}. Montage sur ${STORAGE_DIR}..." mount -o defaults,noatime,compress=zstd "${DATA_PART}" "${STORAGE_DIR}" 2>/dev/null || mount "${DATA_PART}" "${STORAGE_DIR}" 2>/dev/null || true DATA_UUID=$(blkid -s UUID -o value "${DATA_PART}" 2>/dev/null || true) if [ -n "$DATA_UUID" ] && ! grep -q "${STORAGE_DIR}" /etc/fstab; then echo "UUID=${DATA_UUID} ${STORAGE_DIR} btrfs defaults,noatime,compress=zstd 0 2" >> /etc/fstab echo -e " ✅ Point de montage ${STORAGE_DIR} ajouté dans /etc/fstab." fi fi fi mkdir -p "${STORAGE_DIR}/users/admin/Notes" mkdir -p "${STORAGE_DIR}/system" # Configuration des permissions Samba et Stockage chmod -R 775 "${STORAGE_DIR}" 2>/dev/null || true # Configuration Samba pour Obsidian, Irbis Notes et partage réseau macOS/Windows cat << 'EOF' > /etc/samba/smb.conf [global] workgroup = WORKGROUP server string = Irbis OS Storage server role = standalone server security = user map to guest = Bad User min protocol = SMB2_10 vfs objects = fruit streams_xattr fruit:metadata = stream fruit:model = Macmini [Notes] comment = Coffre Irbis Notes & Obsidian path = /mnt/storage/users/admin/Notes browseable = yes read only = no guest ok = yes create mask = 0775 directory mask = 0775 [Home] comment = Espace Personnel path = /mnt/storage/users/%U browseable = yes read only = no valid users = %U, admin create mask = 0770 directory mask = 0770 [Admin-Storage] comment = Stockage Global Système (Admin Uniquement) path = /mnt/storage browseable = yes read only = no valid users = admin create mask = 0775 directory mask = 0775 EOF systemctl restart smbd.service 2>/dev/null || systemctl restart samba.service 2>/dev/null || true # 6. Téléchargement et Déploiement du Paquet Irbis OS echo -e "\n${GREEN}${BOLD}[4/6] Déploiement d'Irbis OS v${TARGET_VERSION}...${NC}" ARCHIVE_PATH="/tmp/${ARCHIVE_NAME}" DOWNLOAD_SUCCESS=false # Vérification si l'archive est déjà présente localement (ex: test local) if [ -f "./${ARCHIVE_NAME}" ]; then echo -e " 📦 Archive trouvée localement dans le dossier courant." cp "./${ARCHIVE_NAME}" "${ARCHIVE_PATH}" DOWNLOAD_SUCCESS=true elif [ -f "./dist_release/${ARCHIVE_NAME}" ]; then echo -e " 📦 Archive trouvée dans dist_release." cp "./dist_release/${ARCHIVE_NAME}" "${ARCHIVE_PATH}" DOWNLOAD_SUCCESS=true else echo -e " 🌐 Téléchargement de l'archive officielle depuis Gitea :" echo -e " 👉 ${DOWNLOAD_URL}" if curl -fSL --progress-bar "${DOWNLOAD_URL}" -o "${ARCHIVE_PATH}"; then DOWNLOAD_SUCCESS=true else echo -e "${YELLOW}[!] Téléchargement direct échoué, essai avec fallback release...${NC}" FALLBACK_URL="https://git.nebulia.tech/SlyderSlash/Irbis_OS-Release/raw/branch/main/irbis-os-update-${TARGET_VERSION}.tar.gz" if curl -fSL "${FALLBACK_URL}" -o "${ARCHIVE_PATH}"; then DOWNLOAD_SUCCESS=true fi fi fi if [ "$DOWNLOAD_SUCCESS" = true ] && [ -f "${ARCHIVE_PATH}" ]; then # Sauvegarde préventive des identités (utilisateurs, groupes et configurations existantes) [ -f "/etc/irbis-os/users.json" ] && cp -f /etc/irbis-os/users.json /tmp/irbis_users_backup.json 2>/dev/null || true [ -f "/etc/irbis-os/groups.json" ] && cp -f /etc/irbis-os/groups.json /tmp/irbis_groups_backup.json 2>/dev/null || true [ -f "/etc/irbis-os/config.json" ] && cp -f /etc/irbis-os/config.json /tmp/irbis_config_backup.json 2>/dev/null || true echo -e " 📦 Extraction des fichiers dans ${INSTALL_DIR}..." tar --warning=no-unknown-keyword -xzf "${ARCHIVE_PATH}" -C "${INSTALL_DIR}" 2>/dev/null || tar -xzf "${ARCHIVE_PATH}" -C "${INSTALL_DIR}" rm -f "${ARCHIVE_PATH}" # Restauration garantie des utilisateurs et groupes mkdir -p /etc/irbis-os [ -f "/tmp/irbis_users_backup.json" ] && cp -f /tmp/irbis_users_backup.json /etc/irbis-os/users.json 2>/dev/null || true [ -f "/tmp/irbis_groups_backup.json" ] && cp -f /tmp/irbis_groups_backup.json /etc/irbis-os/groups.json 2>/dev/null || true [ -f "/tmp/irbis_config_backup.json" ] && cp -f /tmp/irbis_config_backup.json /etc/irbis-os/config.json 2>/dev/null || true else echo -e "${RED}${BOLD}[ERREUR]${NC} Impossible de récupérer l'archive Irbis OS v${TARGET_VERSION}." echo -e "Vérifiez votre connexion internet ou téléchargez manuellement l'archive dans /tmp." exit 1 fi # Installation des dépendances Node de production echo -e " 📦 Installation des dépendances Node de production..." cd "${INSTALL_DIR}" # Liaison locale propre du package partagé @irbis-os/shared mkdir -p "${INSTALL_DIR}/apps/backend/node_modules/@irbis-os" ln -sf "${INSTALL_DIR}/packages/shared" "${INSTALL_DIR}/apps/backend/node_modules/@irbis-os/shared" # Remplacement de workspace:* par file:../../packages/shared pour compatibilité npm/pnpm sans blocage semver if [ -f "${INSTALL_DIR}/apps/backend/package.json" ]; then sed -i 's/"workspace:\*"/"file:..\/..\/packages\/shared"/g' "${INSTALL_DIR}/apps/backend/package.json" 2>/dev/null || true cd "${INSTALL_DIR}/apps/backend" npm install --omit=dev --no-audit --no-fund 2>/dev/null || npm install --omit=dev || pnpm install --prod --no-frozen-lockfile || true fi # Copie de l'utilitaire CLI Irbis OS if [ -f "${INSTALL_DIR}/scripts/bin/irbis" ]; then cp -f "${INSTALL_DIR}/scripts/bin/irbis" /usr/local/bin/irbis chmod +x /usr/local/bin/irbis fi # 7. Création et Activation du Service Systemd echo -e "\n${GREEN}${BOLD}[5/6] Configuration du daemon système Irbis OS (systemd)...${NC}" cat << 'EOF' > /etc/systemd/system/irbis-os.service [Unit] Description=Irbis OS Appliance Daemon (Raspberry Pi OS) After=network.target docker.service avahi-daemon.service Wants=docker.service avahi-daemon.service [Service] Type=simple User=root WorkingDirectory=/opt/irbis-os/apps/backend ExecStart=/usr/bin/node dist/index.js Restart=always RestartSec=5 Environment=NODE_ENV=production Environment=PORT=4000 Environment=IRBIS_DEVICE_ARCH=arm64 Environment=STORAGE_PATH=/mnt/storage Environment="NODE_PATH=/opt/irbis-os/node_modules:/opt/irbis-os/apps/backend/node_modules" SupplementaryGroups=docker disk [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable irbis-os.service systemctl restart irbis-os.service # Configuration de la bannière TTY pour affichage sur l'écran HDMI cat << 'EOF' > /etc/issue ====================================================================== 🐾 Irbis OS Appliance - Raspberry Pi OS Edition ====================================================================== Tableau de bord Web : http://irbis-nas.local:4000 Accès via IP : http://\4:4000 ====================================================================== EOF # 8. Vérification finale et Santé du Service echo -e "\n${GREEN}${BOLD}[6/6] Vérification du bon démarrage des services...${NC}" echo -e " ⏳ Attente de l'initialisation du démon Irbis OS (5 secondes)..." sleep 5 IS_HEALTHY=false for i in {1..15}; do if curl -s "http://127.0.0.1:4000/api/health" >/dev/null 2>&1; then IS_HEALTHY=true break fi sleep 1 done # Affichage automatique du dashboard en direct (irbis status) echo -e "\n${CYAN}${BOLD}[*] Affichage du statut en direct du système Irbis OS :${NC}\n" if command -v irbis >/dev/null 2>&1; then irbis status || true elif [ -f "${INSTALL_DIR}/scripts/bin/irbis" ]; then bash "${INSTALL_DIR}/scripts/bin/irbis" status || true fi # Récupération de l'adresse IP locale LOCAL_IP="$(hostname -I | awk '{print $1}')" echo -e "\n${GREEN}${BOLD}======================================================================${NC}" if [ "$IS_HEALTHY" = true ]; then echo -e "${GREEN}${BOLD} 🎉 FÉLICITATIONS ! IRBIS OS EST OPÉRATIONNEL SUR VOTRE RASPBERRY PI ! ${NC}" else echo -e "${YELLOW}${BOLD} ⚠️ IRBIS OS EST DÉPLOYÉ ET EN COURS D'INITIALISATION INITIALE ${NC}" fi echo -e "${GREEN}${BOLD}======================================================================${NC}" echo -e " 🌐 Accès Dashboard Web : ${CYAN}${BOLD}http://irbis-nas.local:4000${NC}" if [ -n "$LOCAL_IP" ]; then echo -e " 🌐 Accès direct par IP : ${CYAN}${BOLD}http://${LOCAL_IP}:4000${NC}" fi echo -e " 📁 Dossier d'installation: ${INSTALL_DIR}" echo -e " 💾 Stockage persistant : ${STORAGE_DIR}" echo -e " 🛠️ Commande de contrôle : ${BOLD}irbis status${NC} ou ${BOLD}systemctl status irbis-os${NC}" echo -e "${GREEN}${BOLD}======================================================================${NC}\n" # Proposition de redémarrage propre sécurisée (lecture via /dev/tty pour éviter d'absorber le flux stdin lors d'un curl | bash) REPLY="" if [ -c /dev/tty ]; then read -p "Voulez-vous redémarrer le Raspberry Pi maintenant pour finaliser tous les services ? (o/N) : " -n 1 -r REPLY < /dev/tty || true echo "" fi if [[ "$REPLY" =~ ^[Oo]$ ]]; then echo -e "\n${CYAN}[*] Redémarrage en cours... Rendez-vous sur http://irbis-nas.local:4000 dans 30 secondes !${NC}" reboot fi