#!/bin/bash # Montana Node — полностью децентрализованное присоединение к сети. # По спеке Montana Protocol v35.25.0 — admission через VDF + Selection event, # без admin-токенов и человеческих gate-keepers. # # Одна команда (любой человек, никакого TOKEN): # ALIAS=cologne LABEL=Köln COUNTRY=DE HOSTING=Hetzner COORDS="50.94,6.96" \ # bash <(curl -sk https://hub.montana.quest/efir369999/montana/raw/branch/main/Node/join.sh) # # Поднимает оба слоя сразу (Montana Mesh whitepaper §2: оператор обязан запустить оба): # - montana-node :8444 — p2p TimeChain, self-sovereign identity, VDF kandidatura # - xray :443 — VPN backend (Reality+Vision), готов к включению в cascade # # Жизненный цикл узла: # 1. join.sh поднимает оба слоя на новом сервере # 2. POST /vpn/node/join → orchestrator проверяет TCP :8444 + NodeTable membership # 3. Если узел уже в NodeTable Active (повторный join после VDF) → попадает в cascade сразу # 4. Иначе — статус 'candidate' (виден на /net/ карте). Montana-node идёт CandidateVdf (~10ч). # 5. После selection event → Active в NodeTable + 13 Ɉ welcome-bonus # 6. Orchestrator-promote.timer (каждые 5 минут) auto-promote в cascade когда видит Active set -euo pipefail : "${ALIAS:?нужен ALIAS (например: cologne)}" : "${LABEL:?нужен LABEL (например: Köln)}" : "${COUNTRY:?нужен COUNTRY (2 буквы, например: DE)}" : "${HOSTING:?нужен HOSTING (например: Hetzner)}" : "${COORDS:?нужны COORDS \"lat,lon\" (например: 50.94,6.96)}" ORCH="${ORCH:-https://montana.quest/vpn/node}" HUB="${HUB:-https://hub.montana.quest/efir369999/montana/raw/branch/main}" PUBLIC_IP="$(curl -s https://api.ipify.org)" echo "==> Montana Node join: $ALIAS ($LABEL, $COUNTRY/$HOSTING) @ $PUBLIC_IP" # 1. зависимости export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq curl ca-certificates openssl unzip jq # 2. ufw — оба порта открыты (whitepaper §2: и :8444 и :443) ufw default deny incoming >/dev/null 2>&1 || true ufw default allow outgoing >/dev/null 2>&1 || true ufw allow 22/tcp >/dev/null ufw allow 8444/tcp >/dev/null ufw allow 443/tcp >/dev/null echo "y" | ufw enable >/dev/null # 3. montana-node бинарь + manifest с хаба (публично) mkdir -p /etc/montana [ -x /usr/local/bin/montana-node ] || { curl -sL "$HUB/Node/bin/montana-node" -o /usr/local/bin/montana-node; chmod +x /usr/local/bin/montana-node; } [ -f /etc/montana/genesis-manifest.json ] || curl -sL "$HUB/Node/genesis-manifest.json" -o /etc/montana/genesis-manifest.json id montana &>/dev/null || useradd -r -m -d /var/lib/montana -s /usr/sbin/nologin montana mkdir -p /var/lib/montana chown -R montana:montana /var/lib/montana && chmod 700 /var/lib/montana [ -f /var/lib/montana/identity.bin ] || sudo -u montana /usr/local/bin/montana-node init --data-dir /var/lib/montana cat > /etc/systemd/system/montana-node.service <&1 | tail -3 mkdir -p /usr/local/etc/xray UUID="$(xray uuid)" KEYS="$(xray x25519)" PRIV="$(echo "$KEYS" | awk '/PrivateKey/ {print $NF}')" PBK="$(echo "$KEYS" | awk '/Password/ {print $NF}')" SID="$(openssl rand -hex 8)" cat > /usr/local/etc/xray/config.json </dev/null systemctl enable --now xray # 6. POST /join (без TOKEN — admission по спеке Montana) LAT="$(echo "$COORDS" | cut -d, -f1)" LON="$(echo "$COORDS" | cut -d, -f2)" PAYLOAD=$(jq -nc \ --arg alias "$ALIAS" --arg ip "$PUBLIC_IP" --arg country "$COUNTRY" \ --arg hosting "$HOSTING" --arg label "$LABEL" --argjson lat "$LAT" --argjson lon "$LON" \ --arg acc "$ACCOUNT_ID" --arg nid "$NODE_ID" \ --arg pbk "$PBK" --arg uuid "$UUID" --arg sid "$SID" \ '{alias:$alias,ip:$ip,country:$country,hosting:$hosting,label:$label,coords:[$lat,$lon],account_id:$acc,node_id:$nid,reality_pbk:$pbk,reality_uuid:$uuid,reality_sid:$sid}') RESP=$(curl -sk -X POST "$ORCH/join" -H 'Content-Type: application/json' -d "$PAYLOAD") echo echo "orchestrator: $RESP" cat <