#!/bin/bash # Montana node — установка одной командой на Linux VPS. # # Использование (одна строка в терминале VPS): # curl -sSL https://raw.githubusercontent.com/efir369999/Montana/main/Код/scripts/install-vps.sh | sudo bash # # Либо локально после git clone: # sudo bash scripts/install-vps.sh # # Что делает: # 1. Проверяет OS (Ubuntu/Debian/Fedora/RHEL/Alpine) # 2. Устанавливает system deps (build-essential, clang, git, perl) # 3. Ставит Rust toolchain через rustup (если нет) # 4. Клонирует/обновляет репозиторий в /opt/montana # 5. Собирает release бинарь # 6. Создаёт системного пользователя montana и /var/lib/montana # 7. Генерирует identity (24-словная мнемоника выводится — ЗАПИШИТЕ!) # 8. Устанавливает systemd unit с hardening # 9. Запускает узел и включает автозапуск при старте VPS set -euo pipefail REPO_URL="${MONTANA_REPO_URL:-https://github.com/efir369999/Montana.git}" REPO_BRANCH="${MONTANA_REPO_BRANCH:-main}" INSTALL_DIR="/opt/montana" DATA_DIR="/var/lib/montana" BIN_DST="/usr/local/bin/montana-node" USER_NAME="montana" SERVICE_FILE="/etc/systemd/system/montana-node.service" log() { printf '\033[1;32m[install-vps]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[install-vps]\033[0m %s\n' "$*" >&2; } die() { printf '\033[1;31m[install-vps] ОШИБКА:\033[0m %s\n' "$*" >&2; exit 1; } # --- Шаг 1: проверка root --- if [ "$(id -u)" != "0" ]; then die "требуется sudo/root. Запустите: curl -sSL | sudo bash" fi # --- Шаг 2: detect OS --- if [ ! -f /etc/os-release ]; then die "не могу определить OS — отсутствует /etc/os-release" fi . /etc/os-release OS_ID="${ID:-unknown}" log "обнаружен OS: ${PRETTY_NAME:-$OS_ID}" # --- Шаг 3: install system deps --- log "устанавливаю system dependencies..." case "$OS_ID" in ubuntu|debian) export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq build-essential clang pkg-config git curl perl ca-certificates >/dev/null ;; fedora|rhel|centos|rocky|almalinux) dnf install -y -q gcc gcc-c++ clang pkgconf-pkg-config git curl perl ca-certificates make >/dev/null ;; alpine) apk add --no-cache build-base clang pkgconfig git curl perl linux-headers ca-certificates >/dev/null ;; *) die "неподдерживаемый OS: $OS_ID. Поддерживаются: ubuntu, debian, fedora, rhel, centos, rocky, almalinux, alpine" ;; esac # --- Шаг 4: install Rust toolchain --- if ! command -v cargo >/dev/null 2>&1; then log "устанавливаю Rust toolchain (rustup)..." curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- -y --default-toolchain stable --profile minimal --no-modify-path export PATH="/root/.cargo/bin:$PATH" else log "Rust toolchain уже установлен: $(cargo --version)" fi export PATH="${HOME:-/root}/.cargo/bin:/root/.cargo/bin:$PATH" # --- Шаг 5: clone/update repo --- if [ -d "$INSTALL_DIR/.git" ]; then log "обновляю репозиторий $INSTALL_DIR..." cd "$INSTALL_DIR" git fetch origin "$REPO_BRANCH" git reset --hard "origin/$REPO_BRANCH" else log "клонирую $REPO_URL (branch $REPO_BRANCH) → $INSTALL_DIR..." rm -rf "$INSTALL_DIR" git clone --branch "$REPO_BRANCH" --single-branch "$REPO_URL" "$INSTALL_DIR" fi # --- Шаг 6: build бинарь --- SOURCE_DIR="$INSTALL_DIR/Код" if [ ! -d "$SOURCE_DIR" ]; then die "директория '$SOURCE_DIR' не найдена в репозитории. Возможно структура изменилась — проверьте путь к montana-node." fi cd "$SOURCE_DIR" log "собираю montana-node release (это занимает 5-15 минут на первом запуске)..." cargo build --release -p montana-node 2>&1 | tail -5 # --- Шаг 7: install бинарь --- install -m 0755 target/release/montana-node "$BIN_DST" log "бинарь установлен: $BIN_DST" # --- Шаг 8: create user + data dir --- if ! id "$USER_NAME" >/dev/null 2>&1; then log "создаю системного пользователя $USER_NAME..." useradd -r -s /usr/sbin/nologin -d "$DATA_DIR" -M "$USER_NAME" 2>/dev/null \ || useradd -r -s /bin/false -d "$DATA_DIR" "$USER_NAME" fi mkdir -p "$DATA_DIR" chown -R "$USER_NAME:$USER_NAME" "$DATA_DIR" chmod 0750 "$DATA_DIR" # --- Шаг 9: init identity (если нет) --- if [ ! -f "$DATA_DIR/identity.bin" ]; then log "генерирую identity (24-словная мнемоника)..." echo echo "================================================================" echo " ВНИМАНИЕ: ниже выведутся 24 слова мнемоники." echo " ЗАПИШИТЕ их в надёжное место — это backup всего." echo " Потеряете → потеряете доступ к узлу и всем заработанным Ɉ." echo "================================================================" echo sudo -u "$USER_NAME" "$BIN_DST" init --data-dir "$DATA_DIR" echo else log "identity уже существует ($DATA_DIR/identity.bin) — пропускаю генерацию" fi # --- Шаг 10: M8 cross-machine networking config (опционально) --- # Если operator задал MONTANA_LISTEN и MONTANA_GENESIS_MANIFEST в env — # узел стартует в cross-machine режиме (libp2p TCP+TLS+Noise + peer discovery). # Иначе остаётся в singleton mode (backward compat). MONTANA_NODE_EXTRA_ARGS="" if [ -n "${MONTANA_LISTEN:-}" ] && [ -n "${MONTANA_GENESIS_MANIFEST:-}" ]; then MONTANA_NODE_EXTRA_ARGS="--listen $MONTANA_LISTEN --genesis-manifest $MONTANA_GENESIS_MANIFEST" log "cross-machine M8 mode: --listen=$MONTANA_LISTEN, manifest=$MONTANA_GENESIS_MANIFEST" if [ ! -f "$MONTANA_GENESIS_MANIFEST" ]; then warn "manifest $MONTANA_GENESIS_MANIFEST ещё не существует — узел перезапустится корректно после его создания (Restart=on-failure)" fi elif [ -n "${MONTANA_LISTEN:-}" ] || [ -n "${MONTANA_GENESIS_MANIFEST:-}" ]; then die "MONTANA_LISTEN и MONTANA_GENESIS_MANIFEST должны указываться вместе" else log "singleton mode (без --listen/--genesis-manifest)" fi # --- Шаг 11: install systemd unit --- log "устанавливаю systemd unit $SERVICE_FILE..." cat > "$SERVICE_FILE" </dev/null 2>&1 systemctl restart montana-node.service # --- Финальный отчёт --- sleep 2 log "" log "================================================================" log " УСТАНОВКА ЗАВЕРШЕНА" log "================================================================" log "" log "Бинарь: $BIN_DST" log "Данные: $DATA_DIR" log "Пользователь: $USER_NAME" log "Service: montana-node.service" log "" log "--- статус узла ---" systemctl --no-pager status montana-node.service | head -10 || true log "" log "Полезные команды:" log " systemctl status montana-node # текущий статус" log " journalctl -u montana-node -f # логи в реальном времени" log " systemctl stop montana-node # остановить узел" log " systemctl restart montana-node # перезапустить" log " $BIN_DST status --data-dir $DATA_DIR # phase + balance" log "" log "Жизненный цикл узла:" log " Phase 1: Bootstrap → CandidateVdf (~10-14 часов VDF до vdf_chain_length ≥ τ₂)" log " Phase 2: CandidateVdf → Registered (NodeRegistration через canonical apply_*)" log " Phase 3: Registered → Active (selection event на следующем W % 336 == 0)" log " Phase 4: Active (эмиссия 13 Ɉ per окно через apply_proposal)" log "" log "Это spec-compliant Sybil-защита Montana — нельзя обойти быстрее." log "Узел переживает рестарты VPS (systemd Restart=on-failure) и продолжает с того окна где был."