diff --git a/install.sh b/install.sh index b405360..e8353b3 100755 --- a/install.sh +++ b/install.sh @@ -9,7 +9,14 @@ set -euo pipefail readonly UNBOUND_PORT=5335 readonly NETALERTX_PORT=20211 readonly PYTHON_SUITE_PORT=8090 +readonly NETALERTX_IMAGE="jokobsk/netalertx:latest" +readonly SUITE_API_KEY_ENV="${SUITE_API_KEY:-}" +readonly SUITE_LOG_LEVEL_ENV="${SUITE_LOG_LEVEL:-INFO}" +readonly INSTALL_USER=${SUDO_USER:-$(whoami)} readonly PROJECT_DIR="$(pwd)" +readonly RESOLV_CONF="/etc/resolv.conf" +readonly RESOLV_CONF_BACKUP="/etc/resolv.conf.pi-hole-installer.bak" +readonly -a FALLBACK_RESOLVERS=("1.1.1.1" "9.9.9.9") # ๐ŸŽจ Colors RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' @@ -22,7 +29,24 @@ error() { echo -e "${RED}[โœ—]${NC} $*"; } step() { echo -e "\n${YELLOW}[STEP]${NC} $*"; } # ๐Ÿ›ก๏ธ Error handler -trap 'error "Installation failed. See logs above."' ERR +trap 'error "Installation failed. See logs above."; exit 1' ERR + +# --------------------------------------------------------------------------- +# ๐Ÿงช Helpers +write_resolv_conf() { + local file="$1"; shift + : >"$file" + for resolver in "$@"; do + printf 'nameserver %s\n' "$resolver" >>"$file" + done +} + +extract_env_value() { + local key="$1" file="$2" + if [[ -f "$file" ]]; then + grep -E "^${key}=" "$file" | tail -n1 | cut -d= -f2- + fi +} # --------------------------------------------------------------------------- # ๐Ÿ” System checks @@ -34,24 +58,72 @@ check_system() { success "System checks passed" } +# ๐Ÿงฐ Ubuntu resolver handling (Port 53) +handle_systemd_resolved() { + step "Checking systemd-resolved on Ubuntu (port 53)" + if [[ -r /etc/os-release ]]; then + # shellcheck disable=SC1091 + . /etc/os-release + if [[ "${ID:-}" == ubuntu* || "${ID_LIKE:-}" == *ubuntu* ]]; then + if systemctl list-unit-files | grep -q '^systemd-resolved\.service'; then + if systemctl is-active --quiet systemd-resolved; then + warn "systemd-resolved is active; stopping to free port 53" + systemctl stop systemd-resolved || true + fi + systemctl disable systemd-resolved || true + if [[ -L $RESOLV_CONF ]]; then + warn "$RESOLV_CONF is a symlink; replacing with static resolver" + if [[ ! -e $RESOLV_CONF_BACKUP ]]; then + mv -f "$RESOLV_CONF" "$RESOLV_CONF_BACKUP" + else + rm -f "$RESOLV_CONF" + fi + fi + write_resolv_conf "$RESOLV_CONF" "${FALLBACK_RESOLVERS[@]}" + fi + fi + fi + success "Resolver prepared with external fallbacks" +} + +finalize_resolver_configuration() { + log "Pointing system resolver to Pi-hole" + local resolvers=("127.0.0.1" "${FALLBACK_RESOLVERS[@]}") + write_resolv_conf "$RESOLV_CONF" "${resolvers[@]}" + success "System resolver now prefers Pi-hole on 127.0.0.1" +} + +# ๐Ÿ”Œ Port conflicts check_ports() { step "Checking ports" local ports=($UNBOUND_PORT $NETALERTX_PORT $PYTHON_SUITE_PORT 53) - for port in "${ports[@]}"; do - if ss -tuln | grep -q ":$port "; then - warn "Port $port already in use" - fi - done + if command -v ss >/dev/null; then + for port in "${ports[@]}"; do + if ss -tuln | grep -q ":$port "; then + warn "Port $port already in use" + fi + done + elif command -v netstat >/dev/null; then + for port in "${ports[@]}"; do + if netstat -tuln | grep -q ":$port "; then + warn "Port $port already in use" + fi + done + else + warn "Neither ss nor netstat available; skipping port checks" + fi } # ๐Ÿ“ฆ Packages install_packages() { step "Installing system packages" apt-get update -qq - python3 python3-venv python3-pip git docker.io openssl systemd sqlite3 + apt-get install -y unbound ca-certificates curl dnsutils \ + python3 python3-venv python3-pip git docker.io openssl systemd sqlite3 iproute2 success "System packages installed" } +# ๐Ÿ” Unbound config configure_unbound() { step "Configuring Unbound" install -d -m 0755 /var/lib/unbound @@ -74,6 +146,7 @@ server: cache-max-ttl: 86400 trust-anchor-file: /var/lib/unbound/root.key root-hints: /var/lib/unbound/root.hints + tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt forward-zone: name: "." @@ -100,6 +173,7 @@ install_pihole() { sed -i "s/^PIHOLE_DNS_1=.*/PIHOLE_DNS_1=127.0.0.1#$UNBOUND_PORT/" /etc/pihole/setupVars.conf sed -i "s/^PIHOLE_DNS_2=.*/PIHOLE_DNS_2=/" /etc/pihole/setupVars.conf pihole restartdns + finalize_resolver_configuration success "Pi-hole configured with Unbound" } @@ -122,12 +196,33 @@ install_netalertx() { setup_python_suite() { step "Setting up Python suite" cd "$PROJECT_DIR" + # Ensure data directory exists and is writable by service user + install -d -m 0755 "$PROJECT_DIR/data" + chown -R "$INSTALL_USER:$INSTALL_USER" "$PROJECT_DIR/data" + [[ -d .venv ]] || sudo -u "$INSTALL_USER" python3 -m venv .venv sudo -u "$INSTALL_USER" .venv/bin/pip install -U pip sudo -u "$INSTALL_USER" .venv/bin/pip install -r requirements.txt sudo -u "$INSTALL_USER" .venv/bin/python scripts/bootstrap.py || true - cat > /etc/systemd/system/pihole-suite.service < "$env_file" < /etc/systemd/system/pihole-suite.service < .env <