Montana/Node/join.sh: полная децентрализация admission
По спеке Montana Protocol v35.25.0 и Montana Mesh whitepaper §2: admission через VDF + Selection event, без admin-токенов. Изменения: - удалён TOKEN-gate из join.sh и orchestrator - единый endpoint POST /vpn/node/join (без secret) - orchestrator проверяет TCP :8444 + NodeTable membership - если узел Active в NodeTable → сразу в Helsinki cascade VPN - иначе candidate (видим на /net/), promote-таймер каждые 5 минут Узел поднимает оба слоя одновременно (whitepaper §2): montana-node :8444 + xray :443 Reality. После прохождения CandidateVdf (~10ч) → Selection event → Active + 13 Ɉ welcome-bonus → auto-promotion в cascade.
This commit is contained in:
parent
4cbe83d0e7
commit
f94a2b5873
156
Node/join.sh
156
Node/join.sh
@ -1,70 +1,64 @@
|
||||
#!/bin/bash
|
||||
# Montana Node — авто-присоединение к сети.
|
||||
# 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)
|
||||
#
|
||||
# 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
|
||||
# Поднимает оба слоя сразу (Montana Mesh whitepaper §2: оператор обязан запустить оба):
|
||||
# - montana-node :8444 — p2p TimeChain, self-sovereign identity, VDF kandidatura
|
||||
# - xray :443 — VPN backend (Reality+Vision), готов к включению в cascade
|
||||
#
|
||||
# 2. Permissioned VPN-backend (нужен TOKEN от admin) — узел дополнительно
|
||||
# попадает в Helsinki cascade VPN balancer:
|
||||
# ROLE=vpn-backend TOKEN=<orch_token> \
|
||||
# ALIAS=cologne LABEL=Köln COUNTRY=DE HOSTING=Hetzner \
|
||||
# COORDS="50.94,6.96" bash join.sh
|
||||
# Жизненный цикл узла:
|
||||
# 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, например: 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
|
||||
: "${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}"
|
||||
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"
|
||||
echo "==> Montana Node join: $ALIAS ($LABEL, $COUNTRY/$HOSTING) @ $PUBLIC_IP"
|
||||
|
||||
# 1. Зависимости
|
||||
# 1. зависимости
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq curl ca-certificates openssl unzip jq
|
||||
|
||||
# 2. ufw
|
||||
# 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 # p2p Montana — всегда открыт
|
||||
[ "$ROLE" = "vpn-backend" ] && ufw allow 443/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 с хаба
|
||||
# 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
|
||||
[ -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 <<UNIT
|
||||
[Unit]
|
||||
Description=Montana Local Node (M8 cross-machine, Proof-of-Time)
|
||||
Description=Montana Local Node (M8, Proof-of-Time, VDF candidate→Active)
|
||||
After=network.target
|
||||
Wants=network-online.target
|
||||
|
||||
@ -88,20 +82,24 @@ WantedBy=multi-user.target
|
||||
UNIT
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now montana-node
|
||||
sleep 5
|
||||
systemctl is-active montana-node && echo "montana-node: active" || echo "!! montana-node fail"
|
||||
sleep 3
|
||||
|
||||
# 4. xray (только для vpn-backend role)
|
||||
PBK="" UUID="" SID=""
|
||||
if [ "$ROLE" = "vpn-backend" ]; then
|
||||
curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s -- install --without-geodata 2>&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 <<XCFG
|
||||
# 4. account_id для NodeTable membership check
|
||||
ACCOUNT_ID="$(sudo -u montana /usr/local/bin/montana-node inspect --data-dir /var/lib/montana | awk '/account_id/ {print $3}')"
|
||||
NODE_ID="$(sudo -u montana /usr/local/bin/montana-node inspect --data-dir /var/lib/montana | awk '/node_id/ {print $3}')"
|
||||
echo " account_id: $ACCOUNT_ID"
|
||||
echo " node_id: $NODE_ID"
|
||||
|
||||
# 5. xray Reality VPN backend
|
||||
curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s -- install --without-geodata 2>&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 <<XCFG
|
||||
{
|
||||
"log": {"loglevel":"warning","access":"/var/log/xray/access.log","error":"/var/log/xray/error.log"},
|
||||
"dns": {"servers":["https+local://1.1.1.1/dns-query","1.1.1.1"],"queryStrategy":"UseIP"},
|
||||
@ -118,42 +116,36 @@ if [ "$ROLE" = "vpn-backend" ]; then
|
||||
{"type":"field","protocol":["bittorrent"],"outboundTag":"blocked"}]}
|
||||
}
|
||||
XCFG
|
||||
xray -test -config /usr/local/etc/xray/config.json >/dev/null
|
||||
systemctl enable --now xray
|
||||
fi
|
||||
xray -test -config /usr/local/etc/xray/config.json >/dev/null
|
||||
systemctl enable --now xray
|
||||
|
||||
# 5. Регистрация в orchestrator
|
||||
# 6. POST /join (без TOKEN — admission по спеке Montana)
|
||||
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"
|
||||
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 <<DONE
|
||||
|
||||
╔══════════════════════════════════════════════════╗
|
||||
║ Montana Node "$ALIAS" подключён ($ROLE) ║
|
||||
╠══════════════════════════════════════════════════╣
|
||||
║ montana-node :8444 — p2p Bootstrap→CandidateVdf
|
||||
║ $([ "$ROLE" = vpn-backend ] && echo "xray :443 — Reality VPN backend cascade
|
||||
║ reality_pbk: $PBK" || echo "(VPN не включён — это p2p-only узел)")
|
||||
╔════════════════════════════════════════════════════════╗
|
||||
║ Montana Node "$ALIAS" подключён ║
|
||||
╠════════════════════════════════════════════════════════╣
|
||||
║ TimeChain :8444 → CandidateVdf (~10 ч) → Active
|
||||
║ xray Reality :443 → VPN backend готов
|
||||
║
|
||||
║ На /net/ карте появишься через ~30 сек (pull-aggregator).
|
||||
$([ "$ROLE" = vpn-backend ] && echo "║ В Helsinki cascade balancer уже добавлен.")
|
||||
╚══════════════════════════════════════════════════╝
|
||||
║ account_id: $ACCOUNT_ID
|
||||
║ reality_pbk: $PBK
|
||||
║
|
||||
║ Уже виден на /net/ карте Montana (как candidate).
|
||||
║ После прохождения VDF и Selection event автоматически
|
||||
║ попадёшь в Helsinki cascade VPN balancer и начнёшь
|
||||
║ обслуживать клиентский трафик. Получишь 13 Ɉ welcome-bonus.
|
||||
╚════════════════════════════════════════════════════════╝
|
||||
DONE
|
||||
|
||||
Loading…
Reference in New Issue
Block a user