Montana/Node/join.sh + orchestrator: auto-registration новых узлов
POST /vpn/node/register на Moscow orchestrator автоматически: - peer-health PEERS на всех узлах - montana-net-pull, montana-cities-build - Helsinki cascade outbound + selector join.sh — одна команда на новом сервере.
This commit is contained in:
parent
310ce21e17
commit
4deb04cd4e
@ -160,3 +160,45 @@ ssh <server> "systemctl stop montana-node && systemctl disable montana-node && r
|
||||
| fra | Frankfurt | DE | Timeweb | genesis, vpn backend|
|
||||
| fin | Helsinki | FI | THE.Hosting | genesis, vpn frontend|
|
||||
| us | New York | US | WorkTitans | non-genesis joined 2026-05-14, vpn backend |
|
||||
|
||||
---
|
||||
|
||||
## Альтернатива: одной командой через `join.sh`
|
||||
|
||||
Не хочешь читать 9 шагов — запусти автоматический скрипт:
|
||||
|
||||
```bash
|
||||
# на новом сервере (под root):
|
||||
scp <existing-server>:/usr/local/bin/montana-node /usr/local/bin/
|
||||
scp <existing-server>:/etc/montana/genesis-manifest.json /etc/montana/
|
||||
|
||||
ALIAS=amsterdam \
|
||||
LABEL=Amsterdam \
|
||||
COUNTRY=NL \
|
||||
HOSTING=DigitalOcean \
|
||||
COORDS="52.37,4.89" \
|
||||
TOKEN=<orchestrator_token> \
|
||||
bash <(curl -sk https://hub.montana.quest/efir369999/montana/raw/branch/main/Node/join.sh)
|
||||
```
|
||||
|
||||
Скрипт автоматически:
|
||||
1. Поставит xray + ufw
|
||||
2. Сгенерирует Reality keypair, UUID, shortId
|
||||
3. Создаст systemd unit для montana-node и xray
|
||||
4. Откроет порты :443 и :8444
|
||||
5. Сделает identity через `montana-node init`
|
||||
6. Зарегистрирует узел в Moscow **orchestrator** (`POST /vpn/node/register`)
|
||||
7. Orchestrator автоматически обновит на **всех** узлах:
|
||||
- `peer-health.py` (PEERS)
|
||||
- `montana-net-pull` (SRC/LABEL/HOSTING/COUNTRY)
|
||||
- `montana-cities-build` (CITIES dict)
|
||||
- Helsinki `xray/config.json` (добавит outbound + расширит cascade balancer selector)
|
||||
8. Через ~30 секунд новый узел появится на `montana.quest/net/` и `/vpn/`
|
||||
|
||||
`TOKEN` — секрет orchestrator, лежит на Moscow в `/etc/montana-orchestrator.token`. Запроси у admin Montana.
|
||||
|
||||
## Orchestrator API
|
||||
|
||||
- `GET https://montana.quest/vpn/node/health` → `{"ok":true,"nodes":<count>}`
|
||||
- `GET https://montana.quest/vpn/node/nodes` → список всех известных узлов сети
|
||||
- `POST https://montana.quest/vpn/node/register` → регистрация нового узла (требует `secret` в body)
|
||||
|
||||
160
Node/join.sh
Executable file
160
Node/join.sh
Executable file
@ -0,0 +1,160 @@
|
||||
#!/bin/bash
|
||||
# Montana Node — авто-присоединение к сети.
|
||||
# Одна команда:
|
||||
# ALIAS=amsterdam LABEL=Amsterdam COUNTRY=NL HOSTING=DigitalOcean \
|
||||
# COORDS="52.37,4.89" TOKEN=<orch_token> bash join.sh
|
||||
#
|
||||
# Скрипт:
|
||||
# 1. Ставит xray + ufw + montana-node
|
||||
# 2. Генерирует Reality keypair + UUID + shortId
|
||||
# 3. Поднимает montana-node :8444 (p2p сети Montana) и xray :443 (VLESS+Reality)
|
||||
# 4. Регистрирует узел в Moscow orchestrator → авто-добавление на сайт,
|
||||
# в карту, peer-health всех узлов, Helsinki cascade balancer.
|
||||
set -euo pipefail
|
||||
|
||||
: "${ALIAS:?нужен ALIAS, например: amsterdam}"
|
||||
: "${LABEL:?нужен LABEL, например: Amsterdam}"
|
||||
: "${COUNTRY:?нужен COUNTRY 2-буквы, например: NL}"
|
||||
: "${HOSTING:?нужен HOSTING, например: DigitalOcean}"
|
||||
: "${COORDS:?нужны COORDS \"lat,lon\", например: 52.37,4.89}"
|
||||
: "${TOKEN:?нужен orchestrator TOKEN (запроси у admin)}"
|
||||
ROLE="${ROLE:-vpn-backend}"
|
||||
ORCH="${ORCH:-https://montana.quest/vpn/node}"
|
||||
BOOTSTRAP_FROM="${BOOTSTRAP_FROM:-cdn.montana.quest}"
|
||||
|
||||
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. xray + Reality keypair
|
||||
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}')"
|
||||
PUB="$(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
|
||||
|
||||
# 3. 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 443/tcp >/dev/null
|
||||
ufw allow 8444/tcp >/dev/null
|
||||
echo "y" | ufw enable >/dev/null
|
||||
|
||||
# 4. montana-node
|
||||
id montana &>/dev/null || useradd -r -m -d /var/lib/montana -s /usr/sbin/nologin montana
|
||||
mkdir -p /var/lib/montana /etc/montana
|
||||
chown -R montana:montana /var/lib/montana && chmod 700 /var/lib/montana
|
||||
|
||||
if [ ! -x /usr/local/bin/montana-node ]; then
|
||||
echo "!! /usr/local/bin/montana-node отсутствует. Скопируй с любого узла:"
|
||||
echo " scp <existing-server>:/usr/local/bin/montana-node $PUBLIC_IP:/usr/local/bin/"
|
||||
exit 2
|
||||
fi
|
||||
if [ ! -f /etc/montana/genesis-manifest.json ]; then
|
||||
echo "!! /etc/montana/genesis-manifest.json отсутствует. Скопируй:"
|
||||
echo " scp <existing-server>:/etc/montana/genesis-manifest.json $PUBLIC_IP:/etc/montana/"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ ! -f /var/lib/montana/identity.bin ]; then
|
||||
sudo -u montana /usr/local/bin/montana-node init --data-dir /var/lib/montana
|
||||
fi
|
||||
|
||||
cat > /etc/systemd/system/montana-node.service <<UNIT
|
||||
[Unit]
|
||||
Description=Montana Local Node (M8 cross-machine, Proof-of-Time)
|
||||
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
|
||||
systemctl is-active montana-node && echo "montana-node: active" || echo "!! montana-node fail"
|
||||
|
||||
# 5. Регистрация в orchestrator
|
||||
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 pbk "$PUB" \
|
||||
--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}')
|
||||
|
||||
RESP=$(curl -sk -X POST "$ORCH/register" -H 'Content-Type: application/json' -d "$PAYLOAD")
|
||||
echo "orchestrator: $RESP"
|
||||
|
||||
cat <<DONE
|
||||
|
||||
╔══════════════════════════════════════════════════╗
|
||||
║ Montana Node "$ALIAS" подключён ║
|
||||
╠══════════════════════════════════════════════════╣
|
||||
║ reality_pbk: $PUB
|
||||
║ reality_uuid: $UUID
|
||||
║ reality_sid: $SID
|
||||
║ montana-node :8444 — p2p Bootstrap → CandidateVdf
|
||||
║ xray :443 — Reality backend cascade
|
||||
║ На /net/ и /vpn/ появишься через ~30 сек pull.
|
||||
╚══════════════════════════════════════════════════╝
|
||||
DONE
|
||||
Loading…
Reference in New Issue
Block a user