#!/bin/bash # install.sh — установка Bridge-and-Join-s одной командой. # # ЦЕЛЕВАЯ АУДИТОРИЯ: оператор без знания Linux/Go. Просто запускает строку: # # curl -sSL https://git.zetit.ru/zuevav/Bridge-and-Join-s/raw/main/deploy/astra/install.sh | sudo bash # # и всё работает. # # Поддерживаемые ОС: # - Astra Linux Special Edition 1.6 / 1.7 (платная, для прод) # - Astra Linux Common Edition / 1.8 (бесплатная) # - Debian 11 / 12 # - Ubuntu 22.04 / 24.04 (с предупреждением) # # Что устанавливается АВТОМАТИЧЕСКИ: # 1. Системные зависимости (apt: curl, git, podman, postgresql-client) # 2. Go 1.24+ (скачивается с go.dev) # 3. PostgreSQL 16 в podman-контейнере + миграции # 4. bj-server (компилируется из исходников, ставится в /opt/bj/) # 5. Дистрибутив ИШ НРД (скачивается с сайта НРД, ~120 МБ) # 6. Сам ИШ устанавливается через dpkg -i (но не запускается без Валидаты) # 7. systemd unit + автозапуск # # Что НЕ автоматизируется (только пользователь): # - СКЗИ Валидата CSP — выдаётся НРД по запросу (soed@nsd.ru) # - Сертификат подписи УЦ Московской Биржи (ca.moex.com) # - Регистрация в TEST3 (заявка через nsd.ru) set -euo pipefail # ---- параметры ---- REPO_URL="${REPO_URL:-https://git.zetit.ru/zuevav/Bridge-and-Join-s.git}" BRANCH="${BRANCH:-main}" BIND_ADDR="${BIND_ADDR:-:8080}" ISH_DEB_URL="${ISH_DEB_URL:-https://old.nsd.ru/upload/docs/edo/po/igate_100.0-765_amd64.deb}" SKIP_ISH=0 NON_INTERACTIVE="${NON_INTERACTIVE:-0}" for arg in "$@"; do case "$arg" in --skip-ish) SKIP_ISH=1 ;; --bind=*) BIND_ADDR="${arg#*=}" ;; --branch=*) BRANCH="${arg#*=}" ;; --yes|-y) NON_INTERACTIVE=1 ;; esac done # ---- утилиты вывода ---- NS=$(date +%s) step() { local n=$(( $(date +%s) - NS )); printf "\033[1;36m[%4ds]\033[0m \033[1;34m▶\033[0m %s\n" "$n" "$*"; } ok() { printf " \033[1;32m✓\033[0m %s\n" "$*"; } warn() { printf " \033[1;33m⚠\033[0m %s\n" "$*"; } fail() { printf " \033[1;31m✗\033[0m %s\n" "$*" >&2; exit 1; } ask() { [ "$NON_INTERACTIVE" = "1" ] && return 0 printf " \033[1;35m?\033[0m %s [y/N]: " "$*" read -r REPLY < /dev/tty || REPLY=n [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ] } # ---- баннер ---- clear 2>/dev/null || true cat <<'BANNER' ╔══════════════════════════════════════════════════════════════════╗ ║ ║ ║ Bridge-and-Join-s — установка с нуля ║ ║ сервис M2M-переводов с НКО АО НРД ║ ║ ║ ║ Установка займёт ~5-10 минут ║ ║ Скачается ~150-250 МБ (Go + ИШ + миграции) ║ ║ ║ ╚══════════════════════════════════════════════════════════════════╝ BANNER echo [ "$EUID" -eq 0 ] || fail "Запускать от root: sudo bash $0" # ============================================================ # ШАГ 1/9. Определение ОС # ============================================================ step "1/9: определение операционной системы" OS_KIND="" OS_NAME="неизвестно" if [ -r /etc/astra_version ]; then OS_NAME="Astra Linux $(cat /etc/astra_version)" OS_KIND="astra" elif [ -r /etc/os-release ]; then . /etc/os-release OS_NAME="$PRETTY_NAME" case "${ID:-}" in astra) OS_KIND="astra" ;; debian) OS_KIND="debian" ;; ubuntu) OS_KIND="ubuntu" ;; *) case "${ID_LIKE:-}" in *debian*) OS_KIND="debian-like" ;; esac ;; esac fi ok "Обнаружено: $OS_NAME" case "$OS_KIND" in astra) ok "Astra Linux — полностью поддерживается, ИШ заработает официально" ;; debian|"debian-like") warn "Debian-based — bj-server установится, ИШ скорее всего тоже" warn "(но официально НРД его не поддерживает на Debian; для прод-инфры лучше Astra Linux SE)" ;; ubuntu) warn "Ubuntu — bj-server установится, но ИШ может потребовать допилов" ask "Продолжить?" || exit 1 ;; *) fail "Неподдерживаемая ОС. Поддерживаются: Astra Linux (SE/CE), Debian, Ubuntu" ;; esac # ============================================================ # ШАГ 2/9. Системные пакеты # ============================================================ step "2/9: установка системных пакетов через apt" export DEBIAN_FRONTEND=noninteractive apt-get update -qq >/dev/null apt-get install -y -qq \ ca-certificates curl wget git tar gzip \ podman postgresql-client \ >/dev/null 2>&1 # podman-compose доступен либо как apt-пакет, либо как pip — пробуем оба if ! command -v podman-compose >/dev/null 2>&1; then apt-get install -y -qq podman-compose >/dev/null 2>&1 || \ apt-get install -y -qq python3-pip >/dev/null 2>&1 && pip3 install --quiet podman-compose 2>/dev/null || true fi command -v podman >/dev/null && ok "podman: $(podman --version | awk '{print $3}')" || fail "podman не установился" command -v git >/dev/null && ok "git: $(git --version | awk '{print $3}')" || fail "git не установился" # ============================================================ # ШАГ 3/9. Go 1.24+ # ============================================================ step "3/9: Go 1.24+" need_go=1 if command -v go >/dev/null 2>&1; then GO_HAVE=$(go version | awk '{print $3}' | sed 's/go//') if printf '%s\n%s' "1.24" "$GO_HAVE" | sort -V | head -1 | grep -q '^1.24$'; then ok "Go $GO_HAVE — подходит" need_go=0 else warn "Go $GO_HAVE — слишком старый, обновляю" fi fi if [ "$need_go" = 1 ]; then GO_VER="1.24.0" ok "качаю Go $GO_VER с go.dev (~70 МБ)..." curl -sSL "https://go.dev/dl/go${GO_VER}.linux-amd64.tar.gz" -o /tmp/go.tar.gz \ || fail "не получилось скачать Go (нужен интернет)" rm -rf /usr/local/go tar -C /usr/local -xzf /tmp/go.tar.gz ln -sf /usr/local/go/bin/go /usr/local/bin/go ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt rm -f /tmp/go.tar.gz ok "Go $GO_VER установлен в /usr/local/go" fi # ============================================================ # ШАГ 4/9. Пользователь bj и каталоги # ============================================================ step "4/9: системный пользователь bj и каталоги" if ! id bj >/dev/null 2>&1; then useradd --system --create-home --home-dir /var/lib/bj --shell /bin/bash bj ok "создан пользователь bj" else ok "пользователь bj уже существует" fi install -d -o bj -g bj -m 0755 /opt/bj /var/lib/bj /var/log/bj install -d -o bj -g bj -m 0700 /var/lib/bj/.bj ok "каталоги: /opt/bj /var/lib/bj /var/log/bj" # ============================================================ # ШАГ 5/9. Клон репо и сборка bj-server # ============================================================ step "5/9: клон репозитория и сборка bj-server" SRC=/opt/bj/src if [ -d "$SRC/.git" ]; then sudo -u bj -H git -C "$SRC" fetch --quiet origin sudo -u bj -H git -C "$SRC" reset --hard --quiet "origin/$BRANCH" ok "репо обновлено до $BRANCH" else sudo -u bj -H git clone --quiet --branch "$BRANCH" "$REPO_URL" "$SRC" \ || fail "git clone failed" ok "репо склонирован" fi chown -R bj:bj "$SRC" ok "компиляция bj-server..." sudo -u bj -H bash -c "cd $SRC && /usr/local/bin/go build -o /opt/bj/bj-server ./cmd/bj-server" \ || fail "go build failed" chown bj:bj /opt/bj/bj-server chmod 0755 /opt/bj/bj-server ok "бинарник: /opt/bj/bj-server ($(du -h /opt/bj/bj-server | awk '{print $1}'))" # ============================================================ # ШАГ 6/9. PostgreSQL в podman + миграции # ============================================================ step "6/9: PostgreSQL в podman + миграции БД" cd "$SRC" if ! podman ps --format '{{.Names}}' 2>/dev/null | grep -qx bj-postgres; then sudo -u bj -H podman-compose -f deploy/docker-compose/docker-compose.yml up -d postgres \ 2>/dev/null || { warn "podman-compose не сработал, пробую podman run напрямую" sudo -u bj -H podman run -d --name bj-postgres \ -e POSTGRES_USER=bj -e POSTGRES_PASSWORD=bj_dev -e POSTGRES_DB=bj \ -p 127.0.0.1:5432:5432 \ docker.io/library/postgres:16-alpine } sleep 5 fi # Ждём pg_isready for i in 1 2 3 4 5 6 7 8 9 10; do if sudo -u bj -H podman exec bj-postgres pg_isready -U bj -d bj >/dev/null 2>&1; then ok "PostgreSQL готов" break fi sleep 2 done # Накат миграций MIG_COUNT=0 for mig in migrations/fansy-store/*.sql migrations/m2m-core/*.sql; do if [ -f "$mig" ]; then sudo -u bj -H podman exec -i bj-postgres psql -U bj -d bj -v ON_ERROR_STOP=0 < "$mig" >/dev/null 2>&1 && \ MIG_COUNT=$((MIG_COUNT+1)) fi done ok "миграций накачено: $MIG_COUNT" # Сохраняем DSN cat > /var/lib/bj/.bj/setup.json < /etc/systemd/system/bj-server.service </dev/null 2>&1 systemctl restart bj-server sleep 2 if systemctl is-active --quiet bj-server; then ok "bj-server.service active" else warn "bj-server не стартанул, см. journalctl -u bj-server -n 30" fi # ============================================================ # ШАГ 8/9. ИШ НРД — скачивание и установка # ============================================================ if [ "$SKIP_ISH" = "1" ]; then step "8/9: ИШ НРД — пропущено (--skip-ish)" else step "8/9: Интеграционный шлюз НРД (ИШ)" ISH_LOCAL="$SRC/dist/ish/igate_100.0-765_amd64.deb" if [ -f "$ISH_LOCAL" ]; then ok "дистрибутив ИШ уже в репо: $ISH_LOCAL" else ok "качаю дистрибутив ИШ с НРД (~120 МБ)..." mkdir -p "$(dirname "$ISH_LOCAL")" if curl -sSL -A "Mozilla/5.0" "$ISH_DEB_URL" -o "$ISH_LOCAL" --max-time 600; then ok "скачан: $(du -h "$ISH_LOCAL" | awk '{print $1}')" else warn "не получилось скачать ИШ автоматически" warn "скачайте вручную: $ISH_DEB_URL" warn "и положите в $ISH_LOCAL, потом перезапустите этот скрипт" ISH_LOCAL="" fi fi if [ -n "$ISH_LOCAL" ] && [ -f "$ISH_LOCAL" ]; then ok "установка ИШ через dpkg..." if dpkg -i "$ISH_LOCAL" >/dev/null 2>&1; then ok "ИШ установлен" else # Часто dpkg падает на зависимостях — пробуем apt-get install -f apt-get install -f -y >/dev/null 2>&1 if dpkg -i "$ISH_LOCAL" >/dev/null 2>&1; then ok "ИШ установлен (после починки зависимостей)" else warn "ИШ не встал — возможно нет Валидаты или системных пакетов" warn "это нормально на текущем этапе — продолжаем" fi fi fi fi # ============================================================ # ШАГ 9/9. Финальная проверка # ============================================================ step "9/9: проверка готовности" sleep 1 CODE=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1${BIND_ADDR}/admin/" 2>/dev/null || echo "—") [ "$CODE" = "200" ] && ok "веб-админка отвечает: HTTP 200" || warn "веб-админка пока не отвечает (HTTP $CODE) — проверь логи" IP=$(hostname -I | awk '{print $1}') echo echo "╔══════════════════════════════════════════════════════════════════╗" echo "║ УСТАНОВКА BJ-SERVER ЗАВЕРШЕНА ║" echo "╚══════════════════════════════════════════════════════════════════╝" echo echo " Веб-админка: http://$IP${BIND_ADDR}/admin/" echo " Мастер настройки: http://$IP${BIND_ADDR}/admin/wizard" echo " Архитектура: http://$IP${BIND_ADDR}/admin/help/architecture" echo " Новости: http://$IP${BIND_ADDR}/admin/news" echo echo " Логи: tail -f /var/log/bj/bj-server.log" echo " Сервис: systemctl status bj-server" echo echo " ──── ЧТО ОСТАЛОСЬ СДЕЛАТЬ (НЕ АВТОМАТИЧЕСКИ) ───────────────" echo echo " 1. Запросить СКЗИ Валидата CSP у НРД:" echo " Email: soed@nsd.ru" echo " Текст: «Запрос дистрибутива Валидата CSP для Linux + временной" echo " лицензии для подключения к ЭДО НРД в рамках MOEX МОСТ M2M.»" echo echo " 2. Получить сертификат подписи в УЦ Московской Биржи:" echo " https://ca.moex.com/" echo echo " 3. Подать заявку на тестирование в TEST3:" echo " https://www.nsd.ru/workflow/zayavka-na-testirovanie/" echo echo " 4. Когда придёт Валидата — поставить:" echo " sudo bash $SRC/deploy/astra/install-validata.sh /path/to/validata-*.deb" echo echo " 5. Когда заработает ИШ — указать его URL в /admin/setup → «ИШ НРД»" echo echo " ──── ПРОВЕРКА СОСТОЯНИЯ ВСЕГО ──────────────────────────────" echo " sudo bash $SRC/deploy/astra/healthcheck.sh" echo