#!/bin/sh # ============================================================ # Деплой frpc на роутер OpenWRT без установки пакета. # frpc скачивается в /tmp при каждой перезагрузке. # SERVER_IP и FRP_TOKEN получаются автоматически с bootstrap API. # # Использование: # sh -c "$(wget -qO- https://raw.githubusercontent.com/Official-VPN/Routers-FRP/main/router/setup-tmpfs.sh)" # или: # ./setup-tmpfs.sh # # Требования: wget с поддержкой HTTPS (встроен в OpenWRT 23/24) # ============================================================ BOOTSTRAP_DOMAIN="getconfig.tgvpnbot.com" # --- Определяем архитектуру роутера --- detect_arch() { local machine machine=$(uname -m) case "$machine" in mips) if grep -q "MIPS.*EB\|Big Endian" /proc/cpuinfo 2>/dev/null; then echo "mips" else echo "mipsle" fi ;; mipsel) echo "mipsle" ;; mips64) echo "mips64" ;; mips64el) echo "mips64le" ;; armv7l|armv6l) echo "arm" ;; aarch64) echo "arm64" ;; x86_64) echo "amd64" ;; i686|i386) echo "386" ;; *) echo "unknown" ;; esac } ARCH=$(detect_arch) if [ "$ARCH" = "unknown" ]; then echo "ERROR: Cannot detect CPU architecture (uname -m = $(uname -m))" exit 1 fi echo "CPU architecture: $(uname -m) → frpc arch: ${ARCH}" # --- Получаем MAC-адрес WAN-интерфейса --- WAN_DEV=$(uci get network.wan.device 2>/dev/null) [ -z "$WAN_DEV" ] && WAN_DEV=$(uci get network.wan.ifname 2>/dev/null) [ -z "$WAN_DEV" ] && WAN_DEV=$(uci get network.wan6.device 2>/dev/null) [ -z "$WAN_DEV" ] && WAN_DEV="eth0" MAC_RAW=$(cat /sys/class/net/"${WAN_DEV}"/address 2>/dev/null) if [ -z "$MAC_RAW" ]; then MAC_RAW=$(ip link show "$WAN_DEV" 2>/dev/null | awk '/link\/ether/{print $2}') fi if [ -z "$MAC_RAW" ]; then echo "ERROR: Cannot detect WAN MAC address (device: ${WAN_DEV})" exit 1 fi MAC=$(echo "$MAC_RAW" | tr ':' '-' | tr 'a-f' 'A-F') MAC_PLAIN=$(echo "$MAC_RAW" | tr -d ':' | tr 'a-f' 'A-F') echo "WAN device : $WAN_DEV" echo "WAN MAC : $MAC_RAW" echo "Proxy names: ssh-${MAC} / luci-${MAC}" echo "" # --- Получаем SERVER_IP и FRP_TOKEN с bootstrap API --- echo "Fetching FRP config from ${BOOTSTRAP_DOMAIN} ..." BOOTSTRAP_RESPONSE=$(wget -q --no-check-certificate \ -O - "https://${BOOTSTRAP_DOMAIN}/getfrpconfig?routermac=${MAC_PLAIN}" 2>/tmp/frpc_bootstrap.log) if [ -z "$BOOTSTRAP_RESPONSE" ]; then echo "ERROR: Bootstrap API unreachable or returned empty response" echo "Check: cat /tmp/frpc_bootstrap.log" echo "Make sure MAC ${MAC_RAW} is registered in the Router-Configs-Backend" exit 1 fi SERVER_IP=$(echo "$BOOTSTRAP_RESPONSE" | sed -n 's/.*"server_ip"[^:]*:[^"]*"\([^"]*\)".*/\1/p') FRP_TOKEN=$(echo "$BOOTSTRAP_RESPONSE" | sed -n 's/.*"frp_token"[^:]*:[^"]*"\([^"]*\)".*/\1/p') if [ -z "$SERVER_IP" ] || [ -z "$FRP_TOKEN" ]; then echo "ERROR: Failed to parse bootstrap response:" echo "$BOOTSTRAP_RESPONSE" exit 1 fi echo "Bootstrap OK: server=${SERVER_IP}" echo "" # --- Сохраняем конфиг для бутового скрипта --- CONFIG_PERSIST="/etc/frpc_bootstrap.conf" cat > "$CONFIG_PERSIST" < "$INIT_SCRIPT" <<'INITEOF' #!/bin/sh /etc/rc.common # frpc-boot — при каждом ребуте: обновляет конфиг с bootstrap API, # скачивает frpc в /tmp и запускает его. START=99 STOP=10 USE_PROCD=1 CONF="/etc/frpc_bootstrap.conf" FRPC_BIN="/tmp/frpc" FRPC_CONF="/tmp/frpc.toml" FRPC_LOG="/tmp/frpc.log" DOWNLOAD_BASE="https://github.com/fatedier/frp/releases/download" load_config() { if [ ! -f "$CONF" ]; then logger -t frpc-boot "ERROR: $CONF not found" return 1 fi . "$CONF" if [ -z "$MAC" ] || [ -z "$FRP_ARCH" ]; then logger -t frpc-boot "ERROR: incomplete config in $CONF" return 1 fi return 0 } # Обновляем SERVER_IP и FRP_TOKEN с bootstrap API fetch_frp_config() { if [ -z "$BOOTSTRAP_DOMAIN" ]; then logger -t frpc-boot "No BOOTSTRAP_DOMAIN, using cached config" return 0 fi logger -t frpc-boot "Fetching FRP config from ${BOOTSTRAP_DOMAIN} ..." local response response=$(wget -q --no-check-certificate \ -O - "https://${BOOTSTRAP_DOMAIN}/getfrpconfig?routermac=${MAC_PLAIN}" \ 2>/tmp/frpc_bootstrap.log) || true if [ -z "$response" ]; then logger -t frpc-boot "Bootstrap unreachable, using cached config (${SERVER_IP})" return 0 fi local new_ip new_token new_ip=$(echo "$response" | sed -n 's/.*"server_ip"[^:]*:[^"]*"\([^"]*\)".*/\1/p') new_token=$(echo "$response" | sed -n 's/.*"frp_token"[^:]*:[^"]*"\([^"]*\)".*/\1/p') if [ -n "$new_ip" ] && [ -n "$new_token" ]; then if [ "$new_ip" != "$SERVER_IP" ] || [ "$new_token" != "$FRP_TOKEN" ]; then sed -i "s|^SERVER_IP=.*|SERVER_IP=\"${new_ip}\"|" "$CONF" sed -i "s|^FRP_TOKEN=.*|FRP_TOKEN=\"${new_token}\"|" "$CONF" . "$CONF" logger -t frpc-boot "FRP config updated: server=${new_ip}" else logger -t frpc-boot "FRP config unchanged: server=${SERVER_IP}" fi else logger -t frpc-boot "Invalid bootstrap response, using cached config" fi } download_frpc() { local version="${FRP_VERSION:-0.61.1}" local arch="${FRP_ARCH}" local url="${DOWNLOAD_BASE}/v${version}/frp_${version}_linux_${arch}.tar.gz" local tmp_tar="/tmp/frp_download.tar.gz" logger -t frpc-boot "Downloading frpc ${version} (${arch}) ..." if wget -q --no-check-certificate -O "$tmp_tar" "$url" 2>/tmp/frpc_wget.log; then local tmp_dir="/tmp/frp_extract" rm -rf "$tmp_dir" mkdir -p "$tmp_dir" if tar -xzf "$tmp_tar" -C "$tmp_dir" 2>/tmp/frpc_wget.log; then mv "$tmp_dir"/frp_*/frpc "$FRPC_BIN" 2>/dev/null \ || mv "$tmp_dir"/frpc "$FRPC_BIN" 2>/dev/null chmod +x "$FRPC_BIN" rm -rf "$tmp_dir" "$tmp_tar" logger -t frpc-boot "frpc downloaded OK" return 0 else logger -t frpc-boot "ERROR: tar failed" rm -rf "$tmp_dir" "$tmp_tar" return 1 fi else logger -t frpc-boot "ERROR: wget failed — $(cat /tmp/frpc_wget.log)" rm -f "$tmp_tar" return 1 fi } write_config() { cat > "$FRPC_CONF" </dev/null 2>&1; then echo "" echo "OK: frpc is running" echo " Server : ${SERVER_IP}" echo " Binary : /tmp/frpc" echo " Config : /tmp/frpc.toml" echo " Proxies: ssh-${MAC} / luci-${MAC}" else echo "" echo "WARNING: frpc may not be running." echo "Check:" echo " logread | grep frpc-boot" echo " cat /tmp/frpc.log" fi