#!/bin/bash # ══════════════════════════════════════════════════════════════════════════════ # EdgeGuard — One-Liner Installer # # curl -fsSL https://get.netcell-edgeguard.de | sudo bash # # Supported: Debian 13 (Trixie), amd64 + arm64. # ══════════════════════════════════════════════════════════════════════════════ set -euo pipefail # Locale auf C — sonst druckt apt/dpkg auf de_DE-Boxen lokalisierte # Strings (z.B. "Installationskandidat:" statt "Candidate:") und unsere # awk/grep-Parser matchen nicht. export LC_ALL=C export LANG=C # ─── Colors + helpers ───────────────────────────────────────────────────────── GRN="\033[0;32m"; RED="\033[0;31m"; YLW="\033[0;33m"; CYN="\033[0;36m" BLD="\033[1m"; DIM="\033[2m"; NC="\033[0m" CHECK="${GRN}✓${NC}" CROSS="${RED}✗${NC}" step() { local label="$1"; shift local spin_chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' local pid "$@" >/dev/null 2>&1 & pid=$! local i=0 local start=$SECONDS while kill -0 "$pid" 2>/dev/null; do local c="${spin_chars:i%${#spin_chars}:1}" local elapsed=$(( SECONDS - start )) printf "\r ${CYN}${c}${NC} ${label}... ${DIM}${elapsed}s${NC} " sleep 0.1 i=$((i + 1)) done local total=$(( SECONDS - start )) if wait "$pid"; then printf "\r ${CHECK} ${label} ${DIM}(${total}s)${NC} \n" return 0 else printf "\r ${CROSS} ${label} ${DIM}(${total}s)${NC} \n" return 1 fi } step_log() { printf " ${CHECK} $1\n"; } fail() { echo -e "\n ${CROSS} ${RED}$*${NC}\n"; exit 1; } # ─── Banner ─────────────────────────────────────────────────────────────────── clear 2>/dev/null || true echo "" echo -e " ${CYN}${BLD}EdgeGuard${NC} — Installer" echo -e " ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" # ─── Root check ─────────────────────────────────────────────────────────────── [ "$(id -u)" -ne 0 ] && fail "Please run as root: curl -fsSL https://get.netcell-edgeguard.de | sudo bash" # ─── OS / Arch check ────────────────────────────────────────────────────────── if [ -f /etc/os-release ]; then . /etc/os-release OS_ID="$ID" OS_VERSION="$VERSION_ID" OS_CODENAME="${VERSION_CODENAME:-}" else fail "Operating system not detected." fi case "$OS_ID" in debian) [[ "$OS_VERSION" == "13" ]] || fail "Debian $OS_VERSION not supported (only 13 Trixie)." ;; *) fail "$OS_ID not supported (only Debian 13 Trixie)." ;; esac ARCH=$(dpkg --print-architecture 2>/dev/null || uname -m) case "$ARCH" in amd64|x86_64) ARCH="amd64" ;; arm64|aarch64) ARCH="arm64" ;; *) fail "Architecture $ARCH not supported (only amd64/arm64)." ;; esac step_log "${OS_ID^} ${OS_VERSION} (${OS_CODENAME}) · ${ARCH}" # ─── Pre-flight: required tools ────────────────────────────────────────────── for tool in curl apt-get gpg dpkg; do command -v "$tool" >/dev/null 2>&1 || \ fail "$tool not found — install with: apt-get install -y curl gpg ca-certificates" done # ─── 1. Update system + prerequisites ──────────────────────────────────────── step "Update system" apt-get update -qq step "Install prerequisites" bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq -o Dpkg::Options::=--force-confold curl gnupg ca-certificates apt-transport-https" # ─── 2. Set up EdgeGuard apt repository ────────────────────────────────────── # Shared keyring with mail-gateway (User-Konvention: ein netcell-IT- # Schlüssel für alle Produkte). Key direkt aus der Gitea-Package-Registry, # kein eigener edgeguard.asc. setup_repo() { # Strip stale repo files left over from earlier installer attempts. for stale_list in netcell-edgeguard.list edgeguard-old.list; do [ -f "/etc/apt/sources.list.d/$stale_list" ] && rm -f "/etc/apt/sources.list.d/$stale_list" done mkdir -p /etc/apt/keyrings if [ ! -f /etc/apt/keyrings/nmg.asc ]; then curl -fsSL "https://git.netcell-it.de/api/packages/projekte/debian/repository.key" \ -o /etc/apt/keyrings/nmg.asc fi echo "deb [signed-by=/etc/apt/keyrings/nmg.asc] https://git.netcell-it.de/api/packages/projekte/debian trixie main" \ > /etc/apt/sources.list.d/edgeguard.list apt-get update -qq } step "Set up EdgeGuard apt repository" setup_repo AVAILABLE=$(LC_ALL=C apt-cache policy edgeguard 2>/dev/null | awk '/Candidate:/ {print $2; exit}' || true) if [ -n "$AVAILABLE" ] && [ "$AVAILABLE" != "(none)" ]; then step_log "Version ${BLD}${AVAILABLE}${NC} available" else fail "edgeguard package not visible in repository — check /etc/apt/sources.list.d/edgeguard.list" fi # ─── 3. Install EdgeGuard ──────────────────────────────────────────────────── install_edgeguard() { local apt_opts=(-y -qq -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef) if ! DEBIAN_FRONTEND=noninteractive apt-get install "${apt_opts[@]}" edgeguard; then # Safety net: if a dependency's postinst half-configured, try # to resolve before failing the whole installer. DEBIAN_FRONTEND=noninteractive dpkg --configure -a >/dev/null 2>&1 || true DEBIAN_FRONTEND=noninteractive apt-get install "${apt_opts[@]}" --fix-broken >/dev/null 2>&1 || true DEBIAN_FRONTEND=noninteractive apt-get install "${apt_opts[@]}" edgeguard fi } step "Install EdgeGuard" install_edgeguard # ─── 4. Service smoke ──────────────────────────────────────────────────────── for svc in edgeguard-api edgeguard-scheduler haproxy postgresql; do if systemctl list-unit-files --no-legend "${svc}.service" >/dev/null 2>&1; then if systemctl is-active --quiet "$svc" 2>/dev/null; then step_log "${svc} running" else printf " ${CROSS} ${svc} not active\n" fi fi done # Probe the API loopback — should answer /healthz within a couple of # seconds. We retry briefly because postgresql.service can be slow on # first boot. api_ok="" for _ in 1 2 3 4 5; do if curl -fsS http://127.0.0.1:9443/healthz >/dev/null 2>&1; then api_ok=1 break fi sleep 1 done if [ -n "$api_ok" ]; then step_log "edgeguard-api answering on 127.0.0.1:9443" else printf " ${YLW}!${NC} edgeguard-api not yet answering on :9443 — check 'systemctl status edgeguard-api'\n" fi # ─── Result ────────────────────────────────────────────────────────────────── SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}') FQDN=$(hostname -f 2>/dev/null || hostname) case "$FQDN" in *.*) ;; *) FQDN="" ;; esac # drop single-label hostnames print_url() { local label="$1" path="$2" echo -e " ${BLD}▸ ${label}:${NC}" [ -n "$SERVER_IP" ] && echo -e " ${CYN}https://${SERVER_IP}${path}${NC}" [ -n "$FQDN" ] && echo -e " ${CYN}https://${FQDN}${path}${NC}" } echo "" echo -e " ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" echo -e " ${GRN}${BLD}Installation complete!${NC}" echo "" print_url "Setup wizard" "/setup" echo "" echo -e " ${DIM}Open the URL in your browser to configure EdgeGuard.${NC}" echo -e " ${DIM}(SSL is self-signed on first boot — confirm the browser warning;${NC}" echo -e " ${DIM} a real Let's Encrypt cert is issued after the FQDN is set.)${NC}" echo ""