Montana/Node/join.sh: dual-mode permissioned/permissionless
ROLE=node-only (default) — без TOKEN, использует /vpn/node/announce. P2P-узел Montana, ставится через wget+manifest с хаба. Появляется на /net/ карте как валидатор. НЕ попадает в Helsinki cascade VPN. ROLE=vpn-backend — нужен TOKEN от admin, /vpn/node/register. Узел дополнительно генерирует Reality keypair и попадает в cascade balancer Helsinki — обслуживает VPN-клиентов. Бинарь и manifest теперь публично доступны на хабе: HUB/Node/bin/montana-node HUB/Node/genesis-manifest.json
This commit is contained in:
parent
33daa755d1
commit
4cbe83d0e7
179
Node/join.sh
179
Node/join.sh
@ -1,15 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Montana Node — авто-присоединение к сети.
|
# 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
|
# 1. Permissionless P2P-only (любой может) — узел в сети Montana, на карте /net/,
|
||||||
# 3. Поднимает montana-node :8444 (p2p сети Montana) и xray :443 (VLESS+Reality)
|
# НО НЕ в cascade VPN balancer:
|
||||||
# 4. Регистрирует узел в Moscow orchestrator → авто-добавление на сайт,
|
# ALIAS=cologne LABEL=Köln COUNTRY=DE HOSTING=Hetzner \
|
||||||
# в карту, peer-health всех узлов, Helsinki cascade balancer.
|
# COORDS="50.94,6.96" bash join.sh
|
||||||
|
#
|
||||||
|
# 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
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
: "${ALIAS:?нужен ALIAS, например: amsterdam}"
|
: "${ALIAS:?нужен ALIAS, например: amsterdam}"
|
||||||
@ -17,83 +20,47 @@ set -euo pipefail
|
|||||||
: "${COUNTRY:?нужен COUNTRY 2-буквы, например: NL}"
|
: "${COUNTRY:?нужен COUNTRY 2-буквы, например: NL}"
|
||||||
: "${HOSTING:?нужен HOSTING, например: DigitalOcean}"
|
: "${HOSTING:?нужен HOSTING, например: DigitalOcean}"
|
||||||
: "${COORDS:?нужны COORDS \"lat,lon\", например: 52.37,4.89}"
|
: "${COORDS:?нужны COORDS \"lat,lon\", например: 52.37,4.89}"
|
||||||
: "${TOKEN:?нужен orchestrator TOKEN (запроси у admin)}"
|
ROLE="${ROLE:-node-only}" # node-only | vpn-backend
|
||||||
ROLE="${ROLE:-vpn-backend}"
|
|
||||||
ORCH="${ORCH:-https://montana.quest/vpn/node}"
|
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}"
|
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)"
|
PUBLIC_IP="$(curl -s https://api.ipify.org)"
|
||||||
echo "==> Montana Node join: $ALIAS ($LABEL, $COUNTRY/$HOSTING) @ $PUBLIC_IP"
|
echo "==> Montana Node join: $ALIAS ($LABEL, $COUNTRY/$HOSTING) role=$ROLE ip=$PUBLIC_IP"
|
||||||
|
|
||||||
# 1. Зависимости
|
# 1. Зависимости
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
apt-get install -y -qq curl ca-certificates openssl unzip jq
|
apt-get install -y -qq curl ca-certificates openssl unzip jq
|
||||||
|
|
||||||
# 2. xray + Reality keypair
|
# 2. ufw
|
||||||
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 deny incoming >/dev/null 2>&1 || true
|
||||||
ufw default allow outgoing >/dev/null 2>&1 || true
|
ufw default allow outgoing >/dev/null 2>&1 || true
|
||||||
ufw allow 22/tcp >/dev/null
|
ufw allow 22/tcp >/dev/null
|
||||||
ufw allow 443/tcp >/dev/null
|
ufw allow 8444/tcp >/dev/null # p2p Montana — всегда открыт
|
||||||
ufw allow 8444/tcp >/dev/null
|
[ "$ROLE" = "vpn-backend" ] && ufw allow 443/tcp >/dev/null
|
||||||
echo "y" | ufw enable >/dev/null
|
echo "y" | ufw enable >/dev/null
|
||||||
|
|
||||||
# 4. montana-node
|
# 3. montana-node — скачать бинарь с хаба, manifest с хаба
|
||||||
id montana &>/dev/null || useradd -r -m -d /var/lib/montana -s /usr/sbin/nologin montana
|
mkdir -p /etc/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
|
if [ ! -x /usr/local/bin/montana-node ]; then
|
||||||
echo "!! /usr/local/bin/montana-node отсутствует. Скопируй с любого узла:"
|
echo "==> Скачиваю montana-node бинарь с $HUB/Node/bin/montana-node"
|
||||||
echo " scp <existing-server>:/usr/local/bin/montana-node $PUBLIC_IP:/usr/local/bin/"
|
curl -sL "$HUB/Node/bin/montana-node" -o /usr/local/bin/montana-node
|
||||||
exit 2
|
chmod +x /usr/local/bin/montana-node
|
||||||
fi
|
fi
|
||||||
if [ ! -f /etc/montana/genesis-manifest.json ]; then
|
if [ ! -f /etc/montana/genesis-manifest.json ]; then
|
||||||
echo "!! /etc/montana/genesis-manifest.json отсутствует. Скопируй:"
|
curl -sL "$HUB/Node/genesis-manifest.json" -o /etc/montana/genesis-manifest.json
|
||||||
echo " scp <existing-server>:/etc/montana/genesis-manifest.json $PUBLIC_IP:/etc/montana/"
|
|
||||||
exit 2
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f /var/lib/montana/identity.bin ]; then
|
id montana &>/dev/null || useradd -r -m -d /var/lib/montana -s /usr/sbin/nologin montana
|
||||||
sudo -u montana /usr/local/bin/montana-node init --data-dir /var/lib/montana
|
mkdir -p /var/lib/montana
|
||||||
fi
|
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
|
cat > /etc/systemd/system/montana-node.service <<UNIT
|
||||||
[Unit]
|
[Unit]
|
||||||
@ -121,40 +88,72 @@ WantedBy=multi-user.target
|
|||||||
UNIT
|
UNIT
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable --now montana-node
|
systemctl enable --now montana-node
|
||||||
sleep 3
|
sleep 5
|
||||||
systemctl is-active montana-node && echo "montana-node: active" || echo "!! montana-node fail"
|
systemctl is-active montana-node && echo "montana-node: active" || echo "!! montana-node fail"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
fi
|
||||||
|
|
||||||
# 5. Регистрация в orchestrator
|
# 5. Регистрация в orchestrator
|
||||||
LAT="$(echo "$COORDS" | cut -d, -f1)"
|
LAT="$(echo "$COORDS" | cut -d, -f1)"
|
||||||
LON="$(echo "$COORDS" | cut -d, -f2)"
|
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")
|
if [ "$ROLE" = "vpn-backend" ]; then
|
||||||
echo "orchestrator: $RESP"
|
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 <<DONE
|
cat <<DONE
|
||||||
|
|
||||||
╔══════════════════════════════════════════════════╗
|
╔══════════════════════════════════════════════════╗
|
||||||
║ Montana Node "$ALIAS" подключён ║
|
║ Montana Node "$ALIAS" подключён ($ROLE) ║
|
||||||
╠══════════════════════════════════════════════════╣
|
╠══════════════════════════════════════════════════╣
|
||||||
║ reality_pbk: $PUB
|
║ montana-node :8444 — p2p Bootstrap→CandidateVdf
|
||||||
║ reality_uuid: $UUID
|
║ $([ "$ROLE" = vpn-backend ] && echo "xray :443 — Reality VPN backend cascade
|
||||||
║ reality_sid: $SID
|
║ reality_pbk: $PBK" || echo "(VPN не включён — это p2p-only узел)")
|
||||||
║ montana-node :8444 — p2p Bootstrap → CandidateVdf
|
║
|
||||||
║ xray :443 — Reality backend cascade
|
║ На /net/ карте появишься через ~30 сек (pull-aggregator).
|
||||||
║ На /net/ и /vpn/ появишься через ~30 сек pull.
|
$([ "$ROLE" = vpn-backend ] && echo "║ В Helsinki cascade balancer уже добавлен.")
|
||||||
╚══════════════════════════════════════════════════╝
|
╚══════════════════════════════════════════════════╝
|
||||||
DONE
|
DONE
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user