montana/Node/join.sh

152 lines
7.7 KiB
Bash
Raw Normal View History

#!/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 <<UNIT
[Unit]
Description=Montana Local Node (M8, Proof-of-Time, VDF candidate→Active)
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=montana
Group=montana
ExecStart=/usr/local/bin/montana-node start --data-dir /var/lib/montana --listen /ip4/0.0.0.0/tcp/8444 --genesis-manifest /etc/montana/genesis-manifest.json
Restart=on-failure
RestartSec=10
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/montana
CPUQuota=200%
LimitNOFILE=8192
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now montana-node
sleep 3
# 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"},
"inbounds": [{"tag":"reality-${ALIAS}-backend","listen":"0.0.0.0","port":443,"protocol":"vless",
"settings":{"clients":[{"id":"${UUID}","email":"${ALIAS}-cascade","flow":"xtls-rprx-vision"}],"decryption":"none"},
"streamSettings":{"network":"tcp","security":"reality",
"realitySettings":{"show":false,"dest":"www.googletagmanager.com:443","xver":0,
"serverNames":["www.googletagmanager.com"],"privateKey":"${PRIV}","shortIds":["${SID}"]}},
"sniffing":{"enabled":true,"destOverride":["http","tls","quic"]}}],
"outbounds":[{"tag":"direct","protocol":"freedom","settings":{"domainStrategy":"UseIP"}},
{"tag":"blocked","protocol":"blackhole"},{"tag":"dns-out","protocol":"dns"}],
"routing":{"rules":[{"type":"field","port":"53","outboundTag":"dns-out"},
{"type":"field","ip":["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16","127.0.0.0/8"],"outboundTag":"blocked"},
{"type":"field","protocol":["bittorrent"],"outboundTag":"blocked"}]}
}
XCFG
xray -test -config /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 <<DONE
╔════════════════════════════════════════════════════════╗
║ Montana Node "$ALIAS" подключён ║
╠════════════════════════════════════════════════════════╣
║ TimeChain :8444 → CandidateVdf (~10 ч) → Active
║ xray Reality :443 → VPN backend готов
║ account_id: $ACCOUNT_ID
║ reality_pbk: $PBK
║ Уже виден на /net/ карте Montana (как candidate).
║ После прохождения VDF и Selection event автоматически
║ попадёшь в Helsinki cascade VPN balancer и начнёшь
║ обслуживать клиентский трафик. Получишь 13 Ɉ welcome-bonus.
╚════════════════════════════════════════════════════════╝
DONE