op-packages/homeproxy-hiddify/install.sh
github-actions[bot] ae7b9f4d28 🎁 Sync 2026-07-31 00:21:49
2026-07-31 00:21:49 +08:00

221 lines
14 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Установщик Re:HomeProxy для OpenWrt (в одном скрипте: APK / opkg / 23.05 legacy)
# https://github.com/1andrevich/homeproxy-hiddify
#
# Вручную ставится только LuCI-приложение + ключ подписи, а ядро, ByeDPI и Zapret
# устанавливаются через собственный бэкенд приложения (core_mgmt.uc + rpcd-объект
# luci.homeproxy) — поэтому определение архитектуры, компактные сборки под малую
# флеш-память, проверка подписи и резерв через зеркало GitHub работают той же
# проверенной логикой, что и графический интерфейс.
#
# Установка (одной строкой — ввод читается из /dev/tty, пайп остаётся интерактивным):
# wget -qO- https://raw.githubusercontent.com/1andrevich/homeproxy-hiddify/master/install.sh | sh
# Либо в два шага:
# wget -O /tmp/install.sh https://raw.githubusercontent.com/1andrevich/homeproxy-hiddify/master/install.sh
# sh /tmp/install.sh
#
# При заблокированном/замедленном GitHub можно указать зеркало:
# GH_MIRROR=https://my.mirror sh install.sh
# (зеркало также пишется в uci, чтобы делегированные загрузки тоже его использовали).
# Внимание: `sh <(wget -O- ...)` на OpenWrt НЕ работает — в busybox ash нет
# process substitution; используйте форму с пайпом выше.
G='\033[0;32m'; R='\033[0;31m'; Y='\033[0;33m'; C='\033[0;36m'; N='\033[0m'
ok() { echo -e "${G}$1${N}"; }
info() { echo -e "${C}$1${N}"; }
warn() { echo -e "${Y}$1${N}"; }
die() { echo -e "${R}$1${N}"; exit 1; }
ask() { printf "${C}%s${N} " "$1"; read -r REPLY </dev/tty 2>/dev/null || REPLY=""; }
is_yes() { case "$1" in y|Y|yes|YES|да|Да|д|Д) return 0;; *) return 1;; esac; }
# --- Разбор JSON (на устройстве нет jq): достать строковое поле / проверить result:true
jget() { printf '%s\n' "$1" | sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1; }
jtrue() { printf '%s' "$1" | grep -qE "\"result\"[[:space:]]*:[[:space:]]*true"; }
jerr() { printf '%s\n' "$1" | grep -qE "\"error\""; }
jfalse(){ printf '%s' "$1" | grep -qE "\"$2\"[[:space:]]*:[[:space:]]*false"; }
# --- Загрузка «сначала GitHub, при сбое — зеркало» для первого хопа (app + ключ),
# пока ещё нет собственного gh_fetch приложения. dl <url> <файл>
dl() {
wget -qO "$2" --timeout=20 "$1" 2>/dev/null && [ -s "$2" ] && return 0
if [ -n "$GH_MIRROR" ]; then
m=$(echo "$1" | sed "s#https://github.com#${GH_MIRROR}#")
wget -qO "$2" --timeout=20 "$m" 2>/dev/null && [ -s "$2" ] && return 0
fi
return 1
}
api() { wget -qO- --timeout=20 "$1" 2>/dev/null; } # GitHub API (без зеркала)
echo
ok "===== Установщик Re:HomeProxy ====="
# ---------------------------------------------------------------- 0. окружение
[ "$(id -u)" = 0 ] || die "Запустите от root."
[ -r /etc/openwrt_release ] || die "Это не OpenWrt (нет /etc/openwrt_release)."
. /etc/openwrt_release 2>/dev/null
ARCH="$DISTRIB_ARCH"; VER="$DISTRIB_RELEASE"
[ -n "$ARCH" ] || die "Не удалось определить архитектуру пакетов (DISTRIB_ARCH)."
if command -v apk >/dev/null 2>&1; then PM=apk; EXT=apk
elif command -v opkg >/dev/null 2>&1; then PM=opkg; EXT=ipk
else die "Не найден поддерживаемый менеджер пакетов (apk/opkg)."; fi
case "$VER" in
23.05*) LEGACY=1 ;;
24.10*|25.*|*SNAPSHOT*) LEGACY=0 ;;
22.*|21.*|19.*) die "OpenWrt $VER слишком старая — нужна 23.05 или новее." ;;
*) LEGACY=0; warn "Непроверенная версия OpenWrt $VER — продолжаю." ;;
esac
SUFFIX="_all"; [ "$LEGACY" = 1 ] && SUFFIX="_all-legacy"
info "Версия: OpenWrt $VER | Архитектура: $ARCH | Менеджер пакетов: $PM | legacy=$LEGACY"
# ----------------------------------------------------------- 1. LuCI-приложение + ключ
ok "[1/5] Устанавливаю LuCI-приложение Re:HomeProxy..."
if [ "$PM" = apk ]; then
if [ ! -f /etc/apk/keys/homeproxy-hiddify.pub ]; then
dl "https://github.com/1andrevich/homeproxy-hiddify/releases/latest/download/homeproxy-hiddify.pub" /tmp/hp.pub \
&& cp /tmp/hp.pub /etc/apk/keys/ && rm -f /tmp/hp.pub && ok " ключ подписи добавлен в доверенные" \
|| warn " не удалось скачать ключ подписи — поставлю без проверки подписи"
fi
fi
APPURL=$(api 'https://api.github.com/repos/1andrevich/homeproxy-hiddify/releases' \
| grep -o "https://github\.com/[^\"]*luci-app-re-homeproxy[^\"]*${SUFFIX}\.${EXT}" | head -1)
[ -n "$APPURL" ] || die "Не нашёл пакет luci-app-re-homeproxy${SUFFIX}.${EXT} (GitHub заблокирован? попробуйте GH_MIRROR=...)."
dl "$APPURL" /tmp/app.$EXT || die "Не удалось скачать приложение (попробуйте GH_MIRROR=...)."
if [ "$PM" = apk ]; then
apk add /tmp/app.$EXT 2>/dev/null || apk add --allow-untrusted /tmp/app.$EXT || die "apk add завершился ошибкой."
else
opkg update >/dev/null 2>&1; opkg install /tmp/app.$EXT || die "opkg install завершился ошибкой."
fi
rm -f /tmp/app.$EXT
ok " приложение установлено."
# Русский язык интерфейса (по умолчанию — да)
ask " Установить пакет русского языка? [Y/n] (по умолчанию Y):"
case "$REPLY" in
n|N|no|NO|нет|Нет|н|Н) ;; # отказ — пропускаем
*)
info " ставлю русский язык LuCI..."
# базовый перевод интерфейса LuCI (из фида, best-effort)
if [ "$PM" = apk ]; then apk add luci-i18n-base-ru >/dev/null 2>&1; else opkg install luci-i18n-base-ru >/dev/null 2>&1; fi
# перевод самого приложения (из релиза homeproxy)
LURL=$(api 'https://api.github.com/repos/1andrevich/homeproxy-hiddify/releases' \
| grep -o "https://github\.com/[^\"]*luci-i18n-homeproxy-ru[^\"]*\.${EXT}" | head -1)
if [ -n "$LURL" ] && dl "$LURL" /tmp/i18n.$EXT; then
if [ "$PM" = apk ]; then apk add /tmp/i18n.$EXT 2>/dev/null || apk add --allow-untrusted /tmp/i18n.$EXT; \
else opkg install /tmp/i18n.$EXT; fi
else warn " перевод приложения не найден — пропускаю"; fi
rm -f /tmp/i18n.$EXT
uci set luci.main.lang=ru; uci commit luci
ok " русский язык установлен" ;;
esac
# Прописываем зеркало в бэкенд, чтобы делегированные загрузки тоже его использовали
if [ -n "$GH_MIRROR" ]; then uci set homeproxy.config.github_mirror="$GH_MIRROR"; uci commit homeproxy; fi
# rpcd нужно перезапустить, чтобы появились ubus-методы приложения (установка ByeDPI/Zapret)
/etc/init.d/rpcd restart >/dev/null 2>&1; sleep 2
CM=/usr/share/homeproxy/scripts/core_mgmt.uc
[ -f "$CM" ] || die "core_mgmt.uc не найден после установки — прерываю."
# ------------------------------------------------------- 2. ядро прокси (обязательно)
ok "[2/5] Ядро прокси (обязательно — выберите одно)"
echo " 1) hiddify-core (по умолчанию; на малой флеш-памяти выберет компактную сборку)"
echo " 2) sing-box-extended (AmneziaWG / WARP, самый широкий набор протоколов)"
ask " Выбор [1/2] (по умолчанию 1):"
case "$REPLY" in 2) CORE=singbox ;; *) CORE=hiddify ;; esac
PREP=$(ucode "$CM" prepare_install "$CORE")
jerr "$PREP" && die " подготовка ядра не удалась: $(jget "$PREP" error)"
DLURL=$(jget "$PREP" dl_url); TMP=$(jget "$PREP" tmp_path); PMG=$(jget "$PREP" pkg_manager)
[ -n "$DLURL" ] && [ -n "$TMP" ] && [ -n "$PMG" ] || die " подготовка ядра не вернула данные для загрузки."
info " скачиваю $CORE..."
jtrue "$(ucode "$CM" download_pkg "$DLURL" "$TMP")" || die " не удалось скачать ядро (попробуйте GH_MIRROR=...)."
jtrue "$(ucode "$CM" install_pkg "$CORE" "$TMP" "$PMG")" || die " установка ядра не удалась."
jtrue "$(ucode "$CM" install_kmods "$PMG")" || warn " не удалось поставить kmod — без kmod-nft-tproxy/kmod-tun прокси не будет маршрутизировать."
ok " $CORE установлен."
# --------------------------------------------------------------- 3. Zapret (опционально)
ask "[3/5] Установить Zapret 2 (обход DPI на уровне пакетов — видео/QUIC, звонки)? [y/N]:"
if is_yes "$REPLY"; then
info " ставлю модуль ядра NFQUEUE..."
if [ "$PM" = apk ]; then apk add kmod-nft-queue >/dev/null 2>&1; else opkg install kmod-nft-queue >/dev/null 2>&1; fi
ZP=$(ubus call luci.homeproxy zapret_prepare_install 2>/dev/null)
if [ -z "$ZP" ] || jerr "$ZP"; then warn " не удалось подготовить Zapret — пропускаю. ($(jget "$ZP" error))"
else
ZURL=$(jget "$ZP" dl_url); ZTMP=$(jget "$ZP" tmp_path); ZPMG=$(jget "$ZP" pkg_manager)
if [ -n "$ZURL" ] && dl "$ZURL" "$ZTMP"; then
RES=$(ubus call luci.homeproxy zapret_install_pkg "{\"tmp_path\":\"$ZTMP\",\"pkg_manager\":\"$ZPMG\"}" 2>/dev/null)
if jtrue "$RES"; then
ok " Zapret установлен."
ZST=$(ubus call luci.homeproxy zapret_status 2>/dev/null)
if jfalse "$ZST" kmod_ok; then
warn " модуль NFQUEUE не загружен — Zapret не включаю (иначе сломается firewall). Включите вручную после kmod-nft-queue."
else
uci set homeproxy.config.zapret_enabled=1; uci commit homeproxy; ok " Zapret включён."
fi
else warn " установка Zapret не удалась."; fi
else warn " не удалось скачать Zapret — пропускаю."; fi
fi
fi
# --------------------------------------------------------------- 4. ByeDPI (опционально)
ask "[4/5] Установить ByeDPI (обход DPI на уровне SOCKS, нужен curl)? [y/N]:"
if is_yes "$REPLY"; then
info " ставлю curl (его использует тестер стратегий ByeDPI)..."
if [ "$PM" = apk ]; then apk add curl >/dev/null 2>&1; else opkg install curl >/dev/null 2>&1; fi
BP=$(ubus call luci.homeproxy byedpi_prepare_install 2>/dev/null)
if [ -z "$BP" ] || jerr "$BP"; then warn " не удалось подготовить ByeDPI — пропускаю. ($(jget "$BP" error))"
else
BURL=$(jget "$BP" dl_url); BTMP=$(jget "$BP" tmp_path); BPMG=$(jget "$BP" pkg_manager)
if [ -n "$BURL" ] && dl "$BURL" "$BTMP"; then
RES=$(ubus call luci.homeproxy byedpi_install_pkg "{\"tmp_path\":\"$BTMP\",\"pkg_manager\":\"$BPMG\"}" 2>/dev/null)
if jtrue "$RES"; then
ok " ByeDPI установлен."
uci set homeproxy.config.byedpi_enabled=1; uci commit homeproxy; ok " ByeDPI включён."
else warn " установка ByeDPI не удалась."; fi
else warn " не удалось скачать ByeDPI — пропускаю."; fi
fi
fi
# ------------------------------------------------- 5. режим маршрутизации (пресет)
ask "[5/5] Настроить режим «Россия — раздельное туннелирование» (Re:filter через основной сервер)? [Д/н] (по умолчанию да):"
case "$REPLY" in
n|N|no|NO|нет|Нет|н|Н) ;; # отказ — оставляем как есть
*)
CURMODE=$(uci -q get homeproxy.config.routing_mode)
if [ -z "$CURMODE" ]; then
uci set homeproxy.config.routing_mode=proxy_banned_ru
uci set homeproxy.config.proxy_calls=1
uci set homeproxy.config.no_proxy_torrents=1
uci set homeproxy.config.ipv6_support=0
uci commit homeproxy
CURMODE=proxy_banned_ru
fi
# Re:filter через основной пул — только если режим РФ и правил ещё нет
if [ "$CURMODE" = proxy_banned_ru ] && ! uci show homeproxy 2>/dev/null | grep -q "=proxy_ru_rule$"; then
SEC=$(uci add homeproxy proxy_ru_rule)
uci set "homeproxy.$SEC.source=refilter"
uci set "homeproxy.$SEC.node=main-out"
uci set "homeproxy.$SEC.enabled=1"
uci commit homeproxy
ok " режим настроен: Re:filter через основной сервер"
else
info " режим/правила уже заданы — не меняю"
fi ;;
esac
# ------------------------------------------------------------------- 6. финал
/etc/init.d/homeproxy enable >/dev/null 2>&1
/etc/init.d/homeproxy start >/dev/null 2>&1
# LAN-адрес роутера для прямой ссылки на страницу LuCI (обрезаем /маску на 25.12+)
LANIP=$(uci -q get network.lan.ipaddr | cut -d/ -f1)
[ -n "$LANIP" ] || LANIP=$(ip -4 addr show br-lan 2>/dev/null | sed -n 's#.*inet \([0-9.]*\).*#\1#p' | head -1)
[ -n "$LANIP" ] || LANIP="192.168.1.1"
echo
ok "===== Готово ====="
info "Откройте Re:HomeProxy в браузере:"
URL="http://$LANIP/cgi-bin/luci/admin/services/homeproxy"
# OSC 8: кликабельная ссылка в поддерживающих терминалах; в остальных просто виден URL
printf '\033[0;36m \033]8;;%s\033\\%s\033]8;;\033\\\033[0m\n' "$URL" "$URL"