Add Docker/Compose always-check and SSH key import to AI stack setup
- Docker + Docker Compose check now runs on every invocation (not skipped on updates), installing if missing — ensures the stack can always run - Added Docker Compose plugin install as fallback if compose is missing - NVIDIA Container Toolkit check also always runs (not update-gated) - Added SSH key import wizard question: import public keys from GitHub (gh:username) and/or Launchpad (lp:username) using ssh-import-id, so the machine is accessible over SSH immediately after setup https://claude.ai/code/session_012gDnantBmFTWZGCiKyjazx
This commit is contained in:
+67
-29
@@ -137,13 +137,31 @@ fi
|
|||||||
$INSTALL_AI || $INSTALL_KIWIX || $INSTALL_POSTINSTALL \
|
$INSTALL_AI || $INSTALL_KIWIX || $INSTALL_POSTINSTALL \
|
||||||
|| die "Nothing selected — run again and select at least one option."
|
|| die "Nothing selected — run again and select at least one option."
|
||||||
|
|
||||||
|
# ── Q1b: SSH keys from GitHub / Launchpad ─────────────────────────────────────
|
||||||
|
SSH_IMPORT_IDS=() # list of "gh:username" or "lp:username" entries
|
||||||
|
|
||||||
|
if ! $IS_UPDATE || [[ ! -f "$HOME/.ssh/authorized_keys" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${BOLD}[SSH] Import SSH public keys? (for passwordless SSH into this machine)${NC}"
|
||||||
|
echo " Pulls your public keys from GitHub or Launchpad and adds them to"
|
||||||
|
echo " ~/.ssh/authorized_keys using ssh-import-id."
|
||||||
|
echo ""
|
||||||
|
echo " Examples: gh:yourusername lp:yourlaunchpadid"
|
||||||
|
echo " Multiple: gh:alice lp:alice"
|
||||||
|
echo ""
|
||||||
|
read -rp " Usernames (or Enter to skip): " SSH_INPUT
|
||||||
|
if [[ -n "$SSH_INPUT" ]]; then
|
||||||
|
read -ra SSH_IMPORT_IDS <<< "$SSH_INPUT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Q2: Storage for Ollama models ─────────────────────────────────────────────
|
# ── Q2: Storage for Ollama models ─────────────────────────────────────────────
|
||||||
OLLAMA_STORAGE="volume" # "volume" = Docker named volume, else a host path
|
OLLAMA_STORAGE="volume" # "volume" = Docker named volume, else a host path
|
||||||
OLLAMA_HOST_PATH=""
|
OLLAMA_HOST_PATH=""
|
||||||
|
|
||||||
if $INSTALL_AI; then
|
if $INSTALL_AI; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}[2/5] Where should Ollama models be stored?${NC}"
|
echo -e " ${BOLD}[2/6] Where should Ollama models be stored?${NC}"
|
||||||
echo " (Models are large — 5-50GB each. A fast SSD or large HDD is ideal.)"
|
echo " (Models are large — 5-50GB each. A fast SSD or large HDD is ideal.)"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Available mount points with >20GB free:"
|
echo " Available mount points with >20GB free:"
|
||||||
@@ -172,7 +190,7 @@ KIWIX_DIR="$BASE/kiwix" # default
|
|||||||
|
|
||||||
if $INSTALL_KIWIX; then
|
if $INSTALL_KIWIX; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}[3/5] Where should Kiwix ZIM files be stored?${NC}"
|
echo -e " ${BOLD}[3/6] Where should Kiwix ZIM files be stored?${NC}"
|
||||||
echo " (ZIMs are large — Wikipedia alone is ~46GB. Total collection ~130GB.)"
|
echo " (ZIMs are large — Wikipedia alone is ~46GB. Total collection ~130GB.)"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Available mount points with >50GB free:"
|
echo " Available mount points with >50GB free:"
|
||||||
@@ -191,7 +209,7 @@ if $INSTALL_KIWIX; then
|
|||||||
|
|
||||||
# ── Q4: Download ZIMs now? ─────────────────────────────────────────────────
|
# ── Q4: Download ZIMs now? ─────────────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}[4/5] Download ZIM files? (offline Wikipedia, Stack Overflow, etc.)${NC}"
|
echo -e " ${BOLD}[4/6] Download ZIM files? (offline Wikipedia, Stack Overflow, etc.)${NC}"
|
||||||
echo " Downloads run in the background — safe to start now and leave overnight."
|
echo " Downloads run in the background — safe to start now and leave overnight."
|
||||||
echo " Total: ~130GB (Wikipedia 46GB, Project Gutenberg 60GB, others smaller)"
|
echo " Total: ~130GB (Wikipedia 46GB, Project Gutenberg 60GB, others smaller)"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -211,7 +229,7 @@ if command -v ufw &>/dev/null && { [[ ! -f "$BASE/.ufw-done" ]] || $FORCE; }; th
|
|||||||
echo ""
|
echo ""
|
||||||
# Auto-detect likely subnet from current IP
|
# Auto-detect likely subnet from current IP
|
||||||
AUTO_SUBNET=$(echo "$LOCAL_IP" | awk -F. '{print $1"."$2"."$3".0/24"}')
|
AUTO_SUBNET=$(echo "$LOCAL_IP" | awk -F. '{print $1"."$2"."$3".0/24"}')
|
||||||
echo -e " ${BOLD}[4b] Firewall — allow LAN access to services${NC}"
|
echo -e " ${BOLD}[4b/6] Firewall — allow LAN access to services${NC}"
|
||||||
read -rp " LAN subnet [${AUTO_SUBNET}]: " LAN_INPUT
|
read -rp " LAN subnet [${AUTO_SUBNET}]: " LAN_INPUT
|
||||||
LAN_SUBNET="${LAN_INPUT:-$AUTO_SUBNET}"
|
LAN_SUBNET="${LAN_INPUT:-$AUTO_SUBNET}"
|
||||||
[[ "$LAN_SUBNET" =~ /[0-9]+$ ]] || LAN_SUBNET="${LAN_SUBNET}/24"
|
[[ "$LAN_SUBNET" =~ /[0-9]+$ ]] || LAN_SUBNET="${LAN_SUBNET}/24"
|
||||||
@@ -223,7 +241,7 @@ PULL_DEEPSEEK=false
|
|||||||
|
|
||||||
if $INSTALL_AI; then
|
if $INSTALL_AI; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}[5/5] Download AI models now?${NC}"
|
echo -e " ${BOLD}[5/6] Download AI models now?${NC}"
|
||||||
echo " GPU detected: ${GPU_NAME} (${VRAM_GB}GB VRAM) → recommended tier: ${GPU_TIER}"
|
echo " GPU detected: ${GPU_NAME} (${VRAM_GB}GB VRAM) → recommended tier: ${GPU_TIER}"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Models that will be downloaded:"
|
echo " Models that will be downloaded:"
|
||||||
@@ -248,6 +266,7 @@ echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━
|
|||||||
echo ""
|
echo ""
|
||||||
$INSTALL_POSTINSTALL && echo " ✓ Full system setup (ubuntu-post-install.sh — interactive)"
|
$INSTALL_POSTINSTALL && echo " ✓ Full system setup (ubuntu-post-install.sh — interactive)"
|
||||||
$INSTALL_AI && echo " ✓ AI stack (Ollama · WebUI · RAG · MCP · Gitea · InvokeAI · Portainer)"
|
$INSTALL_AI && echo " ✓ AI stack (Ollama · WebUI · RAG · MCP · Gitea · InvokeAI · Portainer)"
|
||||||
|
[[ "${#SSH_IMPORT_IDS[@]}" -gt 0 ]] && echo " ✓ SSH keys → ${SSH_IMPORT_IDS[*]}"
|
||||||
$INSTALL_KIWIX && echo " ✓ Kiwix offline library"
|
$INSTALL_KIWIX && echo " ✓ Kiwix offline library"
|
||||||
if $INSTALL_AI; then
|
if $INSTALL_AI; then
|
||||||
if [[ "$OLLAMA_STORAGE" == "bind" ]]; then
|
if [[ "$OLLAMA_STORAGE" == "bind" ]]; then
|
||||||
@@ -297,21 +316,28 @@ fi
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
section "Prerequisites"
|
section "Prerequisites"
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
if ! $IS_UPDATE; then
|
|
||||||
|
|
||||||
# Docker
|
# ── Docker (always check — required whether new install or update) ─────────────
|
||||||
if ! command -v docker &>/dev/null; then
|
if ! command -v docker &>/dev/null; then
|
||||||
info "Installing Docker..."
|
info "Installing Docker..."
|
||||||
curl -fsSL https://get.docker.com | sh
|
curl -fsSL https://get.docker.com | sh
|
||||||
sudo usermod -aG docker "$USER"
|
sudo usermod -aG docker "$USER"
|
||||||
ok "Docker installed — log out/in or run: newgrp docker"
|
warn "Added $USER to docker group — changes take effect on next login."
|
||||||
else
|
warn "If docker commands fail, run: newgrp docker"
|
||||||
ok "Docker: $(docker --version)"
|
else
|
||||||
fi
|
ok "Docker: $(docker --version | sed 's/Docker version //')"
|
||||||
|
fi
|
||||||
|
|
||||||
# NVIDIA Container Toolkit
|
# Ensure Docker Compose plugin is present (included with modern Docker)
|
||||||
if command -v nvidia-smi &>/dev/null && \
|
if ! docker compose version &>/dev/null; then
|
||||||
! dpkg -l 2>/dev/null | grep -q nvidia-container-toolkit; then
|
info "Installing docker-compose-plugin..."
|
||||||
|
sudo apt-get install -y docker-compose-plugin
|
||||||
|
fi
|
||||||
|
ok "Docker Compose: $(docker compose version --short 2>/dev/null || echo 'ok')"
|
||||||
|
|
||||||
|
# ── NVIDIA Container Toolkit ───────────────────────────────────────────────────
|
||||||
|
if command -v nvidia-smi &>/dev/null; then
|
||||||
|
if ! dpkg -l 2>/dev/null | grep -q nvidia-container-toolkit; then
|
||||||
info "Installing NVIDIA Container Toolkit..."
|
info "Installing NVIDIA Container Toolkit..."
|
||||||
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
|
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
|
||||||
| sudo gpg --dearmor --yes \
|
| sudo gpg --dearmor --yes \
|
||||||
@@ -324,20 +350,32 @@ if ! $IS_UPDATE; then
|
|||||||
sudo nvidia-ctk runtime configure --runtime=docker
|
sudo nvidia-ctk runtime configure --runtime=docker
|
||||||
sudo systemctl restart docker
|
sudo systemctl restart docker
|
||||||
ok "NVIDIA Container Toolkit installed"
|
ok "NVIDIA Container Toolkit installed"
|
||||||
elif command -v nvidia-smi &>/dev/null; then
|
|
||||||
ok "NVIDIA Container Toolkit already present"
|
|
||||||
else
|
else
|
||||||
warn "No NVIDIA GPU detected — CPU-only (Ollama will use CPU)"
|
ok "NVIDIA Container Toolkit: already present"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ripgrep (used by MCP search_code tool)
|
|
||||||
if ! command -v rg &>/dev/null; then
|
|
||||||
sudo apt-get install -y ripgrep
|
|
||||||
ok "ripgrep installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
else
|
||||||
ok "Skipping prereq checks (update mode)"
|
info "No NVIDIA GPU detected — Ollama will run on CPU"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── ripgrep (used by MCP search_code tool) ─────────────────────────────────────
|
||||||
|
if ! command -v rg &>/dev/null; then
|
||||||
|
sudo apt-get install -y ripgrep
|
||||||
|
ok "ripgrep installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── SSH key import from GitHub / Launchpad ─────────────────────────────────────
|
||||||
|
if [[ "${#SSH_IMPORT_IDS[@]}" -gt 0 ]]; then
|
||||||
|
section "SSH Keys"
|
||||||
|
if ! command -v ssh-import-id &>/dev/null; then
|
||||||
|
info "Installing ssh-import-id..."
|
||||||
|
sudo apt-get install -y ssh-import-id
|
||||||
|
fi
|
||||||
|
mkdir -p "$HOME/.ssh"
|
||||||
|
chmod 700 "$HOME/.ssh"
|
||||||
|
for id in "${SSH_IMPORT_IDS[@]}"; do
|
||||||
|
info "Importing SSH keys: $id"
|
||||||
|
ssh-import-id "$id" && ok "Keys imported: $id" || warn "Failed to import: $id"
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user