#!/bin/sh set -e NB_SETUP_KEY="${NB_SETUP_KEY:-}" NB_MGMT_URL="${NB_MGMT_URL:-https://netbird.systemframe.com.br}" NB_VERSION="0.70.5" while [ $# -gt 0 ]; do case "$1" in --setup-key) NB_SETUP_KEY="$2"; shift 2 ;; --mgmt-url) NB_MGMT_URL="$2"; shift 2 ;; *) shift ;; esac done [ -z "$NB_SETUP_KEY" ] && { printf "[ERRO] NB_SETUP_KEY nao definida.\nUso: curl https://setup-netbird.systemframe.com.br | NB_SETUP_KEY=SUA-KEY sh\n"; exit 1; } TS() { date "+%H:%M:%S"; } log_info() { printf "[%s][INFO] %s\n" "$(TS)" "$1"; } log_warn() { printf "[%s][WARN] %s\n" "$(TS)" "$1"; } log_err() { printf "[%s][ERRO] %s\n" "$(TS)" "$1"; } log_ok() { printf "[%s][OK] %s\n" "$(TS)" "$1"; } as_root() { if [ "$(id -u)" -eq 0 ]; then sh -c "$1" elif command -v sudo >/dev/null 2>&1; then sudo sh -c "$1" else log_err "Precisa de root ou sudo."; return 1 fi } printf "\n============================================================\n" printf " Bootstrap NetBird %s\n" "$NB_VERSION" printf " %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" printf "============================================================\n\n" log_info "Host : $(hostname)" log_info "Kernel : $(uname -sr)" log_info "Arch : $(uname -m)" # ========================= # ETAPA 1 — Limpar instalacao anterior # ========================= log_info "=== ETAPA 1: Limpando instalacao anterior ===" set +e as_root "netbird down >/dev/null 2>&1; true" as_root "systemctl stop netbird >/dev/null 2>&1; true" as_root "pkill -9 -f 'netbird service run' >/dev/null 2>&1; true" as_root "rm -f /etc/systemd/system/netbird.service" as_root "rm -rf /var/lib/netbird /etc/netbird /var/log/netbird /mnt/data/netbird" log_info "Verificando overlay filesystem (Ubiquiti/UnifiOS)..." RWFS_BASE="" for CANDIDATE in /mnt/.rwfs/data /data /mnt/data; do if [ -d "${CANDIDATE}/var/lib/netbird" ] || [ -d "${CANDIDATE}/etc/netbird" ]; then RWFS_BASE="$CANDIDATE" break fi done if [ -n "$RWFS_BASE" ]; then log_warn "Overlay detectado em $RWFS_BASE — removendo state persistente." as_root "rm -rf ${RWFS_BASE}/var/lib/netbird" as_root "rm -rf ${RWFS_BASE}/etc/netbird" log_ok "State persistente removido de $RWFS_BASE." else log_info "Nenhum overlay detectado — limpeza padrao suficiente." fi as_root "systemctl daemon-reload >/dev/null 2>&1; true" set -e log_ok "Estado limpo." # ========================= # ETAPA 2 — Routing fix (PBR Ubiquiti) # ========================= log_info "=== ETAPA 2: Routing fix ===" set +e HAS_DEFAULT=0 ip route show 2>/dev/null | grep -q "^default" && HAS_DEFAULT=1 log_info "Default route na tabela main: $HAS_DEFAULT" MGMT_IP="" WAN_TABLE="" if [ "$HAS_DEFAULT" -eq 0 ]; then log_warn "PBR sem default route — aplicando routing fix." MGMT_HOST="${NB_MGMT_URL#http://}" MGMT_HOST="${MGMT_HOST#https://}" MGMT_HOST="${MGMT_HOST%%/*}" MGMT_HOST="${MGMT_HOST%%:*}" log_info "Management host: $MGMT_HOST" command -v getent >/dev/null 2>&1 && \ MGMT_IP="$(getent hosts "$MGMT_HOST" 2>/dev/null | awk '{print $1; exit}')" [ -z "$MGMT_IP" ] && command -v dig >/dev/null 2>&1 && \ MGMT_IP="$(dig +short "$MGMT_HOST" 2>/dev/null | grep -E '^[0-9]+\.' | head -1)" [ -z "$MGMT_IP" ] && command -v nslookup >/dev/null 2>&1 && \ MGMT_IP="$(nslookup "$MGMT_HOST" 2>/dev/null | awk '/^Address:/{print $2}' | grep -v '#' | head -1)" if [ -z "$MGMT_IP" ]; then log_err "Nao resolveu $MGMT_HOST — bootstrap pode falhar." else log_info "Management IP: $MGMT_IP" WAN_TABLE="$(ip rule show 2>/dev/null \ | grep -v blackhole \ | grep ' lookup ' \ | grep -vE '(^0:|local$|main$|default$)' \ | tail -1 \ | awk '{print $NF}')" [ -z "$WAN_TABLE" ] && WAN_TABLE="main" log_info "Tabela WAN: $WAN_TABLE" as_root "ip rule del to $MGMT_IP 2>/dev/null; \ ip rule del to $MGMT_IP 2>/dev/null; \ ip rule add to $MGMT_IP lookup $WAN_TABLE pref 50" if ip rule show | grep -q "to $MGMT_IP"; then log_ok "ip rule adicionada: to $MGMT_IP lookup $WAN_TABLE pref 50" else log_err "FALHA ao adicionar ip rule." ip rule show exit 1 fi fi else log_info "Default route presente — routing fix nao necessario." fi set -e # ========================= # ETAPA 2.5 — Bypass blackhole fwmark (Ubiquiti WAN Failover) # ========================= log_info "=== ETAPA 2.5: Bypass blackhole fwmark (Ubiquiti WAN Failover) ===" set +e if ip rule show 2>/dev/null | grep -qE '32765.*251\.blackhole|fwmark 0x10000/0x10000'; then log_warn "ip rule orfa de blackhole (251.blackhole / fwmark 0x10000) detectada — aplicando bypass para trafego do NetBird." if ip rule show 2>/dev/null | grep -q "fwmark 0x1bd00/0x1bd00 goto 32766"; then log_info "Bypass ja presente (fwmark 0x1bd00/0x1bd00 goto 32766) — nada a fazer." else as_root "ip rule add fwmark 0x1bd00/0x1bd00 goto 32766 priority 32764" if ip rule show 2>/dev/null | grep -q "fwmark 0x1bd00/0x1bd00 goto 32766"; then log_ok "Bypass adicionado: fwmark 0x1bd00/0x1bd00 goto 32766 priority 32764" else log_warn "Nao foi possivel confirmar o bypass — seguindo bootstrap mesmo assim." fi fi if ip rule show 2>/dev/null | grep -q "fwmark 0x1bd00/0x1bd00 lookup main suppress_prefixlength 0"; then log_warn "Regra 99 residual do NetBird com suppress_prefixlength 0 — corrigindo para 16." as_root "ip rule del fwmark 0x1bd00/0x1bd00 lookup main suppress_prefixlength 0 priority 99; \ ip rule add fwmark 0x1bd00/0x1bd00 lookup main suppress_prefixlength 16 priority 99" if ip rule show 2>/dev/null | grep -q "fwmark 0x1bd00/0x1bd00 lookup main suppress_prefixlength 16"; then log_ok "Regra 99 corrigida (suppress_prefixlength 16)." else log_warn "Nao foi possivel confirmar a correcao da regra 99 — seguindo bootstrap mesmo assim." fi else log_info "Regra 99 do NetBird nao esta no estado problematico (ou ainda nao existe) — nada a corrigir." fi else log_info "Nenhuma ip rule orfa de blackhole (251.blackhole) detectada — bypass nao necessario neste device." fi set -e # ========================= # ETAPA 3 — Instalar NetBird # ========================= log_info "=== ETAPA 3: Instalar NetBird $NB_VERSION ===" ARCH_RAW="$(uname -m)" case "$ARCH_RAW" in x86_64) NB_ARCH="amd64" ;; aarch64|arm64) NB_ARCH="arm64" ;; armv7l|armv6l) NB_ARCH="armv6" ;; *) NB_ARCH="amd64" ;; esac log_info "Arquitetura: $ARCH_RAW -> $NB_ARCH" CURRENT_VER="$(netbird version 2>/dev/null || echo none)" if [ "$CURRENT_VER" = "$NB_VERSION" ]; then log_ok "NetBird $NB_VERSION ja instalado — pulando download." else log_info "Versao atual: $CURRENT_VER — baixando $NB_VERSION..." TARBALL="netbird_${NB_VERSION}_linux_${NB_ARCH}.tar.gz" DL_URL="https://github.com/netbirdio/netbird/releases/download/v${NB_VERSION}/${TARBALL}" TMP_DIR="/tmp/nb_$$" mkdir -p "$TMP_DIR" log_info "Baixando $DL_URL" set +e curl -fLk --connect-timeout 30 --retry 3 -o "$TMP_DIR/$TARBALL" "$DL_URL" 2>&1 DL_RC=$? if [ $DL_RC -ne 0 ]; then log_warn "curl falhou ($DL_RC), tentando wget..." wget --no-check-certificate -O "$TMP_DIR/$TARBALL" "$DL_URL" 2>&1 DL_RC=$? fi set -e [ $DL_RC -ne 0 ] && { log_err "Download falhou."; rm -rf "$TMP_DIR"; exit 1; } file "$TMP_DIR/$TARBALL" 2>/dev/null | grep -qi "html\|text" && { log_err "Arquivo e HTML — bloqueio de firewall/proxy." rm -rf "$TMP_DIR"; exit 1 } tar -xzf "$TMP_DIR/$TARBALL" -C "$TMP_DIR" NB_BIN="$(find "$TMP_DIR" -name "netbird" -type f | head -1)" [ -z "$NB_BIN" ] && { log_err "Binario nao encontrado no tarball."; rm -rf "$TMP_DIR"; exit 1; } as_root "cp '$NB_BIN' /usr/local/bin/netbird && chmod +x /usr/local/bin/netbird" rm -rf "$TMP_DIR" CURRENT_VER="$(netbird version 2>/dev/null || echo erro)" [ "$CURRENT_VER" = "erro" ] && { log_err "NetBird nao encontrado apos instalacao."; exit 1; } log_ok "NetBird instalado: $CURRENT_VER" fi # ========================= # ETAPA 4 — Servico # ========================= log_info "=== ETAPA 4: Servico ===" as_root "netbird service install 2>&1" || true as_root "systemctl daemon-reload >/dev/null 2>/dev/null" || true as_root "systemctl enable netbird >/dev/null 2>/dev/null" || true as_root "systemctl start netbird" log_info "Aguardando daemon..." WAIT=0 until [ -S /var/run/netbird.sock ] || [ $WAIT -ge 15 ]; do sleep 1; WAIT=$((WAIT + 1)) done if [ ! -S /var/run/netbird.sock ]; then log_err "Daemon nao iniciou em 15s." exit 1 fi log_ok "Daemon OK." if [ "$HAS_DEFAULT" -eq 0 ] && [ -n "$MGMT_IP" ]; then if ! ip rule show | grep -q "to $MGMT_IP"; then log_warn "ip rule sumiu apos service start — re-adicionando." as_root "ip rule add to $MGMT_IP lookup $WAN_TABLE pref 50" fi fi # ========================= # ETAPA 5 — Registro # ========================= log_info "=== ETAPA 5: Registro ===" NB_HOSTNAME="$(hostname)" log_info "Executando netbird up --hostname $NB_HOSTNAME ..." RETRY=0 NB_UP_OK=0 until [ $NB_UP_OK -eq 1 ] || [ $RETRY -ge 3 ]; do set +e as_root "netbird up \ --management-url '$NB_MGMT_URL' \ --setup-key '$NB_SETUP_KEY' \ --hostname '$NB_HOSTNAME' \ --log-level info" RC=$? set -e if [ $RC -eq 0 ]; then NB_UP_OK=1 else RETRY=$((RETRY + 1)) if [ $RETRY -lt 3 ]; then log_warn "netbird up falhou (tentativa $RETRY/3) — aguardando 5s..." sleep 5 if [ "$HAS_DEFAULT" -eq 0 ] && [ -n "$MGMT_IP" ]; then if ! ip rule show | grep -q "to $MGMT_IP"; then as_root "ip rule add to $MGMT_IP lookup $WAN_TABLE pref 50" || true fi fi fi fi done [ $NB_UP_OK -eq 0 ] && { log_err "netbird up falhou apos 3 tentativas."; exit 1; } # ========================= # ETAPA 6 — Verificacao final # ========================= log_info "=== ETAPA 6: Verificacao ===" WAIT=0 until netbird status 2>&1 | grep -q "Management: Connected" || [ $WAIT -ge 30 ]; do sleep 2; WAIT=$((WAIT + 2)) done STATUS="$(netbird status 2>&1)" if echo "$STATUS" | grep -q "Management: Connected"; then NB_IP="$(echo "$STATUS" | awk '/NetBird IP:/{print $NF}')" NB_FQDN="$(echo "$STATUS" | awk '/FQDN:/{print $NF}')" log_ok "=== Bootstrap finalizado com sucesso ===" log_info "IP : $NB_IP" log_info "FQDN : $NB_FQDN" else log_err "Management NAO conectado." echo "$STATUS" exit 1 fi