#!/bin/bash # Montana Node — авто-присоединение к сети. # # Два режима: # # 1. Permissionless P2P-only (любой может) — узел в сети Montana, на карте /net/, # НО НЕ в cascade VPN balancer: # ALIAS=cologne LABEL=Köln COUNTRY=DE HOSTING=Hetzner \ # COORDS="50.94,6.96" bash join.sh # # 2. Permissioned VPN-backend (нужен TOKEN от admin) — узел дополнительно # попадает в Helsinki cascade VPN balancer: # ROLE=vpn-backend TOKEN= \ # ALIAS=cologne LABEL=Köln COUNTRY=DE HOSTING=Hetzner \ # COORDS="50.94,6.96" bash join.sh set -euo pipefail : "${ALIAS:?нужен ALIAS, например: amsterdam}" : "${LABEL:?нужен LABEL, например: Amsterdam}" : "${COUNTRY:?нужен COUNTRY 2-буквы, например: NL}" : "${HOSTING:?нужен HOSTING, например: DigitalOcean}" : "${COORDS:?нужны COORDS \"lat,lon\", например: 52.37,4.89}" ROLE="${ROLE:-node-only}" # node-only | vpn-backend ORCH="${ORCH:-https://montana.quest/vpn/node}" HUB="${HUB:-https://hub.montana.quest/efir369999/montana/raw/branch/main}" BOOTSTRAP_FROM="${BOOTSTRAP_FROM:-cdn.montana.quest}" if [ "$ROLE" = "vpn-backend" ]; then : "${TOKEN:?для vpn-backend нужен TOKEN от admin}" fi PUBLIC_IP="$(curl -s https://api.ipify.org)" echo "==> Montana Node join: $ALIAS ($LABEL, $COUNTRY/$HOSTING) role=$ROLE ip=$PUBLIC_IP" # 1. Зависимости export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq curl ca-certificates openssl unzip jq # 2. ufw 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 # p2p Montana — всегда открыт [ "$ROLE" = "vpn-backend" ] && ufw allow 443/tcp >/dev/null echo "y" | ufw enable >/dev/null # 3. montana-node — скачать бинарь с хаба, manifest с хаба mkdir -p /etc/montana if [ ! -x /usr/local/bin/montana-node ]; then echo "==> Скачиваю montana-node бинарь с $HUB/Node/bin/montana-node" curl -sL "$HUB/Node/bin/montana-node" -o /usr/local/bin/montana-node chmod +x /usr/local/bin/montana-node fi if [ ! -f /etc/montana/genesis-manifest.json ]; then curl -sL "$HUB/Node/genesis-manifest.json" -o /etc/montana/genesis-manifest.json fi 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 fi # 5. Регистрация в orchestrator LAT="$(echo "$COORDS" | cut -d, -f1)" LON="$(echo "$COORDS" | cut -d, -f2)" if [ "$ROLE" = "vpn-backend" ]; then ENDPOINT="$ORCH/register" 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 pbk "$PBK" --arg uuid "$UUID" --arg sid "$SID" --arg role "$ROLE" --arg secret "$TOKEN" \ '{alias:$alias,ip:$ip,country:$country,hosting:$hosting,label:$label,coords:[$lat,$lon],reality_pbk:$pbk,reality_uuid:$uuid,reality_sid:$sid,role:$role,secret:$secret}') else ENDPOINT="$ORCH/announce" 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" \ '{alias:$alias,ip:$ip,country:$country,hosting:$hosting,label:$label,coords:[$lat,$lon]}') fi RESP=$(curl -sk -X POST "$ENDPOINT" -H 'Content-Type: application/json' -d "$PAYLOAD") echo "orchestrator ($ROLE → $ENDPOINT): $RESP" cat <