#!/usr/bin/env bash # VPS Installer bootstrap — downloads the latest installer and launches it. # # One command (defaults: HTTPS on 0.0.0.0:8088, login "admin", auto-generated # password printed in the console): # curl -fsSL https://vps.myidb.ru/files/bootstrap.sh | bash # # Override any of them: # curl -fsSL https://vps.myidb.ru/files/bootstrap.sh | bash -s -- \ # --ip 0.0.0.0 --port 8443 --login admin --password S3cur3Pass [--no-tls] set -euo pipefail INSTALL_DIR="/opt/vps-installer" BASE_URL="${INSTALLER_BASE_URL:-https://vps-test.myidb.ru/files}" # Репозиторий, с которого пришёл инсталлятор, — он же станет источником # обновлений для ноды. Выводится из BASE_URL отбрасыванием /files, а не # задаётся отдельно: два независимых адреса неизбежно разъедутся, и нода, # поставленная с тестового сервера, пошла бы за обновлениями на боевой. UPDATE_URL="${UPDATE_URL:-${BASE_URL%/files}}" UPDATE_URL="${UPDATE_URL%/}" ARGS=() # passed through to the installer while [[ $# -gt 0 ]]; do case "$1" in --dir) INSTALL_DIR="$2"; shift 2 ;; --no-tls) ARGS+=("--no-tls"); shift ;; --ip|--port|--login|--password) ARGS+=("$1" "$2"); shift 2 ;; -h|--help) echo "Usage: bootstrap.sh [--ip IP] [--port N] [--login L] [--password P] [--no-tls] [--dir DIR]" echo "No options: HTTPS on 0.0.0.0:8088, login admin, auto-generated password (printed below)." exit 0 ;; *) ARGS+=("$1"); shift ;; esac done ARCH="$(uname -m)" case "$ARCH" in x86_64) BINARY_ARCH="amd64" ;; aarch64|arm64) BINARY_ARCH="arm64" ;; *) echo "ERROR: unsupported architecture: $ARCH" >&2; exit 1 ;; esac DOWNLOAD_URL="${BASE_URL%/}/vps-installer-linux-${BINARY_ARCH}" mkdir -p "$INSTALL_DIR" BINARY_PATH="$INSTALL_DIR/vps-installer" # ── Учётные данные репозитория (роадмап 1.7) ───────────────────────────────── # # Сам этот скрипт открыт: он не содержит секретов, только запрашивает их. Всё # остальное — бинарник инсталлятора, пакеты обновлений, runtime, зеркало # Go-модулей — закрыто. Пароль спрашивается ОДИН РАЗ и передаётся дальше # окружением: инсталлятору он нужен для загрузки Go-тулчейна и runtime, а по # завершении установки ложится на ноду в /etc/vps-update.conf. # # Читаем с /dev/tty, а не со stdin: при `curl … | bash` стандартный ввод занят # самим скриптом, и обычный read прочитал бы его остаток вместо ответа # оператора. У curl такой проблемы нет — перенаправлен только его stdout. # # Значения могут прийти и из окружения: так работает автоматизация и удалённая # установка с управляющего сервера, где терминала нет вовсе. REPO_USER="${REPO_USER:-}" REPO_PASS="${REPO_PASS:-}" probe_needs_auth() { # 401 → репозиторий закрыт. Пока авторизация не включена, ничего не спрашиваем # и работаем как раньше. command -v curl >/dev/null 2>&1 || return 1 [ "$(curl -s -o /dev/null -w '%{http_code}' "$DOWNLOAD_URL" 2>/dev/null)" = "401" ] } if [ -z "$REPO_USER" ] && probe_needs_auth; then if [ -e /dev/tty ] && [ -r /dev/tty ]; then echo "Репозиторий требует авторизации." printf 'Логин: ' > /dev/tty read -r REPO_USER < /dev/tty printf 'Пароль: ' > /dev/tty read -r -s REPO_PASS < /dev/tty echo > /dev/tty else echo "ERROR: репозиторий требует авторизации, а терминала нет." >&2 echo " Задайте REPO_USER и REPO_PASS в окружении." >&2 exit 1 fi fi # Учётные данные НЕ передаются аргументами: argv виден в ps любому локальному # пользователю. Только окружение. CURL_AUTH=() WGET_AUTH=() if [ -n "$REPO_USER" ]; then CURL_AUTH=(--user "${REPO_USER}:${REPO_PASS}") WGET_AUTH=(--user="${REPO_USER}" --password="${REPO_PASS}") fi echo "==> Downloading vps-installer ($BINARY_ARCH) ..." if command -v curl >/dev/null 2>&1; then # -f обязателен: без него тело HTTP-ошибки (например страница 401) попадает в # файл, и вместо внятного отказа получается неработающий «бинарник». if ! curl -fsSL "${CURL_AUTH[@]+"${CURL_AUTH[@]}"}" "$DOWNLOAD_URL" -o "$BINARY_PATH"; then echo "ERROR: не удалось скачать инсталлятор." >&2 [ -n "$REPO_USER" ] && echo " Проверьте логин и пароль репозитория." >&2 exit 1 fi elif command -v wget >/dev/null 2>&1; then if ! wget -q "${WGET_AUTH[@]+"${WGET_AUTH[@]}"}" -O "$BINARY_PATH" "$DOWNLOAD_URL"; then echo "ERROR: не удалось скачать инсталлятор." >&2 exit 1 fi else echo "ERROR: neither curl nor wget is available." >&2; exit 1 fi chmod +x "$BINARY_PATH" # The installer needs root (writes /etc/*, systemd units, firewall). Use sudo only # when a terminal is available for a possible password prompt. RUN=("$BINARY_PATH") if [ "$(id -u)" -ne 0 ]; then if command -v sudo >/dev/null 2>&1 && [ -t 1 ]; then RUN=(sudo "$BINARY_PATH") else echo "NOTE: run as root (or via sudo) — the installer configures system services." >&2 fi fi echo "==> Starting VPS Installer (Ctrl+C to stop)..." # Учётные данные уходят инсталлятору окружением. sudo по умолчанию сбрасывает # окружение, поэтому нужные переменные пробрасываются явно. if [ "${RUN[0]}" = "sudo" ]; then RUN=(sudo --preserve-env=REPO_USER,REPO_PASS,UPDATE_URL "$BINARY_PATH") fi export REPO_USER REPO_PASS UPDATE_URL if [ ${#ARGS[@]} -gt 0 ]; then exec "${RUN[@]}" "${ARGS[@]}" else exec "${RUN[@]}" fi