v1.2.6: вопрос о протоколах при установке (+--yes, --harden) и правка разбора ответов

This commit is contained in:
2026-10-12 20:22:17 +03:00
parent 4ed9c5ceb5
commit cc17b11bd1
3 changed files with 122 additions and 12 deletions
+5
View File
@@ -5,6 +5,11 @@
## v1.2.6: вопросы при установке
* Обёртка спрашивает, **какие протоколы ставить** (нумерованный список, `1,3,11` или «все»,
Enter — набор автора): невыбранные протоколы не создаются вообще — ни подключения в панели,
ни записей в nginx, ни ссылок в подписке. Список и умолчание взяты из самого установщика
(`ALL_PROTOS`/`DEFAULT_PROTOS`), передаётся его же флагом `--protocols`, так что поведение
не расходится с авторским. Свой `--protocols` можно задать флагом — тогда вопроса не будет.
* Обёртка `scripts/3x-ui-local.sh` теперь спрашивает, а не решает за вас: закрывать ли ответ на ping,
включать ли автообновления безопасности, добавлять ли второй порт SSH, менять ли пароль root.
Маскировку и домен, как и раньше, спрашивает установщик автора.
+17 -5
View File
@@ -8,16 +8,25 @@
1. Если нужен свой домен для маскировки — заранее направьте его A-запись на IP сервера и освободите
порт 80 (иначе Let's Encrypt не выпустит сертификат). Без домена этот шаг пропускается.
2. Одна команда на сервере (от root):
2. Одна команда на сервере (от root) — **дальше скрипт спросит сам**: какие протоколы ставить
(нумерованный список: `1,3,11` или «все», Enter — набор автора), какую маскировку и домен,
закрывать ли ответ на ping, включать ли автообновления, добавлять ли второй порт SSH,
менять ли пароль root:
```bash
bash <(curl -fsSL https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main/scripts/3x-ui-local.sh) --domain vpn.example.com
bash <(curl -fsSL https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main/scripts/3x-ui-local.sh)
```
Те же ответы можно задать флагами — тогда вопросов не будет:
```bash
bash <(curl -fsSL …/scripts/3x-ui-local.sh) --protocols reality,hy2,awg,mtproto --domain vpn.example.com
```
3. Скрипт делает всё сам: проверяет сервер → скачивает наш релиз и **проверяет подпись `SHA256SUMS`
и SHA256 установщика** → запускает установщик автора (панель 3X-UI, протоколы на 443,
сайт-заглушка, маскировка, сертификат, подписка, ufw) → закрывает ответ на ping, включает
обновления безопасности, делает `kit fix` → в конце показывает `kit check` и сводку
и SHA256 установщика** → запускает установщик автора (панель 3X-UI, **только выбранные протоколы**,
сайт-заглушка, маскировка, сертификат, подписка, ufw) → наши вопросы и правки (ping,
автообновления, второй порт SSH, пароль root) → `kit fix` → в конце показывает `kit check` и сводку
`kit local hardening`.
4. Забрать ссылки и подписку: `kit user link admin` (или адрес подписки из вывода установки).
@@ -32,6 +41,9 @@ bash <(curl -fsSL …/scripts/3x-ui-local.sh) --dry-run --domain vpn.example.com
| Флаг | Что делает |
|---|---|
| `--protocols список` | какие протоколы ставить: `all`, `minimal` или через запятую — `reality,reality2,hy2,xhttp,ws,trojan,vmess,ss,tuic,wg,awg,awg3,mtproto`. Невыбранные не создаются вообще. Без флага — вопрос |
| `--yes` | не задавать вопросы (ping закрывается, автообновления включаются, порт SSH и пароль не трогаются) |
| `--harden` | закрыть ответ на ping и включить автообновления без вопросов |
| `--domain домен` | свой домен для маскировки: сайт и REALITY маскируются под него (A-запись на сервер, свободный 80) |
| `--sni сайт.com` | маскировка под чужой сайт вместо домена |
| `--panel-on domain\|ip` | где открывать панель и подписку |
+100 -7
View File
@@ -7,10 +7,12 @@
# 3) запускает установщик автора (scripts/3x-ui.sh) — панель 3X-UI, протоколы, сайт-заглушка,
# маскировка, сертификат, подписка, ufw. Флаги установщика можно передавать как есть,
# а можно ничего не передавать — тогда он задаст вопросы сам (в том числе про домен);
# 4) спрашивает и делает то, чего у автора нет: закрыть ответ на ping, включить обновления
# 4) спрашивает, какие протоколы ставить: невыбранные не создаются вообще — ни подключения в панели,
# ни записей в nginx, ни ссылок в подписке (за это отвечает флаг автора --protocols);
# 5) спрашивает и делает то, чего у автора нет: закрыть ответ на ping, включить обновления
# безопасности, добавить второй порт SSH, сменить пароль root (поведение из StressOzz/vps-setup,
# но безопаснее);
# 5) в конце: kit fix (время и безопасные починки), kit check, kit local hardening.
# 6) в конце: kit fix (время и безопасные починки), kit check, kit local hardening.
#
# Запуск:
# # одна команда, дальше — вопросы:
@@ -56,8 +58,9 @@ usage() {
bash <(curl -fsSL <наш Gitea>/raw/branch/main/scripts/3x-ui-local.sh) [флаги…]
Без флагов скрипт спрашивает: маскировку и домен (это вопросы установщика автора),
затем про ответ на ping, автообновления, второй порт SSH и пароль root (наши вопросы).
Без флагов скрипт спрашивает: какие протоколы ставить (невыбранные не создаются вообще),
маскировку и домен — это вопросы установщика автора; затем про ответ на ping, автообновления,
второй порт SSH и пароль root — это наши вопросы.
Флаги, которые скрипт передаёт установщику автора как есть:
--domain vpn.example.com свой домен для маскировки (A-запись на этот сервер, свободный 80)
@@ -99,8 +102,15 @@ while (($#)); do
done
[[ -z $ssh_port || $ssh_port =~ ^[0-9]{1,5}$ ]] || die "--ssh-port: нужен номер порта, например 2222"
# Если --protocols задан флагом — не спрашиваем и не дублируем его.
proto_flag=""
for ((_i = 0; _i < ${#INSTALLER_ARGS[@]}; _i++)); do
[[ ${INSTALLER_ARGS[_i]} == --protocols ]] && proto_flag=${INSTALLER_ARGS[_i + 1]:-all}
done
pre() { printf ' %s\n' "$*"; }
interactive() { [[ $assume_yes == no && -r /dev/tty ]] && { : </dev/tty; } 2>/dev/null; }
ASK_SRC=${KIT_ASK_SRC:-/dev/tty} # откуда читать ответы (в тестах подменяется файлом)
interactive() { [[ $assume_yes == no && -r $ASK_SRC ]]; }
if [[ $dry == yes ]]; then
say "план установки (--dry-run: ничего не делаю)"
@@ -112,6 +122,9 @@ if [[ $dry == yes ]]; then
else pre "защита: без терминала — закрыть ping и включить автообновления"; fi
elif [[ $harden == yes ]]; then pre "защита: закрыть ping и включить автообновления (--harden)"
else pre "защита: пропускаю (--no-harden)"; fi
if [[ -n $proto_flag ]]; then pre "протоколы: ${proto_flag} (задано флагом)"
elif interactive; then pre "протоколы: спрошу (Enter — всё, кроме WireGuard и REALITY-2)"
else pre "протоколы: всё, кроме WireGuard и REALITY-2"; fi
if [[ -n $ssh_port ]]; then pre "порт SSH: добавляю $ssh_port (прежний остаётся рабочим)"
elif interactive; then pre "порт SSH: спрошу (Enter — не менять)"; fi
if interactive; then pre "пароль root: спрошу (по умолчанию — не менять)"; fi
@@ -162,8 +175,88 @@ printf ' %s\n' "${PRETTY_NAME:-Linux}, ядро $(uname -r), памяти $(awk
df -P / | awk 'NR==2 {gsub("%","",$5); if ($5 >= 95) exit 1}' || warn "диск занят почти полностью — установка может не пройти"
for p in 443 80; do ss -H -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]$p\$" && warn "порт $p уже кем-то занят"; done
# ------------------------------------------------------------------ какие протоколы ставить
# Список, порядок и набор по умолчанию — как у установщика автора (scripts/3x-ui.sh:
# ALL_PROTOS / DEFAULT_PROTOS). Невыбранные протоколы не создаются вообще: под них не будет
# ни подключения в панели, ни записей в nginx, ни ссылок в подписке.
ALL_PROTOS=(reality reality2 hy2 xhttp ws trojan vmess ss tuic wg awg awg3 mtproto)
PROTO_HINT=(
"REALITY основной: VLESS + Reality, порт 443"
"REALITY-2 второй REALITY на случайном высоком порту"
"Hysteria2 быстрее на плохой сети (UDP 443)"
"XHTTP VLESS + Reality под другим именем маскировки"
"VLESS-WS VLESS через WebSocket"
"Trojan-gRPC Trojan через gRPC"
"VMess-WS VMess через WebSocket"
"Shadowsocks Shadowsocks 2022"
"TUIC быстрый UDP-протокол"
"WireGuard обычный WireGuard: легко распознаётся, обычно не ставят"
"AmneziaWG AmneziaWG: Mihomo, роутеры Keenetic"
"AmneziaWG-3.1 AmneziaWG с защитой заголовков: AmneziaVPN"
"MTProto прокси для Telegram"
)
DEFAULT_PROTOS=(reality hy2 xhttp ws trojan vmess ss tuic awg awg3 mtproto)
proto_menu() {
local i n mark
say "какие протоколы поставить?"
for i in "${!ALL_PROTOS[@]}"; do
n=$((i + 1)) mark=" "
[[ " ${DEFAULT_PROTOS[*]} " == *" ${ALL_PROTOS[i]} "* ]] && mark="*"
printf ' %s %2d. %s\n' "$mark" "$n" "${PROTO_HINT[i]}"
done
printf ' %s\n' "${D}[* — набор по умолчанию (всё, кроме WireGuard и REALITY-2). Невыбранные протоколы не создаются вообще.]${N}"
}
proto_parse() { # ответ → выбранные имена через запятую; код 1, если не разобрал
local ans=${1,,} tok i all=" ${ALL_PROTOS[*]} " picked=""
ans=${ans//[[:space:]]/,} # «1 3 11» и «1,3,11» — одно и то же
[[ -n $ans ]] || { printf '%s' "$(IFS=,; echo "${DEFAULT_PROTOS[*]}")"; return 0; }
case $ans in
all | все | всё) printf '%s' "$(IFS=,; echo "${DEFAULT_PROTOS[*]}")"; return 0 ;;
minimal | минимум) printf '%s' "reality"; return 0 ;;
esac
local IFS=','
for tok in $ans; do
[[ -n $tok ]] || continue # двойные запятые и пробелы — не ошибка
if [[ $tok =~ ^[0-9]{1,2}$ ]]; then
i=$((10#$tok - 1))
((i >= 0 && i < ${#ALL_PROTOS[@]})) || return 1
tok=${ALL_PROTOS[i]}
fi
[[ $all == *" $tok "* ]] || return 1 # только имена из списка автора
[[ ,$picked, == *",$tok,"* ]] || picked+="${picked:+,}$tok"
done
[[ -n $picked ]] || return 1
printf '%s' "$picked"
}
ask_protocols() { # печатает итоговый список через запятую
local i ans picked
interactive || { printf '%s' "$(IFS=,; echo "${DEFAULT_PROTOS[*]}")"; return 0; }
proto_menu
for i in 1 2 3; do
printf '\n%sНомера через запятую (например 1,3,11) или «все»; Enter — набор по умолчанию: %s' "$B" "$N"
ans=""
read -r -t 300 ans <"$ASK_SRC" 2>/dev/null || true
if picked=$(proto_parse "$ans"); then printf '%s' "$picked"; return 0; fi
warn "не понял «$ans» — нужны номера из списка через запятую или «все»"
done
warn "оставляю набор по умолчанию"
printf '%s' "$(IFS=,; echo "${DEFAULT_PROTOS[*]}")"
}
# ------------------------------------------------------------------ установка
if [[ -z $proto_flag ]]; then
protos=$(ask_protocols)
INSTALLER_ARGS+=(--protocols "$protos")
else
protos=$proto_flag
fi
say "протоколы: $protos — под остальные не создаётся ничего"
say "запускаю установщик автора (панель 3X-UI, протоколы, сайт-заглушка, подписка)"
if ((${#INSTALLER_ARGS[@]})); then printf ' флаги: %s\n' "${INSTALLER_ARGS[*]}"; else printf ' флагов нет: установщик задаст вопросы (маскировка, домен)\n'; fi
# stdin: если есть терминал — отдаём его установщику (там есть вопросы), иначе /dev/null,
@@ -181,7 +274,7 @@ ask_yes() { # "вопрос" y|n — по умолчанию
local q=$1 def=$2 ans=""
interactive || { [[ $def == y ]]; return; }
printf '\n%s [%s]: ' "$q" "$([[ $def == y ]] && echo 'Y/n' || echo 'y/N'])"
read -r -t 300 ans </dev/tty 2>/dev/null || true
read -r -t 300 ans <"$ASK_SRC" 2>/dev/null || true
ans=${ans,,}; ans=${ans//[[:space:]]/}
[[ -z $ans && $def == y ]] && return 0
[[ $ans =~ ^(y|yes|д|да)$ ]]
@@ -191,7 +284,7 @@ ask_value() { # "вопрос" → ответ (пусто, если термин
interactive || return 0
printf '\n%s: ' "$1"
local v=""
read -r -t 300 v </dev/tty 2>/dev/null || true
read -r -t 300 v <"$ASK_SRC" 2>/dev/null || true
printf '%s' "${v//[[:space:]]/}"
}