1.2: kit user link --amnezia и --telegram; kit fix: ставит systemd-timesyncd на Debian 13 без NTP-клиента; kit check проверяет содержимое подписки

This commit is contained in:
maxdmitrov
2026-10-03 23:23:59 +03:00
parent 0f52237286
commit ca74a1dee3
2 changed files with 83 additions and 14 deletions
+3 -1
View File
@@ -86,7 +86,9 @@ bash <(curl -fsSL https://raw.githubusercontent.com/itsnotkubrick/3X-UI_KIT/main
```bash
kit user add имя [--gb 50] [--days 30] [--devices 3] # добавить пользователя во все протоколы, показать подписку и QR
kit user list # кто сколько израсходовал, до какого числа, когда был в сети
kit user link имя [--all] # показать подписку снова; --all добавляет ссылки vpn:// и tg://
kit user link имя # показать подписку снова
kit user link имя --amnezia # ссылка vpn:// для приложения AmneziaVPN
kit user link имя --telegram # ссылка tg:// для Telegram и QR-код
kit user limit имя [--gb N] [--days N] [--devices N] # изменить лимиты (0 – без ограничений)
kit user off имя # временно выключить пользователя
kit user on имя # включить обратно
+80 -13
View File
@@ -105,8 +105,8 @@ human() { # байты → «1.2 ГБ»
sub_url() { echo "${SUB_BASE}$1"; }
# Отдельные ссылки на протоколы – прямо из подписки 3X-UI внутри сервера (мимо kit-sub, который
# прячет от VPN-приложений vpn:// и tg://). direct_links subId фильтр
direct_links() {
# прячет от VPN-приложений vpn:// и tg://). collect_links subId фильтр – печатает подходящие строки.
collect_links() {
local sid=$1 filter=$2 raw out="" suffix scheme
for suffix in "" -awg; do
raw=""
@@ -119,7 +119,14 @@ direct_links() {
out+=$(grep -E "$filter" <<<"$raw" || true)$'\n'
done
[[ ${SINGLE:-no} == yes ]] && out=$(sed "s/^\(tg:\/\/proxy?\)\(.*\)port=${MTPROTO_INNER:-10445}/\1\2port=443/" <<<"$out")
echo; grep . <<<"$out" || echo "Отдельных ссылок нет."
grep . <<<"$out" || true
}
direct_links() { # subId фильтр
local out
out=$(collect_links "$1" "$2")
echo
if [[ -n $out ]]; then echo "$out"; else echo "Отдельных ссылок нет."; fi
}
# Панель «через SSH-туннель»: подписка слушает только 127.0.0.1, с телефона по ней не зайти.
@@ -141,7 +148,7 @@ show_link() { # имя subId
echo "$url"
echo
command -v qrencode >/dev/null && qrencode -t ANSIUTF8 -m 1 "$url"
echo "${D}AmneziaVPN и Telegram: kit user link $1 --all – отдельные ссылки vpn:// и tg://${N}"
echo "${D}AmneziaVPN: kit user link $1 --amnezia · Telegram: kit user link $1 --telegram${N}"
}
cmd_add() {
@@ -175,13 +182,35 @@ cmd_add() {
}
cmd_link() {
local name=${1:-} all=${2:-} c sid
local name=${1:-} flag=${2:-} c sid out
valid_name "$name"
c=$(client "$name"); [[ -n $c ]] || die "Нет пользователя $name"
sid=$(jq -r '.subId' <<<"$c")
show_link "$name" "$sid"
# В режиме «только на сервере» показ уже содержит все ссылки.
if [[ $all == --all ]] && ! local_only_sub; then direct_links "$sid" '^(vpn|tg)://'; fi
case $flag in
--amnezia)
out=$(collect_links "$sid" '^vpn://')
[[ -n $out ]] || die "Ссылок AmneziaVPN нет: AmneziaWG на этом сервере не установлен."
echo
echo "AmneziaVPN: в приложении «Добавить подключение», вставьте ссылку целиком."
echo "Первая – классический AmneziaWG, вторая (если есть) – версия 3.1."
echo
echo "$out" ;;
--telegram)
out=$(collect_links "$sid" '^tg://')
[[ -n $out ]] || die "Ссылки для Telegram нет: MTProto на этом сервере не установлен."
echo
echo "Telegram: откройте ссылку на телефоне или наведите камеру на QR-код, Telegram предложит добавить прокси."
echo
echo "$out"
echo
command -v qrencode >/dev/null && qrencode -t ANSIUTF8 -m 1 "$(head -1 <<<"$out")"
return 0 ;;
"" | --all)
show_link "$name" "$sid"
# В режиме «только на сервере» показ уже содержит все ссылки.
if [[ $flag == --all ]] && ! local_only_sub; then direct_links "$sid" '^(vpn|tg)://'; fi ;;
*) die "kit user link имя [--all | --amnezia | --telegram]" ;;
esac
}
cmd_list() {
@@ -687,6 +716,14 @@ check_exposure() {
((bad)) || c_ok "файлы с паролями и ключами доступны только root"
}
# Ответ подписки похож на подписку: для Clash есть proxies, для остальных – ссылки (текстом или в base64).
sub_body_ok() { # файл приложение
case $2 in
clash*) grep -q '^proxies:' "$1" ;;
*) grep -q '://' "$1" || base64 -d "$1" 2>/dev/null | grep -q '://' ;;
esac
}
check_subscription() {
local cfg=/etc/kit-sub/config.json port path scheme=http sid ua code size body up sub_cert
[[ -f $cfg ]] || { c_info "подписка не установлена (режим без сертификата: используйте отдельные ссылки из /root/3x-ui.txt)"; return 0; }
@@ -706,12 +743,16 @@ check_subscription() {
: >"$body"
code=$(curl -sgk -m 10 -A "$ua" -o "$body" -w '%{http_code}' "$scheme://127.0.0.1:$port$path$sid" 2>/dev/null || true)
size=$(wc -c <"$body" | tr -d ' ')
if [[ $code == 200 && ${size:-0} -gt 0 ]]; then c_ok "подписка отвечает для $ua ($size байт)"; else c_bad svc:kit-sub "подписка для $ua: HTTP ${code:-нет ответа}"; fi
if [[ $code == 200 && ${size:-0} -gt 0 ]] && sub_body_ok "$body" "$ua"; then c_ok "подписка отвечает для $ua ($size байт)"
elif [[ $code == 200 ]]; then c_bad svc:kit-sub "подписка для $ua: ответ 200, но в нём нет ссылок на подключения"
else c_bad svc:kit-sub "подписка для $ua: HTTP ${code:-нет ответа}"; fi
done
rm -f "$body"
if [[ ${SINGLE:-no} == yes ]]; then
code=$(curl -sk -m 10 -A "Happ/1.0" -o /dev/null -w '%{http_code}' "https://127.0.0.1$path$sid" 2>/dev/null || true)
if [[ $code == 200 ]]; then c_ok "подписка отвечает и через nginx (443)"; else c_bad svc:nginx "подписка через nginx: HTTP ${code:-нет ответа} (ищите причину выше)"; fi
body=$(mktemp)
code=$(curl -sk -m 10 -A "Happ/1.0" -o "$body" -w '%{http_code}' "https://127.0.0.1$path$sid" 2>/dev/null || true)
if [[ $code == 200 ]] && sub_body_ok "$body" "Happ/1.0"; then c_ok "подписка отвечает и через nginx (443)"; else c_bad svc:nginx "подписка через nginx: HTTP ${code:-нет ответа} или ответ без ссылок (ищите причину выше)"; fi
rm -f "$body"
fi
}
@@ -788,10 +829,36 @@ fix_action() { # код
if nginx -t >/dev/null 2>&1; then say "Перечитываю сертификат в nginx"; systemctl reload nginx
else warn "Конфиг nginx не проходит проверку – сертификат не перечитываю."; fi
warn "Если сертификат всё ещё просрочен, запустите продление: ~/.acme.sh/acme.sh --cron" ;;
ntp) say "Включаю синхронизацию времени"; timedatectl set-ntp true ;;
ntp) fix_ntp ;;
esac
}
# На минимальном Debian 13 нет клиента NTP, и «timedatectl set-ntp» отвечает «NTP not supported».
# Ставим systemd-timesyncd, но только если нет другого.
fix_ntp() {
say "Включаю синхронизацию времени"
timedatectl set-ntp true 2>/dev/null && return 0
if other_ntp_installed; then
warn "Время синхронизирует другой NTP-клиент (chrony или ntp) – проверьте, что его служба запущена."
return 0
fi
say "Ставлю systemd-timesyncd"
# timedatectl после установки ещё не видит новую службу, поэтому включаем её напрямую.
if DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=120 install -y -qq systemd-timesyncd >/dev/null 2>&1 \
&& systemctl enable --now systemd-timesyncd >/dev/null 2>&1; then
return 0
fi
warn "Не удалось включить синхронизацию времени. Поставьте клиент вручную: apt install systemd-timesyncd"
}
other_ntp_installed() {
local p
for p in chrony ntp ntpsec openntpd; do
[[ $(dpkg-query -W -f='${Status}' "$p" 2>/dev/null) == "install ok installed" ]] && return 0
done
return 1
}
# Что чинить сейчас: если найдена причина (TLS у подписки), перезапуски kit-sub и nginx – лишь
# следствия: сначала лечим причину, потом проверяем заново.
fix_plan() {
@@ -882,7 +949,7 @@ ${B}kit${N} $KIT_VERSION – управление сервером 3X-UI KIT
Пользователи (один пользователь сразу на всех протоколах):
kit user add имя [--gb 50] [--days 30] [--devices 3] добавить и показать подписку
kit user list трафик, срок, статус
kit user link имя [--all] подписка и QR; --all – ещё vpn:// и tg://
kit user link имя [--all|--amnezia|--telegram] подписка и QR; --all, --amnezia, --telegram – отдельные ссылки
kit user limit имя [--gb N] [--days N] [--devices N] изменить лимиты (0 – без ограничений)
kit user off имя / kit user on имя выключить и включить
kit user del имя удалить