feat: интерактивный установщик install.sh (Docker / Ubuntu, админ, БД)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shop
2026-05-17 13:57:54 +03:00
parent dedef454c8
commit db4bc9bfe1
28 changed files with 1069 additions and 22 deletions
+257
View File
@@ -0,0 +1,257 @@
#!/bin/bash
# Интерактивный установщик Shop
# bash scripts/install.sh
# sudo bash scripts/install.sh (нативная установка на Ubuntu)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# --- ввод ---
read_default() {
local prompt="$1"
local default="$2"
local value
if [ -n "$default" ]; then
read -rp "$prompt [$default]: " value
echo "${value:-$default}"
else
read -rp "$prompt: " value
echo "$value"
fi
}
read_secret() {
local prompt="$1"
local value
read -rsp "$prompt" value
echo ""
echo "$value"
}
read_secret_confirm() {
local prompt="$1"
local a b
while true; do
a=$(read_secret "$prompt")
b=$(read_secret "Повторите: ")
if [ "$a" = "$b" ]; then
echo "$a"
return
fi
echo "Пароли не совпадают. Попробуйте снова."
done
}
gen_secret() {
if command -v openssl >/dev/null; then
openssl rand -hex 32
else
head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n'
fi
}
# Безопасная запись значения в .env (одинарные кавычки)
env_quote() {
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
}
email_ok() {
[[ "$1" =~ ^[^\s@]+@[^\s@]+\.[^\s@]+$ ]]
}
# --- главная ---
clear 2>/dev/null || true
echo "============================================"
echo " Shop — интерактивная установка"
echo "============================================"
echo ""
# Каталог установки
if [ -f "$REPO_ROOT/package.json" ]; then
INSTALL_DIR=$(read_default "Каталог установки" "$REPO_ROOT")
else
INSTALL_DIR=$(read_default "Каталог установки" "/opt/shop")
if [ ! -f "$INSTALL_DIR/package.json" ]; then
GIT_URL=$(read_default "URL git-репозитория" "")
if [ -z "$GIT_URL" ]; then
echo "Ошибка: укажите URL репозитория или запустите установщик из клона."
exit 1
fi
echo "Клонирование $GIT_URL -> $INSTALL_DIR ..."
mkdir -p "$(dirname "$INSTALL_DIR")"
git clone "$GIT_URL" "$INSTALL_DIR"
fi
fi
cd "$INSTALL_DIR"
export SHOP_ROOT="$INSTALL_DIR"
# Режим
echo ""
echo "Способ установки:"
echo " 1) Docker Compose (PostgreSQL + приложение в контейнерах)"
echo " 2) Без Docker (Ubuntu: Node.js + PostgreSQL + systemd)"
echo ""
MODE=$(read_default "Выберите [1/2]" "1")
# Администратор
echo ""
echo "--- Администратор магазина (единственный admin) ---"
ADMIN_EMAIL=$(read_default "Email администратора" "admin@site.com")
while ! email_ok "$ADMIN_EMAIL"; do
echo "Некорректный email."
ADMIN_EMAIL=$(read_default "Email администратора" "admin@site.com")
done
ADMIN_NAME=$(read_default "Имя администратора" "Администратор")
ADMIN_PASSWORD=$(read_secret_confirm "Пароль администратора: ")
# База данных
echo ""
echo "--- PostgreSQL ---"
PG_USER=$(read_default "Пользователь БД" "shop")
PG_PASS=$(read_secret_confirm "Пароль БД: ")
PG_DB=$(read_default "Имя базы данных" "shop")
if [ "$MODE" = "1" ]; then
PG_HOST="postgres"
PG_PORT="5432"
APP_PORT=$(read_default "Порт сайта на хосте" "3000")
TRUST_PROXY="0"
echo ""
read -rp "Включить Caddy (HTTPS, порты 80/443)? [y/N]: " USE_CADDY
if [[ "${USE_CADDY,,}" == "y" || "${USE_CADDY,,}" == "yes" ]]; then
TRUST_PROXY="1"
USE_CADDY=1
else
USE_CADDY=0
fi
else
PG_HOST=$(read_default "Хост PostgreSQL" "127.0.0.1")
PG_PORT=$(read_default "Порт PostgreSQL" "5432")
APP_PORT="3000"
TRUST_PROXY=$(read_default "За reverse proxy (Caddy)? TRUST_PROXY [1/0]" "1")
USE_CADDY=0
fi
# Сайт и секрет
echo ""
echo "--- Прочие настройки ---"
if [ "$MODE" = "1" ] && [ "$USE_CADDY" = "1" ]; then
SITE_DEFAULT="https://shop.example.com"
else
SITE_DEFAULT="http://localhost:${APP_PORT}"
fi
SITE_URL=$(read_default "URL сайта (SITE_URL)" "$SITE_DEFAULT")
SESSION_SECRET=$(read_default "SESSION_SECRET (Enter = сгенерировать)" "")
SESSION_SECRET=${SESSION_SECRET:-$(gen_secret)}
echo ""
read -rp "Настроить SMTP для писем? [y/N]: " SET_SMTP
SMTP_BLOCK=""
if [[ "${SET_SMTP,,}" == "y" || "${SET_SMTP,,}" == "yes" ]]; then
SMTP_HOST=$(read_default "SMTP_HOST" "smtp.example.com")
SMTP_PORT=$(read_default "SMTP_PORT" "587")
SMTP_USER=$(read_default "SMTP_USER" "")
SMTP_PASS=$(read_secret "SMTP_PASS: ")
SMTP_FROM=$(read_default "SMTP_FROM" "shop@example.com")
SMTP_BLOCK="# SMTP
SMTP_HOST=${SMTP_HOST}
SMTP_PORT=${SMTP_PORT}
SMTP_SECURE=false
SMTP_USER=${SMTP_USER}
SMTP_PASS=${SMTP_PASS}
SMTP_FROM=${SMTP_FROM}
"
fi
DATABASE_URL="postgresql://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}"
# --- запись .env ---
ENV_FILE="$INSTALL_DIR/.env"
APP_HOST=$([ "$MODE" = "1" ] && echo "0.0.0.0" || echo "127.0.0.1")
{
echo "# Создано scripts/install.sh $(date -Iseconds)"
echo ""
echo "PORT=${APP_PORT}"
echo "HOST=${APP_HOST}"
echo "NODE_ENV=production"
echo "TRUST_PROXY=${TRUST_PROXY}"
echo "SESSION_SECRET=$(env_quote "$SESSION_SECRET")"
echo ""
echo "ADMIN_EMAIL=$(env_quote "$ADMIN_EMAIL")"
echo "ADMIN_PASSWORD=$(env_quote "$ADMIN_PASSWORD")"
echo "ADMIN_NAME=$(env_quote "$ADMIN_NAME")"
echo ""
echo "SITE_URL=$(env_quote "$SITE_URL")"
echo ""
if [ -n "$SMTP_BLOCK" ]; then
echo "$SMTP_BLOCK"
fi
echo "# PostgreSQL"
echo "POSTGRES_USER=$(env_quote "$PG_USER")"
echo "POSTGRES_PASSWORD=$(env_quote "$PG_PASS")"
echo "POSTGRES_DB=$(env_quote "$PG_DB")"
echo "DATABASE_URL=$(env_quote "$DATABASE_URL")"
echo "PGHOST=$(env_quote "$PG_HOST")"
echo "PGPORT=${PG_PORT}"
echo "PGUSER=$(env_quote "$PG_USER")"
echo "PGPASSWORD=$(env_quote "$PG_PASS")"
echo "PGDATABASE=$(env_quote "$PG_DB")"
} > "$ENV_FILE"
chmod 600 "$ENV_FILE" 2>/dev/null || true
echo ""
echo "Сохранено: $ENV_FILE"
# --- установка ---
echo ""
if [ "$MODE" = "1" ]; then
echo "=== Установка через Docker ==="
if ! command -v docker >/dev/null; then
echo "Ошибка: Docker не установлен. Установите Docker и повторите."
exit 1
fi
if ! docker compose version >/dev/null 2>&1; then
echo "Ошибка: нужен Docker Compose v2 (docker compose)."
exit 1
fi
COMPOSE_CMD=(docker compose)
if [ "$USE_CADDY" = "1" ]; then
echo "Запуск: postgres + app + caddy ..."
"${COMPOSE_CMD[@]}" --profile proxy up -d --build
else
echo "Запуск: postgres + app ..."
"${COMPOSE_CMD[@]}" up -d --build
fi
echo "Ожидание health..."
sleep 5
curl -sf "http://127.0.0.1:${APP_PORT}/health" && echo "" || echo "Проверьте: docker compose logs app"
else
echo "=== Установка без Docker (Ubuntu) ==="
if [ "$(id -u)" -ne 0 ]; then
echo "Запустите с root: sudo bash scripts/install.sh"
exit 1
fi
bash "$SCRIPT_DIR/install-postgresql-ubuntu.sh"
export DB_USER="$PG_USER" DB_PASS="$PG_PASS" DB_NAME="$PG_DB"
bash "$SCRIPT_DIR/setup-postgres-ubuntu.sh"
npm install --omit=dev
bash "$SCRIPT_DIR/install-shop-service.sh"
fi
echo ""
echo "============================================"
echo " Установка завершена"
echo "============================================"
echo " Каталог: $INSTALL_DIR"
echo " Сайт: $SITE_URL"
echo " Админ: $ADMIN_EMAIL"
if [ "$MODE" = "1" ]; then
echo " Порт: $APP_PORT"
echo " Логи: docker compose -f $INSTALL_DIR/docker-compose.yml logs -f"
else
echo " Служба: systemctl status shop"
echo " Health: curl http://127.0.0.1:3000/health"
fi
echo " Обновление: bash $INSTALL_DIR/scripts/server-update.sh"
echo "============================================"