diff --git a/README.md b/README.md index 0d5624a..0c47b96 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ cd /opt/amnezia-admin && chmod +x scripts/install.sh && sudo SKIP_DOWNLOAD=1 bas | `COMMUNITY_DISABLE_DOCKER_CLI_HELPER` | _(не задано)_ | Если `1`, установка из UI снова только «bash внутри панели» (часто конфликт **:8080** с PRO). По умолчанию используется одноразовый контейнер **docker:cli**, который **снимает FREE** и зависший PRO перед `install.sh`. | | `COMMUNITY_SKIP_REMOVE_FREE_BEFORE_PRIVATE_PRO` | `0` | `1` — не выполнять `docker rm` FREE/лендинга перед install (если знаете, что делаете). | | `COMMUNITY_PRO_INSTALL_HELPER_IMAGE` | `docker:26-cli` | Образ с бинарём `docker` для фонового контейнера (нужен доступ к демону по сокету). | +| `COMMUNITY_HELPER_SKIP_PREPARE_TOOLS` | _(не задано)_ | `1` — не ставить `curl` перед приватным `install.sh` в helper (обычно не нужно; образ Alpine часто без `curl`, без него ваш скрипт падает). | | `FREE_PANEL_CONTAINER_FOR_PRO_INSTALL` и др. | см. `server.js` | Имена контейнеров для `docker rm` перед install (по умолчанию `amnezia-admin`, `amnezia-web-landing`, `amnezia-admin-pro`). | Чтобы включить форму установки из панели, задайте в контейнере **`AMNEZIA_EDITION=community`** и **`ALLOW_COMMUNITY_GITHUB_ACTIVATION=1`** (`install.sh`: добавьте `-e ALLOW_COMMUNITY_GITHUB_ACTIVATION=1` или пересоздайте контейнер после правки переменных). URL приватного `install.sh` при необходимости переопределите через **`COMMUNITY_PRIVATE_INSTALL_SCRIPT_URL`**. @@ -98,7 +99,11 @@ curl -fsSL https://raw.githubusercontent.com/andrey271192/amnezia_web/main/scrip ### `Bind for 0.0.0.0:8080 failed: port is already allocated` у `amnezia-admin-pro` -На **8080** уже слушает **FREE**‑панель (**`amnezia-admin`**). Пока она работает, второй контейнер панели (PRO) на тот же порт не поднимется. **Кнопка «Установить PRO» из UI по умолчанию** использует одноразовый контейнер **`docker:cli`** (пауза → **`docker rm`** FREE / лендинг / возможный **`amnezia-admin-pro` в Created** → затем ваш **`install.sh`**). Иначе вручную: **`docker rm -f amnezia-admin`**, затем установщик PRO. Отключить авто-снос: **`COMMUNITY_DISABLE_DOCKER_CLI_HELPER=1`**. +На **8080** уже слушает **FREE**‑панель (**`amnezia-admin`**). Пока она работает, второй контейнер панели (PRO) на тот же порт не поднимется. **Кнопка «Установить PRO» из UI по умолчанию** использует одноразовый контейнер **`docker:cli`** (пауза → **`docker rm`** FREE / лендинг / **`amnezia-admin-pro` и любые имена вида `_…_…-amnezia-admin-pro`** из docker compose → затем ваш **`install.sh`**). Иначе вручную: **`docker rm -f amnezia-admin`**, затем установщик PRO. Отключить авто-снос: **`COMMUNITY_DISABLE_DOCKER_CLI_HELPER=1`**. + +### В `community-install-last.log`: **`curl: command not found`** и затем **`tar: invalid magic`** + +Образ **`docker:26-cli`** на Alpine часто **без `curl`**; ваш приватный `install.sh`, скачивающий архив через `curl … | tar`, падает, а **`tar`** читает пустые данные («invalid magic»). Актуальная панель **перед запуском** `install.sh` в helper ставит **`curl`** через **`apk`** / **`apt-get`**. Если сетевая политика блокирует `apk add`/`apt-get`, укажите другой образ в **`COMMUNITY_PRO_INSTALL_HELPER_IMAGE`** (со встроенным `curl`), либо замените `curl` в своём **`install.sh`** на **`wget`**. Отключить авто-доставку `curl`: **`COMMUNITY_HELPER_SKIP_PREPARE_TOOLS=1`** (обычно не нужно). ### Лендинг: порт 80 занят diff --git a/package.json b/package.json index 178a7e8..f467990 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "amnezia-admin", - "version": "1.2.1", + "version": "1.2.2", "private": true, "description": "amnezia_web — базовая панель AmneziaWG (FREE: просмотр и удаление клиентов; полная версия — PRO).", "license": "MIT", diff --git a/scripts/install.sh b/scripts/install.sh index 22d25ba..4c05bfe 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -127,7 +127,7 @@ for __reuse_var in UI_HIDE_SECTIONS UI_HIDE_USERS UI_HIDE_WARP UI_HIDE_CASCADE W COMMUNITY_UPGRADE_URL COMMUNITY_UPGRADE_PITCH AMNEZIA_EDITION \ COMMUNITY_DISABLE_DOCKER_CLI_HELPER COMMUNITY_SKIP_REMOVE_FREE_BEFORE_PRIVATE_PRO COMMUNITY_PRO_INSTALL_HELPER_IMAGE \ FREE_PANEL_CONTAINER_FOR_PRO_INSTALL FREE_LANDING_CONTAINER_FOR_PRO_INSTALL STALE_PRO_PANEL_CONTAINER_FOR_PRO_INSTALL \ - COMMUNITY_INSTALL_LOG_TAIL_BYTES COMMUNITY_INSTALL_LOG_API_CHUNK_MAX \ + COMMUNITY_INSTALL_LOG_TAIL_BYTES COMMUNITY_INSTALL_LOG_API_CHUNK_MAX COMMUNITY_HELPER_SKIP_PREPARE_TOOLS \ EXPORT_CONFIG_SECRET CLIENT_CONFIG_ENDPOINT CLIENT_EXPORT_DNS1 CLIENT_EXPORT_DNS2; do if [[ -z "${!__reuse_var:-}" ]] && [[ -n "${PREV_CONTAINER_ENV}" ]]; then PREV_VAL="" @@ -203,7 +203,7 @@ elif [[ -f "${INSTALL_DIR}/.amnezia-panel-edition" ]]; then echo "→ AMNEZIA_EDITION из ${INSTALL_DIR}/.amnezia-panel-edition: ${__PE}" fi fi -for __ce_var in COMMUNITY_UPGRADE_URL COMMUNITY_UPGRADE_PITCH ALLOW_COMMUNITY_GITHUB_ACTIVATION COMMUNITY_PRIVATE_INSTALL_SCRIPT_URL COMMUNITY_INSTALL_FETCH_MS PRIVATE_INSTALL_SCRIPT_MAX_BYTES COMMUNITY_DISABLE_DOCKER_CLI_HELPER COMMUNITY_SKIP_REMOVE_FREE_BEFORE_PRIVATE_PRO COMMUNITY_PRO_INSTALL_HELPER_IMAGE FREE_PANEL_CONTAINER_FOR_PRO_INSTALL FREE_LANDING_CONTAINER_FOR_PRO_INSTALL STALE_PRO_PANEL_CONTAINER_FOR_PRO_INSTALL COMMUNITY_INSTALL_LOG_TAIL_BYTES COMMUNITY_INSTALL_LOG_API_CHUNK_MAX; do +for __ce_var in COMMUNITY_UPGRADE_URL COMMUNITY_UPGRADE_PITCH ALLOW_COMMUNITY_GITHUB_ACTIVATION COMMUNITY_PRIVATE_INSTALL_SCRIPT_URL COMMUNITY_INSTALL_FETCH_MS PRIVATE_INSTALL_SCRIPT_MAX_BYTES COMMUNITY_DISABLE_DOCKER_CLI_HELPER COMMUNITY_SKIP_REMOVE_FREE_BEFORE_PRIVATE_PRO COMMUNITY_PRO_INSTALL_HELPER_IMAGE FREE_PANEL_CONTAINER_FOR_PRO_INSTALL FREE_LANDING_CONTAINER_FOR_PRO_INSTALL STALE_PRO_PANEL_CONTAINER_FOR_PRO_INSTALL COMMUNITY_INSTALL_LOG_TAIL_BYTES COMMUNITY_INSTALL_LOG_API_CHUNK_MAX COMMUNITY_HELPER_SKIP_PREPARE_TOOLS; do if [[ -n "${!__ce_var:-}" ]]; then RUN_ENV+=( -e "${__ce_var}=${!__ce_var}" ) fi diff --git a/server.js b/server.js index e34025c..cb4bb78 100644 --- a/server.js +++ b/server.js @@ -378,6 +378,26 @@ function shellSafeDockerContainerName(raw, fallback) { return fallback; } +/** + * Одноразовый helper (`docker:*-cli`) часто Alpine без curl, а частный PRO install.sh дергает `curl`/GitHub — + * см. сообщество: `curl: command not found`, затем tar «invalid magic». + * Установить curl/ca-cert перед `bash ./install.sh`. Отключить: COMMUNITY_HELPER_SKIP_PREPARE_TOOLS=1. + */ +function dockerCliHelperEnsureFetchToolsScript() { + if (envTruthy(process.env.COMMUNITY_HELPER_SKIP_PREPARE_TOOLS)) return ""; + return ` +# Инструменты для приватного install.sh (образ Docker CLI может быть без curl) +if ! command -v curl >/dev/null 2>&1; then + if command -v apk >/dev/null 2>&1; then + apk add --no-cache curl ca-certificates || echo "⚠ helper: apk add curl failed — приватный install.sh может упасть" >> /mnt/data/community-install-last.log + elif command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq >/dev/null && apt-get install -y -qq curl ca-certificates || echo "⚠ helper: apt install curl failed — приватный install.sh может упасть" >> /mnt/data/community-install-last.log + fi +fi +`.trim(); +} + function privateInstallScriptUrlLogged() { try { const u = new URL(COMMUNITY_PRIVATE_INSTALL_SCRIPT_URL); @@ -1546,11 +1566,16 @@ app.post("/api/community/run-private-install", requireAuth, async (req, res) => const dataAbs = path.resolve(DATA_DIR); const prelude = COMMUNITY_SKIP_REMOVE_FREE_BEFORE_PRIVATE_PRO ? "sleep 2" - : `sleep 3; docker rm -f ${freePanelName} ${freeLandingName} 2>/dev/null || true; docker rm -f ${staleProName} 2>/dev/null || true`; + : [ + `sleep 3; docker rm -f ${freePanelName} ${freeLandingName} 2>/dev/null || true`, + `docker rm -f ${staleProName} 2>/dev/null || true`, + 'for __amz_hp in $(docker ps -aq --filter name=amnezia-admin-pro 2>/dev/null || true); do docker rm -f "$__amz_hp" 2>/dev/null || true; done', + ].join(" "); + const fetchTools = dockerCliHelperEnsureFetchToolsScript(); const sh = ` set -eu ${prelude} -cd /mnt/stage && exec bash ./install.sh >> /mnt/data/community-install-last.log 2>&1 +${fetchTools ? `${fetchTools}\n` : ""}cd /mnt/stage && exec bash ./install.sh >> /mnt/data/community-install-last.log 2>&1 `.trim(); const dr = spawn(