chore: remove obsolete deploy scripts and docs
This commit is contained in:
@@ -1,64 +0,0 @@
|
||||
# First-time LAN deploy: bootstrap, craftshop-remote-lan.env, deploy-ssh.ps1 -All, systemd.
|
||||
# Prerequisites: SSH to root works with key (see register-ssh-key-for-root.ps1).
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$scriptsDir = $PSScriptRoot
|
||||
$repoRoot = (Resolve-Path (Join-Path $scriptsDir "..")).Path
|
||||
$deployEnv = Join-Path $scriptsDir "deploy.env"
|
||||
|
||||
if (-not (Test-Path $deployEnv)) {
|
||||
Write-Error "Missing scripts/deploy.env - copy deploy.env.example and set DEPLOY_HOST."
|
||||
}
|
||||
|
||||
. "$PSScriptRoot\read-deploy-env.ps1"
|
||||
Import-DeployDotEnv $deployEnv
|
||||
|
||||
$deployHost = [Environment]::GetEnvironmentVariable("DEPLOY_HOST", "Process")
|
||||
$user = [Environment]::GetEnvironmentVariable("DEPLOY_USER", "Process")
|
||||
if ([string]::IsNullOrWhiteSpace($user)) { $user = "root" }
|
||||
if ([string]::IsNullOrWhiteSpace($deployHost)) {
|
||||
Write-Error "DEPLOY_HOST is missing in scripts/deploy.env."
|
||||
}
|
||||
|
||||
$remote = "${user}@${deployHost}"
|
||||
$bootstrap = Join-Path $scriptsDir "server-bootstrap.sh"
|
||||
$lanEnv = Join-Path $scriptsDir "craftshop-remote-lan.env"
|
||||
|
||||
if (-not (Test-Path $bootstrap)) {
|
||||
Write-Error "Bootstrap script not found: $bootstrap"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $lanEnv)) {
|
||||
Write-Error "Missing scripts/craftshop-remote-lan.env (gitignored). Create it or copy from server/.env.example."
|
||||
}
|
||||
|
||||
ssh -o BatchMode=yes -o ConnectTimeout=8 $remote "echo ok" 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Passwordless SSH to $remote failed. Run .\scripts\register-ssh-key-for-root.ps1 first."
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ">>> scp bootstrap"
|
||||
scp -o StrictHostKeyChecking=accept-new $bootstrap "${remote}:/root/server-bootstrap.sh"
|
||||
|
||||
Write-Host ">>> run bootstrap on server"
|
||||
ssh $remote "bash /root/server-bootstrap.sh"
|
||||
|
||||
Write-Host ">>> scp server .env"
|
||||
scp -o StrictHostKeyChecking=accept-new $lanEnv "${remote}:/opt/craftshop/server/.env"
|
||||
|
||||
Write-Host ">>> chmod .env (owner = same as /opt/craftshop/server, deploy or root)"
|
||||
ssh $remote "chown --reference=/opt/craftshop/server /opt/craftshop/server/.env || chown root:root /opt/craftshop/server/.env; chmod 600 /opt/craftshop/server/.env"
|
||||
|
||||
Set-Location $repoRoot
|
||||
Write-Host ">>> deploy-ssh.ps1 -All"
|
||||
& (Join-Path $scriptsDir "deploy-ssh.ps1") -All
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
|
||||
Write-Host ">>> systemd enable craftshop-api"
|
||||
ssh $remote "systemctl enable --now craftshop-api"
|
||||
|
||||
Write-Host ">>> health check"
|
||||
ssh $remote "curl -sS http://127.0.0.1:3333/health"
|
||||
|
||||
Write-Host "Done. Open http://${deployHost}/"
|
||||
@@ -1,82 +0,0 @@
|
||||
# Вызывает deploy-ssh.sh через bash (Git for Windows или bash в PATH).
|
||||
# Запускайте из корня репозитория или откуда угодно — скрипт перейдёт в root.
|
||||
|
||||
param(
|
||||
[switch]$FrontendOnly,
|
||||
[switch]$BackendOnly,
|
||||
[switch]$All,
|
||||
[switch]$DryRun,
|
||||
[switch]$SkipBuild,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$scriptsDir = $PSScriptRoot
|
||||
$repoRoot = (Resolve-Path (Join-Path $scriptsDir "..")).Path
|
||||
|
||||
$gitUsrRs = "C:\Program Files\Git\usr\bin\rsync.exe"
|
||||
$chocoRsDir = "C:\ProgramData\chocolatey\bin"
|
||||
$chocoRs = Join-Path $chocoRsDir "rsync.exe"
|
||||
if (Test-Path -LiteralPath $gitUsrRs) {
|
||||
$env:Path = "C:\Program Files\Git\usr\bin;$env:Path"
|
||||
} elseif (Test-Path -LiteralPath $chocoRs) {
|
||||
$env:Path = "$chocoRsDir;$env:Path"
|
||||
}
|
||||
|
||||
function Show-Help {
|
||||
@"
|
||||
Использование (рядом с репозиторием или из любого каталога):
|
||||
.\scripts\deploy-ssh.ps1 [-FrontendOnly] [-BackendOnly] [-All]
|
||||
.\scripts\deploy-ssh.ps1 -DryRun -BackendOnly
|
||||
|
||||
Конфиг: scripts/deploy.env (скопируйте из deploy.env.example).
|
||||
|
||||
Нужны: bash (Git for Windows) и rsync в PATH. rsync без Git: установите пакет (например, choco install rsync).
|
||||
|
||||
Если npm ci падает с EPERM на .node (Windows): остановите Vite/Node, затем снова .\scripts\deploy-ssh.ps1
|
||||
Или: cd client; npm run build; затем .\scripts\deploy-ssh.ps1 -SkipBuild (только выкладка dist).
|
||||
"@ | Write-Host
|
||||
}
|
||||
|
||||
if ($Help) { Show-Help; exit 0 }
|
||||
|
||||
$bash = Get-Command bash -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source
|
||||
if (-not $bash) {
|
||||
$git = "C:\Program Files\Git\bin\bash.exe"
|
||||
if (Test-Path $git) { $bash = $git }
|
||||
}
|
||||
if (-not $bash) {
|
||||
Write-Error "Не найден bash. Установите Git for Windows и добавьте Git\usr\bin в PATH (rsync)."
|
||||
}
|
||||
|
||||
if (-not (Get-Command rsync -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "Не найден rsync. Установите: choco install rsync -y либо добавьте C:\Program Files\Git\usr\bin в PATH."
|
||||
}
|
||||
|
||||
$argsToSh = [System.Collections.ArrayList]@()
|
||||
if ($FrontendOnly) { [void]$argsToSh.Add("--frontend-only") }
|
||||
elseif ($BackendOnly) { [void]$argsToSh.Add("--backend-only") }
|
||||
else { [void]$argsToSh.Add("--all") }
|
||||
|
||||
if ($DryRun) { [void]$argsToSh.Add("--dry-run") }
|
||||
if ($SkipBuild) { [void]$argsToSh.Add("--skip-build") }
|
||||
|
||||
function ConvertTo-MsysPath {
|
||||
param([string]$Path)
|
||||
$full = if (Test-Path $Path) { (Resolve-Path -LiteralPath $Path).Path } else { $Path }
|
||||
if ($full -match '^([A-Za-z]):[\\/](.*)$') {
|
||||
return "/" + $Matches[1].ToLower() + "/" + ($Matches[2] -replace '\\', '/')
|
||||
}
|
||||
return ($full -replace '\\', '/')
|
||||
}
|
||||
|
||||
$sh = Join-Path $scriptsDir "deploy-ssh.sh"
|
||||
$shUnix = ConvertTo-MsysPath $sh
|
||||
Push-Location $repoRoot
|
||||
try {
|
||||
& $bash $shUnix @argsToSh
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Деплой по SSH: отдельно фронт (сборка + rsync dist), бэк (rsync + npm ci + prisma migrate).
|
||||
#
|
||||
# Требования: bash, ssh; на Linux/macOS используется rsync, на Git Bash/WIN — tar|ssh (обход проблем cwRsync с путами).
|
||||
#
|
||||
# Конфиг: переменные окружения или файл scripts/deploy.env (скопируйте из scripts/deploy.env.example).
|
||||
#
|
||||
# Примеры:
|
||||
# ./scripts/deploy-ssh.sh --backend-only
|
||||
# ./scripts/deploy-ssh.sh --frontend-only
|
||||
# ./scripts/deploy-ssh.sh --all
|
||||
# DEPLOY_HOST=10.0.0.5 ./scripts/deploy-ssh.sh -b
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Git Bash вызывает Win32 ssh.exe: аргументы вроде /opt/... иначе подменяются → «mkdir: missing operand».
|
||||
case "$(uname -s 2>/dev/null)" in
|
||||
MINGW* | MSYS*) export MSYS2_ARG_CONV_EXCL="*" ;;
|
||||
esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# Загрузка deploy.env без перезаписи уже экспортированных переменных
|
||||
if [[ -f "$SCRIPT_DIR/deploy.env" ]]; then
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$SCRIPT_DIR/deploy.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
DEPLOY_HOST="${DEPLOY_HOST:-}"
|
||||
DEPLOY_USER="${DEPLOY_USER:-root}"
|
||||
DEPLOY_PATH="${DEPLOY_PATH:-/opt/craftshop}"
|
||||
DEPLOY_FRONTEND_DIST="${DEPLOY_FRONTEND_DIST:-$DEPLOY_PATH/www}"
|
||||
DEPLOY_SSH_IDENTITY="${DEPLOY_SSH_IDENTITY:-}"
|
||||
DEPLOY_RESTART_CMD="${DEPLOY_RESTART_CMD:-}" # от root: systemctl restart craftshop-api; от непривилегированного: sudo …
|
||||
# При SSH от root файлы после rsync оказываются root:root; если API в systemd под другим пользователем (bootstrap: deploy), нужен chown:
|
||||
DEPLOY_SERVER_OWNER="${DEPLOY_SERVER_OWNER:-deploy}"
|
||||
DEPLOY_SKIP_CHOWN="${DEPLOY_SKIP_CHOWN:-0}" # 1 — не вызывать chown (например API тоже под root)
|
||||
|
||||
RSYNC_OPTS=(-az --delete --human-readable --progress)
|
||||
SSH_OPTS=()
|
||||
if [[ -n "${DEPLOY_SSH_IDENTITY}" ]]; then
|
||||
SSH_OPTS+=(-i "$DEPLOY_SSH_IDENTITY")
|
||||
fi
|
||||
|
||||
REMOTE="${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
SSH_BASE=(ssh "${SSH_OPTS[@]}" -o StrictHostKeyChecking=accept-new "$REMOTE")
|
||||
|
||||
should_use_tar_transport() {
|
||||
case "$(uname -s 2>/dev/null)" in
|
||||
MINGW*|MSYS*|CYGWIN_NT*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Использование: $(basename "$0") [опции]
|
||||
|
||||
--frontend-only | -f Деплой только фронта (локальная сборка + rsync dist)
|
||||
--backend-only | -b Деплой только бэкенда (rsync server + npm ci + prisma)
|
||||
--all | -a Оба компонента (по умолчанию)
|
||||
|
||||
--dry-run Только показать команды rsync (без записи на сервер)
|
||||
--skip-build Не вызывать npm run build (использовать текущий client/dist)
|
||||
|
||||
Окружение (или scripts/deploy.env):
|
||||
DEPLOY_HOST хост SSH (обязательно)
|
||||
DEPLOY_USER пользователь SSH (по умолчанию: root)
|
||||
DEPLOY_PATH корень приложения на сервере (по умолчанию: /opt/craftshop)
|
||||
DEPLOY_FRONTEND_DIST каталог под статику SPA (по умолчанию: \$DEPLOY_PATH/www)
|
||||
DEPLOY_SSH_IDENTITY путь к приватному ключу (-i ssh)
|
||||
DEPLOY_RESTART_CMD команда после бэкенд-деплоя (опционально; под root без sudo)
|
||||
DEPLOY_SERVER_OWNER при DEPLOY_USER=root: владелец \$DEPLOY_PATH/server после деплоя (по умолчанию: deploy)
|
||||
DEPLOY_SKIP_CHOWN 1 — не менять владельца каталога server (если процесс под root и т.п.)
|
||||
USAGE
|
||||
}
|
||||
|
||||
TARGET="all"
|
||||
DRY_RUN=""
|
||||
SKIP_BUILD=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--frontend-only | -f) TARGET="frontend" ;;
|
||||
--backend-only | -b) TARGET="backend" ;;
|
||||
--all | -a) TARGET="all" ;;
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
--skip-build) SKIP_BUILD=1 ;;
|
||||
-h | --help) usage; exit 0 ;;
|
||||
*) echo "Неизвестный аргумент: $1" >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ -z "$DEPLOY_HOST" ]]; then
|
||||
echo "Укажите DEPLOY_HOST (или добавьте в scripts/deploy.env)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
remote_exec() {
|
||||
"${SSH_BASE[@]}" "$@"
|
||||
}
|
||||
|
||||
if [[ -n "$DRY_RUN" ]]; then
|
||||
RSYNC_OPTS+=(--dry-run)
|
||||
fi
|
||||
|
||||
# Строка для rsync -e (одна подкоманда; пути без пробелов в -i надёжнее)
|
||||
build_rsync_rsh() {
|
||||
printf '%q ' ssh "${SSH_OPTS[@]}" -o StrictHostKeyChecking=accept-new
|
||||
}
|
||||
|
||||
deploy_backend() {
|
||||
remote_exec mkdir -p "$DEPLOY_PATH/server"
|
||||
remote_exec mkdir -p "$DEPLOY_PATH/shared"
|
||||
|
||||
if should_use_tar_transport; then
|
||||
echo ">>> Бэкенд (server): tar|ssh → $REMOTE:$DEPLOY_PATH/server/"
|
||||
if [[ -n "$DRY_RUN" ]]; then
|
||||
echo "(dry-run) без передачи tar"
|
||||
else
|
||||
(
|
||||
cd "$ROOT/server" || exit 1
|
||||
tar -czf - \
|
||||
--exclude=node_modules \
|
||||
--exclude=uploads \
|
||||
--exclude=.git \
|
||||
--exclude='*.db' \
|
||||
--exclude=.env \
|
||||
--exclude=.dev_env \
|
||||
.
|
||||
) | "${SSH_BASE[@]}" "mkdir -p ${DEPLOY_PATH}/server && tar xzf - -C ${DEPLOY_PATH}/server"
|
||||
|
||||
echo ">>> Бэкенд (shared): tar|ssh → $REMOTE:$DEPLOY_PATH/shared/"
|
||||
(
|
||||
cd "$ROOT/shared" || exit 1
|
||||
tar -czf - \
|
||||
--exclude=.git \
|
||||
.
|
||||
) | "${SSH_BASE[@]}" "mkdir -p ${DEPLOY_PATH}/shared && tar xzf - -C ${DEPLOY_PATH}/shared"
|
||||
fi
|
||||
else
|
||||
echo ">>> Бэкенд (server): rsync → $REMOTE:$DEPLOY_PATH/server/"
|
||||
local rsh
|
||||
rsh="$(build_rsync_rsh)"
|
||||
|
||||
rsync "${RSYNC_OPTS[@]}" \
|
||||
-e "$rsh" \
|
||||
--exclude node_modules \
|
||||
--exclude uploads \
|
||||
--exclude .git \
|
||||
--exclude '*.db' \
|
||||
--exclude .env \
|
||||
--exclude .dev_env \
|
||||
"${ROOT}/server/" "${REMOTE}:${DEPLOY_PATH}/server/"
|
||||
|
||||
echo ">>> Бэкенд (shared): rsync → $REMOTE:$DEPLOY_PATH/shared/"
|
||||
rsync "${RSYNC_OPTS[@]}" \
|
||||
-e "$rsh" \
|
||||
--exclude .git \
|
||||
"${ROOT}/shared/" "${REMOTE}:${DEPLOY_PATH}/shared/"
|
||||
fi
|
||||
|
||||
if [[ -n "$DRY_RUN" ]]; then
|
||||
echo "(dry-run) пропуск удалённых команд npm/prisma"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ">>> Бэкенд: npm ci, prisma generate, migrate deploy на сервере"
|
||||
remote_exec bash -lc "set -e
|
||||
cd \"$DEPLOY_PATH/server\"
|
||||
npm ci
|
||||
npx prisma generate
|
||||
npx prisma migrate deploy
|
||||
"
|
||||
if [[ "${DEPLOY_USER}" == "root" && "${DEPLOY_SKIP_CHOWN}" != "1" ]]; then
|
||||
echo ">>> Права на серверный каталог: chown ${DEPLOY_SERVER_OWNER} (деплой от root)"
|
||||
remote_exec chown -R "${DEPLOY_SERVER_OWNER}:${DEPLOY_SERVER_OWNER}" "$DEPLOY_PATH/server"
|
||||
remote_exec chown -R "${DEPLOY_SERVER_OWNER}:${DEPLOY_SERVER_OWNER}" "$DEPLOY_PATH/shared"
|
||||
fi
|
||||
if [[ -n "${DEPLOY_RESTART_CMD}" ]]; then
|
||||
echo ">>> Рестарт: $DEPLOY_RESTART_CMD"
|
||||
remote_exec bash -lc "$DEPLOY_RESTART_CMD"
|
||||
elif [[ -z "$DRY_RUN" ]]; then
|
||||
echo "" >&2
|
||||
echo "ВНИМАНИЕ: код сервера обновлён, но процесс Node не перезапущен." >&2
|
||||
echo " Без рестарта новые маршруты (и правки API) не появятся." >&2
|
||||
echo " Задайте в deploy.env: DEPLOY_RESTART_CMD='systemctl restart <ваш-сервис-api>'" >&2
|
||||
echo "" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_frontend() {
|
||||
if [[ -z "$SKIP_BUILD" ]]; then
|
||||
echo ">>> Фронт: npm ci и npm run build (локально)"
|
||||
# Windows: ESLint/typescript-eslint тянут @unrs/*.node — npm ci часто получает EPERM unlink, если файл держит Node/IDE или остался мусор .resolver-binding-* после сбоя.
|
||||
if should_use_tar_transport; then
|
||||
echo ">>> (Windows/Git Bash) перед npm ci: снимаем блокировки нативных .node (@unrs, @rolldown, .resolver-binding-*)"
|
||||
echo ">>> Подсказка: остановите «npm run dev» / dev-серверы и IDE, если EPERM останется."
|
||||
rm -rf "$ROOT/client/node_modules/@unrs" "$ROOT/client/node_modules/@rolldown" 2>/dev/null || true
|
||||
(
|
||||
cd "$ROOT/client/node_modules" 2>/dev/null || exit 0
|
||||
shopt -s nullglob
|
||||
for x in ./.resolver-binding-*; do
|
||||
[[ -d "$x" ]] && rm -rf "$x"
|
||||
done
|
||||
)
|
||||
fi
|
||||
(cd "$ROOT/client" && npm ci && npm run build) || {
|
||||
echo "" >&2
|
||||
echo "Сборка фронта не удалась. На Windows часто EPERM на .node — закройте процессы Node (dev-сервер), повторите." >&2
|
||||
echo "Или соберите фронт вручную (cd client && npm run build), затем: $0 --frontend-only --skip-build" >&2
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
echo ">>> Фронт: сборка пропущена (--skip-build)"
|
||||
if [[ ! -d "$ROOT/client/dist" ]]; then
|
||||
echo "Нет $ROOT/client/dist — выполните сборку без --skip-build" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
remote_exec mkdir -p "$DEPLOY_FRONTEND_DIST"
|
||||
|
||||
if should_use_tar_transport; then
|
||||
echo ">>> Фронт: tar|ssh dist → $REMOTE:$DEPLOY_FRONTEND_DIST/"
|
||||
if [[ -n "$DRY_RUN" ]]; then
|
||||
echo "(dry-run) без передачи tar (www)"
|
||||
else
|
||||
remote_exec "mkdir -p ${DEPLOY_FRONTEND_DIST} && find ${DEPLOY_FRONTEND_DIST} -mindepth 1 -delete 2>/dev/null || true"
|
||||
(
|
||||
cd "$ROOT/client/dist" || exit 1
|
||||
tar -czf - .
|
||||
) | "${SSH_BASE[@]}" "mkdir -p ${DEPLOY_FRONTEND_DIST} && tar xzf - -C ${DEPLOY_FRONTEND_DIST}"
|
||||
fi
|
||||
else
|
||||
echo ">>> Фронт: rsync dist → $REMOTE:$DEPLOY_FRONTEND_DIST/"
|
||||
local rsh
|
||||
rsh="$(build_rsync_rsh)"
|
||||
rsync "${RSYNC_OPTS[@]}" \
|
||||
-e "$rsh" \
|
||||
"${ROOT}/client/dist/" "${REMOTE}:${DEPLOY_FRONTEND_DIST}/"
|
||||
fi
|
||||
|
||||
echo ">>> Фронт готов (проверьте nginx/root на путь $DEPLOY_FRONTEND_DIST)"
|
||||
}
|
||||
|
||||
case "$TARGET" in
|
||||
backend) deploy_backend ;;
|
||||
frontend) deploy_frontend ;;
|
||||
all)
|
||||
deploy_backend
|
||||
deploy_frontend
|
||||
;;
|
||||
*) echo "internal: bad TARGET=$TARGET" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo "Готово."
|
||||
@@ -1,19 +0,0 @@
|
||||
# Скопируйте в deploy.env рядом с deploy-ssh.sh и подставьте значения.
|
||||
|
||||
DEPLOY_HOST=192.168.1.88
|
||||
DEPLOY_USER=root
|
||||
DEPLOY_PATH=/opt/craftshop
|
||||
|
||||
# Куда выкладывается `client/dist/` (совпадайте с root в nginx для SPA + try_files).
|
||||
DEPLOY_FRONTEND_DIST=/opt/craftshop/www
|
||||
|
||||
# Опционально: ssh -i
|
||||
# DEPLOY_SSH_IDENTITY=C:/Users/Me/.ssh/id_ed25519
|
||||
|
||||
# Если API под пользователем deploy — оставьте DEPLOY_SKIP_CHOWN=0 (дефолт chown deploy).
|
||||
# Если на сервере CRAFTSHOP_USER=root (systemd под root): DEPLOY_SKIP_CHOWN=1 и DEPLOY_SERVER_OWNER=root
|
||||
DEPLOY_SKIP_CHOWN=0
|
||||
# DEPLOY_SERVER_OWNER=deploy
|
||||
|
||||
# После обновления кода API (под root без sudo)
|
||||
DEPLOY_RESTART_CMD='systemctl restart craftshop-api'
|
||||
@@ -1,14 +0,0 @@
|
||||
function Import-DeployDotEnv {
|
||||
param([string]$Path)
|
||||
if (-not (Test-Path $Path)) { return }
|
||||
Get-Content $Path | ForEach-Object {
|
||||
if ($_ -match '^\s*#' -or $_ -match '^\s*$') { return }
|
||||
if ($_ -match '^([A-Za-z_][A-Za-z0-9_]*)=(.*)$') {
|
||||
$name = $Matches[1]; $raw = $Matches[2].Trim()
|
||||
$v = $raw
|
||||
if ($raw.StartsWith("'") -and $raw.EndsWith("'")) { $v = $raw.Trim("'") }
|
||||
elseif ($raw.StartsWith('"') -and $raw.EndsWith('"')) { $v = $raw.Trim('"') }
|
||||
[Environment]::SetEnvironmentVariable($name, $v, "Process")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
# Appends local id_ed25519.pub to root authorized_keys on the server (uses scripts/deploy.env).
|
||||
# Run from repo root: .\scripts\register-ssh-key-for-root.ps1
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$scriptsDir = $PSScriptRoot
|
||||
$deployEnv = Join-Path $scriptsDir "deploy.env"
|
||||
|
||||
if (-not (Test-Path $deployEnv)) {
|
||||
Write-Error "Missing scripts/deploy.env. Copy from deploy.env.example and set DEPLOY_HOST."
|
||||
}
|
||||
|
||||
. "$PSScriptRoot\read-deploy-env.ps1"
|
||||
Import-DeployDotEnv $deployEnv
|
||||
|
||||
$deployHost = [Environment]::GetEnvironmentVariable("DEPLOY_HOST", "Process")
|
||||
$user = [Environment]::GetEnvironmentVariable("DEPLOY_USER", "Process")
|
||||
if ([string]::IsNullOrWhiteSpace($user)) { $user = "root" }
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($deployHost)) {
|
||||
Write-Error "DEPLOY_HOST is not set in scripts/deploy.env."
|
||||
}
|
||||
|
||||
$keyPub = Join-Path $env:USERPROFILE ".ssh\id_ed25519.pub"
|
||||
if (-not (Test-Path $keyPub)) {
|
||||
Write-Error "Public key not found: $keyPub"
|
||||
}
|
||||
|
||||
$remote = "${user}@${deployHost}"
|
||||
Write-Host "Adding key to $remote (from $keyPub). Enter password if SSH asks."
|
||||
$bashCmd = "umask 077; mkdir -p .ssh && touch .ssh/authorized_keys && chmod 700 .ssh && cat >> .ssh/authorized_keys && chmod 600 .ssh/authorized_keys"
|
||||
Get-Content -Raw $keyPub | ssh -o StrictHostKeyChecking=accept-new $remote $bashCmd
|
||||
|
||||
Write-Host "Done. Verify: ssh $remote echo ssh-ok"
|
||||
@@ -1,203 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Этап A: первичная настройка свежего Debian/Ubuntu (LXC/VM) под Craftshop.
|
||||
# Запускать НА СЕРВЕРЕ от root один раз:
|
||||
# curl -fsSL … | bash или scp + bash server-bootstrap.sh
|
||||
#
|
||||
# По умолчанию: ставит Node 22.x (NodeSource), nginx, пользователя deploy, каталоги
|
||||
# /opt/craftshop/server и /opt/craftshop/www, systemd craftshop-api, сайт nginx.
|
||||
#
|
||||
# После выполнения:
|
||||
# 1) Положите .env в /opt/craftshop/server/ (DATABASE_URL, JWT_SECRET, ADMIN_EMAIL, CORS_ORIGIN, PORT=3333)
|
||||
# 2) DEPLOY_RESTART_CMD при SSH от root: «systemctl restart craftshop-api» (без sudo)
|
||||
# 3) Запустите deploy-ssh.sh с вашей машины (по умолчанию пользователь SSH — root, см. scripts/deploy.env.example)
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(id -u)" != "0" ]]; then
|
||||
echo "Запускайте от root: sudo $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CRAFTSHOP_ROOT="${CRAFTSHOP_ROOT:-/opt/craftshop}"
|
||||
CRAFTSHOP_USER="${CRAFTSHOP_USER:-deploy}"
|
||||
CRAFTSHOP_SERVER_NAME="${CRAFTSHOP_SERVER_NAME:-_}"
|
||||
CRAFTSHOP_NODE_MAJOR="${CRAFTSHOP_NODE_MAJOR:-22}"
|
||||
SKIP_NODE_INSTALL="${SKIP_NODE_INSTALL:-0}"
|
||||
SKIP_NGINX="${SKIP_NGINX:-0}"
|
||||
SKIP_SYSTEMD="${SKIP_SYSTEMD:-0}"
|
||||
|
||||
if [[ -f /etc/craftshop-bootstrap.env ]]; then
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source /etc/craftshop-bootstrap.env
|
||||
set +a
|
||||
fi
|
||||
|
||||
detect_os() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source /etc/os-release
|
||||
echo "${ID:-unknown}"
|
||||
return 0
|
||||
fi
|
||||
echo unknown
|
||||
}
|
||||
|
||||
OS="$(detect_os)"
|
||||
if [[ "$OS" != "debian" && "$OS" != "ubuntu" ]]; then
|
||||
echo "Ожидался Debian или Ubuntu (получено: $OS). Прервите выполнение, если образ другой." >&2
|
||||
fi
|
||||
|
||||
echo ">>> apt-get update"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -y
|
||||
|
||||
echo ">>> Базовые пакеты"
|
||||
apt-get install -y ca-certificates curl gnupg
|
||||
|
||||
if [[ "$SKIP_NODE_INSTALL" != "1" ]]; then
|
||||
if command -v node >/dev/null 2>&1; then
|
||||
ver="$(node -p "parseInt(process.versions.node,10)" 2>/dev/null || echo 0)"
|
||||
if [[ "${ver:-0}" -ge 20 ]]; then
|
||||
echo ">>> Node уже есть (версия $(node --version)), пропуск NodeSource"
|
||||
else
|
||||
echo ">>> Node слишком старый, ставим ${CRAFTSHOP_NODE_MAJOR}.x через NodeSource"
|
||||
curl -fsSL "https://deb.nodesource.com/setup_${CRAFTSHOP_NODE_MAJOR}.x" | bash -
|
||||
apt-get install -y nodejs
|
||||
fi
|
||||
else
|
||||
echo ">>> Установка Node.js ${CRAFTSHOP_NODE_MAJOR}.x через NodeSource"
|
||||
curl -fsSL "https://deb.nodesource.com/setup_${CRAFTSHOP_NODE_MAJOR}.x" | bash -
|
||||
apt-get install -y nodejs
|
||||
fi
|
||||
else
|
||||
echo ">>> SKIP_NODE_INSTALL=1 — убедитесь, что node >= 20.6 есть в системе"
|
||||
command -v node >/dev/null 2>&1 || {
|
||||
echo "node не найден" >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
echo ">>> Пользователь $CRAFTSHOP_USER"
|
||||
if ! id -u "$CRAFTSHOP_USER" >/dev/null 2>&1; then
|
||||
useradd --create-home --shell /bin/bash "$CRAFTSHOP_USER"
|
||||
fi
|
||||
|
||||
echo ">>> Каталоги $CRAFTSHOP_ROOT/{server,www,uploads}"
|
||||
mkdir -p "$CRAFTSHOP_ROOT/server/uploads" "$CRAFTSHOP_ROOT/www"
|
||||
chown -R "$CRAFTSHOP_USER:$CRAFTSHOP_USER" "$CRAFTSHOP_ROOT"
|
||||
chmod 755 "$CRAFTSHOP_ROOT" "$CRAFTSHOP_ROOT/server" "$CRAFTSHOP_ROOT/www"
|
||||
|
||||
if [[ "$SKIP_SYSTEMD" != "1" ]]; then
|
||||
echo ">>> systemd craftshop-api"
|
||||
cat >/etc/systemd/system/craftshop-api.service <<EOF
|
||||
[Unit]
|
||||
Description=Craftshop API (Fastify)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$CRAFTSHOP_USER
|
||||
Group=$CRAFTSHOP_USER
|
||||
WorkingDirectory=$CRAFTSHOP_ROOT/server
|
||||
EnvironmentFile=-$CRAFTSHOP_ROOT/server/.env
|
||||
ExecStart=/usr/bin/node src/index.js
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
LimitNOFILE=65535
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable craftshop-api.service
|
||||
echo "(сервис не запущен, пока не появится код и \$CRAFTSHOP_ROOT/server/.env)"
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_NGINX" != "1" ]]; then
|
||||
apt-get install -y nginx
|
||||
|
||||
NGINX_SITE="/etc/nginx/sites-available/craftshop"
|
||||
|
||||
cat >"$NGINX_SITE" <<NGX
|
||||
# Craftshop: статика SPA + proxy /api и /uploads на Node (:3333)
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
server_name $CRAFTSHOP_SERVER_NAME;
|
||||
|
||||
root $CRAFTSHOP_ROOT/www;
|
||||
index index.html;
|
||||
|
||||
location /api/ {
|
||||
client_max_body_size 250m;
|
||||
proxy_pass http://127.0.0.1:3333;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
}
|
||||
|
||||
location /uploads/ {
|
||||
proxy_pass http://127.0.0.1:3333;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ /index.html;
|
||||
}
|
||||
}
|
||||
NGX
|
||||
|
||||
if [[ -f /etc/nginx/sites-enabled/default ]]; then
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
fi
|
||||
ln -sf "$NGINX_SITE" /etc/nginx/sites-enabled/craftshop
|
||||
|
||||
nginx -t
|
||||
systemctl reload nginx || systemctl restart nginx
|
||||
|
||||
echo ">>> nginx включён на порту 80 (server_name=$CRAFTSHOP_SERVER_NAME)"
|
||||
fi
|
||||
|
||||
cat >"$CRAFTSHOP_ROOT/server/README-PLACE-ENV.txt" <<TXT
|
||||
Создайте файл .env в этом каталоге (права только для $CRAFTSHOP_USER).
|
||||
Минимум:
|
||||
DATABASE_URL="file:./prod.db"
|
||||
PORT=3333
|
||||
JWT_SECRET=<длинная случайная строка>
|
||||
ADMIN_EMAIL=<ваш email админа>
|
||||
CORS_ORIGIN=http://<IP_или_домен_фронта>
|
||||
IS_DEFAULT_CODE_ENABLED=false
|
||||
|
||||
Базу и код вы зальёте скриптом deploy-ssh.sh с машины разработчика:
|
||||
первый запуск после деплоя: systemctl start craftshop-api (от root; иначе sudo)
|
||||
TXT
|
||||
chown "$CRAFTSHOP_USER:$CRAFTSHOP_USER" "$CRAFTSHOP_ROOT/server/README-PLACE-ENV.txt"
|
||||
|
||||
if [[ -n "${CRAFTSHOP_AUTHORIZED_KEY:-}" ]]; then
|
||||
uhome="$(getent passwd "$CRAFTSHOP_USER" | cut -d: -f6)"
|
||||
install -d -m 700 -o "$CRAFTSHOP_USER" -g "$CRAFTSHOP_USER" "$uhome/.ssh"
|
||||
afile="$uhome/.ssh/authorized_keys"
|
||||
if [[ ! -f "$afile" ]]; then
|
||||
install -m 600 -o "$CRAFTSHOP_USER" -g "$CRAFTSHOP_USER" /dev/null "$afile"
|
||||
fi
|
||||
if ! grep -qFx "$CRAFTSHOP_AUTHORIZED_KEY" "$afile" 2>/dev/null; then
|
||||
printf '%s\n' "$CRAFTSHOP_AUTHORIZED_KEY" >>"$afile"
|
||||
fi
|
||||
echo ">>> Добавлен SSH-ключ в $afile"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Готово Этап A."
|
||||
echo "- Каталог: $CRAFTSHOP_ROOT"
|
||||
echo "- Пользователь: $CRAFTSHOP_USER"
|
||||
echo "- Положите $CRAFTSHOP_ROOT/server/.env и выполните деплой кода (--backend-only), затем: systemctl start craftshop-api"
|
||||
Reference in New Issue
Block a user