From 534ff8bd0ab3182087c21570217fc3732c9d13af Mon Sep 17 00:00:00 2001 From: xiagw Date: Sat, 7 Dec 2024 20:40:34 +0800 Subject: [PATCH 1/3] Refactor install-release.sh to improve error handling and streamline checks - Changed exit calls to return statements for better control flow. - Updated user and OS checks to enhance script robustness. - Improved network request handling for fetching release versions. - Enhanced readability and maintainability of the code. --- install-release.sh | 63 ++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/install-release.sh b/install-release.sh index 7fa9fc8..c7ca8ee 100755 --- a/install-release.sh +++ b/install-release.sh @@ -117,16 +117,18 @@ systemd_cat_config() { check_if_running_as_root() { # If you want to run as another user, please modify $EUID to be owned by this user - if [[ "$EUID" -ne '0' ]]; then + if [[ "$(id -u)" -eq 0 ]]; then + return 0 + else echo "error: You must run this script as root!" - exit 1 + return 1 fi } identify_the_operating_system_and_architecture() { if [[ "$(uname)" != 'Linux' ]]; then echo "error: This operating system is not supported." - exit 1 + return 1 fi case "$(uname -m)" in 'i386' | 'i686') @@ -176,12 +178,12 @@ identify_the_operating_system_and_architecture() { ;; *) echo "error: The architecture is not supported." - exit 1 + return 1 ;; esac if [[ ! -f '/etc/os-release' ]]; then echo "error: Don't use outdated Linux distributions." - exit 1 + return 1 fi # Do not combine this judgment condition with the following judgment condition. ## Be aware of Linux distribution like Gentoo, which kernel supports switch between Systemd and OpenRC. @@ -191,7 +193,7 @@ identify_the_operating_system_and_architecture() { true else echo "error: Only Linux distributions using systemd are supported." - exit 1 + return 1 fi if [[ "$(type -P apt)" ]]; then PACKAGE_MANAGEMENT_INSTALL='apt -y --no-install-recommends install' @@ -219,7 +221,7 @@ identify_the_operating_system_and_architecture() { package_provide_tput='ncurses' else echo "error: The script does not support the package manager in this operating system." - exit 1 + return 1 fi } @@ -256,7 +258,7 @@ judgment_parameters() { '--version') if [[ -z "$2" ]]; then echo "error: Please specify the correct version." - exit 1 + return 1 fi temp_version='1' SPECIFIED_VERSION="$2" @@ -272,7 +274,7 @@ judgment_parameters() { local_install='1' if [[ -z "$2" ]]; then echo "error: Please specify the correct local file." - exit 1 + return 1 fi LOCAL_FILE="$2" shift @@ -280,7 +282,7 @@ judgment_parameters() { '-p' | '--proxy') if [[ -z "$2" ]]; then echo "error: Please specify the proxy server address." - exit 1 + return 1 fi PROXY="$2" shift @@ -288,7 +290,7 @@ judgment_parameters() { '-u' | '--install-user') if [[ -z "$2" ]]; then echo "error: Please specify the install user.}" - exit 1 + return 1 fi INSTALL_USER="$2" shift @@ -310,7 +312,7 @@ judgment_parameters() { ;; *) echo "$0: unknown option -- -" - exit 1 + return 1 ;; esac shift @@ -319,11 +321,11 @@ judgment_parameters() { INSTALL='1' elif ((INSTALL+INSTALL_GEODATA+HELP+CHECK+REMOVE>1)); then echo 'You can only choose one action.' - exit 1 + return 1 fi if [[ "$INSTALL" -eq '1' ]] && ((temp_version+local_install+REINSTALL+BETA>1)); then echo "--version,--reinstall,--beta and --local can't be used together." - exit 1 + return 1 fi } @@ -372,7 +374,10 @@ get_latest_version() { # Get Xray latest release version number local tmp_file tmp_file="$(mktemp)" - if ! curl -x "${PROXY}" -sS -H "Accept: application/vnd.github.v3+json" -o "$tmp_file" 'https://api.github.com/repos/XTLS/Xray-core/releases/latest'; then + local url='https://api.github.com/repos/XTLS/Xray-core/releases/latest' + if curl -x "${PROXY}" -sSfLo "$tmp_file" -H "Accept: application/vnd.github.v3+json" "$url"; then + echo "get release list success" + else "rm" "$tmp_file" echo 'error: Failed to get release list, please check your network.' exit 1 @@ -390,14 +395,16 @@ get_latest_version() { fi "rm" "$tmp_file" RELEASE_LATEST="v${RELEASE_LATEST#v}" - if ! curl -x "${PROXY}" -sS -H "Accept: application/vnd.github.v3+json" -o "$tmp_file" 'https://api.github.com/repos/XTLS/Xray-core/releases'; then + if curl -x "${PROXY}" -sSfLo "$tmp_file" -H "Accept: application/vnd.github.v3+json" "$url"; then + echo "get release list success" + else "rm" "$tmp_file" echo 'error: Failed to get release list, please check your network.' exit 1 fi local releases_list - releases_list=($(sed 'y/,/\n/' "$tmp_file" | grep 'tag_name' | awk -F '"' '{print $4}')) - if [[ "${#releases_list[@]}" -eq '0' ]]; then + readarray -t releases_list < <(sed 'y/,/\n/' "$tmp_file" | grep 'tag_name' | awk -F '"' '{print $4}') + if [[ "${#releases_list[@]}" -eq 0 ]]; then if grep -q "API rate limit exceeded" "$tmp_file"; then echo "error: github API rate limit exceeded" else @@ -407,14 +414,16 @@ get_latest_version() { "rm" "$tmp_file" exit 1 fi - local i - for i in "${!releases_list[@]}" - do + local i url_zip + for i in "${!releases_list[@]}"; do releases_list["$i"]="v${releases_list[$i]#v}" - grep -q "https://github.com/XTLS/Xray-core/releases/download/${releases_list[$i]}/Xray-linux-$MACHINE.zip" "$tmp_file" && break + url_zip="https://github.com/XTLS/Xray-core/releases/download/${releases_list[$i]}/Xray-linux-$MACHINE.zip" + if grep -q "$url_zip" "$tmp_file"; then + PRE_RELEASE_LATEST="${releases_list[$i]}" + break + fi done "rm" "$tmp_file" - PRE_RELEASE_LATEST="${releases_list[$i]}" } version_gt() { @@ -422,7 +431,7 @@ version_gt() { } download_xray() { - DOWNLOAD_LINK="https://github.com/XTLS/Xray-core/releases/download/${INSTALL_VERSION}/Xray-linux-${MACHINE}.zip" + local DOWNLOAD_LINK="https://github.com/XTLS/Xray-core/releases/download/${INSTALL_VERSION}/Xray-linux-${MACHINE}.zip" echo "Downloading Xray archive: $DOWNLOAD_LINK" if curl -f -x "${PROXY}" -R -H 'Cache-Control: no-cache' -o "$ZIP_FILE" "$DOWNLOAD_LINK"; then echo "ok." @@ -811,9 +820,9 @@ show_help() { } main() { - check_if_running_as_root - identify_the_operating_system_and_architecture - judgment_parameters "$@" + check_if_running_as_root || return 1 + identify_the_operating_system_and_architecture || return 1 + judgment_parameters "$@" || return 1 install_software "$package_provide_tput" 'tput' red=$(tput setaf 1) From 75c9580145eef7f674f10e906508dfb1a09fd209 Mon Sep 17 00:00:00 2001 From: xiagw Date: Sat, 7 Dec 2024 21:57:30 +0800 Subject: [PATCH 2/3] Add OpenWrt support to install-release.sh - Implemented detection for OpenWrt systems, enhancing compatibility. - Updated package management commands for OpenWrt using 'opkg'. - Added installation and service management for Xray on OpenWrt, including init script creation. - Improved error handling for unsupported operating systems and architectures. - Enhanced logging setup for Xray service on OpenWrt. --- install-release.sh | 395 +++++++++++++++++++++++++++++---------------- 1 file changed, 259 insertions(+), 136 deletions(-) diff --git a/install-release.sh b/install-release.sh index c7ca8ee..013b34c 100755 --- a/install-release.sh +++ b/install-release.sh @@ -130,57 +130,77 @@ identify_the_operating_system_and_architecture() { echo "error: This operating system is not supported." return 1 fi + + # Add OpenWrt detection + if grep -q -i 'openwrt' /etc/openwrt_release 2>/dev/null; then + echo "info: OpenWrt system detected." + OPENWRT=1 + else + OPENWRT=0 + fi + case "$(uname -m)" in - 'i386' | 'i686') - MACHINE='32' - ;; - 'amd64' | 'x86_64') - MACHINE='64' - ;; - 'armv5tel') - MACHINE='arm32-v5' - ;; - 'armv6l') - MACHINE='arm32-v6' - grep Features /proc/cpuinfo | grep -qw 'vfp' || MACHINE='arm32-v5' - ;; - 'armv7' | 'armv7l') - MACHINE='arm32-v7a' - grep Features /proc/cpuinfo | grep -qw 'vfp' || MACHINE='arm32-v5' - ;; - 'armv8' | 'aarch64') - MACHINE='arm64-v8a' - ;; - 'mips') - MACHINE='mips32' - ;; - 'mipsle') - MACHINE='mips32le' - ;; - 'mips64') - MACHINE='mips64' - lscpu | grep -q "Little Endian" && MACHINE='mips64le' - ;; - 'mips64le') - MACHINE='mips64le' - ;; - 'ppc64') - MACHINE='ppc64' - ;; - 'ppc64le') - MACHINE='ppc64le' - ;; - 'riscv64') - MACHINE='riscv64' - ;; - 's390x') - MACHINE='s390x' - ;; - *) - echo "error: The architecture is not supported." - return 1 - ;; + 'i386' | 'i686') + MACHINE='32' + ;; + 'amd64' | 'x86_64') + MACHINE='64' + ;; + 'armv5tel') + MACHINE='arm32-v5' + ;; + 'armv6l') + MACHINE='arm32-v6' + grep Features /proc/cpuinfo | grep -qw 'vfp' || MACHINE='arm32-v5' + ;; + 'armv7' | 'armv7l') + MACHINE='arm32-v7a' + grep Features /proc/cpuinfo | grep -qw 'vfp' || MACHINE='arm32-v5' + ;; + 'armv8' | 'aarch64') + MACHINE='arm64-v8a' + ;; + 'mips') + MACHINE='mips32' + ;; + 'mipsle') + MACHINE='mips32le' + ;; + 'mips64') + MACHINE='mips64' + lscpu | grep -q "Little Endian" && MACHINE='mips64le' + ;; + 'mips64le') + MACHINE='mips64le' + ;; + 'ppc64') + MACHINE='ppc64' + ;; + 'ppc64le') + MACHINE='ppc64le' + ;; + 'riscv64') + MACHINE='riscv64' + ;; + 's390x') + MACHINE='s390x' + ;; + *) + echo "error: The architecture is not supported." + return 1 + ;; esac + + if [[ "$OPENWRT" -eq '1' ]]; then + if [[ ! -f '/etc/openwrt_release' ]]; then + echo "error: Not a supported OpenWrt system." + return 1 + fi + PACKAGE_MANAGEMENT_INSTALL='opkg update; opkg install' + PACKAGE_MANAGEMENT_REMOVE='opkg remove' + package_provide_tput='ncurses-utils' + return 0 + fi if [[ ! -f '/etc/os-release' ]]; then echo "error: Don't use outdated Linux distributions." return 1 @@ -215,7 +235,7 @@ identify_the_operating_system_and_architecture() { PACKAGE_MANAGEMENT_INSTALL='pacman -Syy --noconfirm' PACKAGE_MANAGEMENT_REMOVE='pacman -Rsn' package_provide_tput='ncurses' - elif [[ "$(type -P emerge)" ]]; then + elif [[ "$(type -P emerge)" ]]; then PACKAGE_MANAGEMENT_INSTALL='emerge -qv' PACKAGE_MANAGEMENT_REMOVE='emerge -Cv' package_provide_tput='ncurses' @@ -231,89 +251,89 @@ judgment_parameters() { local temp_version='0' while [[ "$#" -gt '0' ]]; do case "$1" in - 'install') - INSTALL='1' - ;; - 'install-geodata') - INSTALL_GEODATA='1' - ;; - 'remove') - REMOVE='1' - ;; - 'help') - HELP='1' - ;; - 'check') - CHECK='1' - ;; - '--without-geodata') - NO_GEODATA='1' - ;; - '--without-logfiles') - NO_LOGFILES='1' - ;; - '--purge') - PURGE='1' - ;; - '--version') - if [[ -z "$2" ]]; then - echo "error: Please specify the correct version." - return 1 - fi - temp_version='1' - SPECIFIED_VERSION="$2" - shift - ;; - '-f' | '--force') - FORCE='1' - ;; - '--beta') - BETA='1' - ;; - '-l' | '--local') - local_install='1' - if [[ -z "$2" ]]; then - echo "error: Please specify the correct local file." - return 1 - fi - LOCAL_FILE="$2" - shift - ;; - '-p' | '--proxy') - if [[ -z "$2" ]]; then - echo "error: Please specify the proxy server address." - return 1 - fi - PROXY="$2" - shift - ;; - '-u' | '--install-user') - if [[ -z "$2" ]]; then - echo "error: Please specify the install user.}" - return 1 - fi - INSTALL_USER="$2" - shift - ;; - '--reinstall') - REINSTALL='1' - ;; - '--no-update-service') - N_UP_SERVICE='1' - ;; - '--logrotate') - if ! grep -qE '\b([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' <<< "$2";then - echo "error: Wrong format of time, it should be in the format of 12:34:56, under 10:00:00 should be start with 0, e.g. 01:23:45." - exit 1 - fi - LOGROTATE='1' - LOGROTATE_TIME="$2" - shift - ;; - *) - echo "$0: unknown option -- -" + 'install') + INSTALL='1' + ;; + 'install-geodata') + INSTALL_GEODATA='1' + ;; + 'remove') + REMOVE='1' + ;; + 'help') + HELP='1' + ;; + 'check') + CHECK='1' + ;; + '--without-geodata') + NO_GEODATA='1' + ;; + '--without-logfiles') + NO_LOGFILES='1' + ;; + '--purge') + PURGE='1' + ;; + '--version') + if [[ -z "$2" ]]; then + echo "error: Please specify the correct version." + return 1 + fi + temp_version='1' + SPECIFIED_VERSION="$2" + shift + ;; + '-f' | '--force') + FORCE='1' + ;; + '--beta') + BETA='1' + ;; + '-l' | '--local') + local_install='1' + if [[ -z "$2" ]]; then + echo "error: Please specify the correct local file." return 1 - ;; + fi + LOCAL_FILE="$2" + shift + ;; + '-p' | '--proxy') + if [[ -z "$2" ]]; then + echo "error: Please specify the proxy server address." + return 1 + fi + PROXY="$2" + shift + ;; + '-u' | '--install-user') + if [[ -z "$2" ]]; then + echo "error: Please specify the install user.}" + return 1 + fi + INSTALL_USER="$2" + shift + ;; + '--reinstall') + REINSTALL='1' + ;; + '--no-update-service') + N_UP_SERVICE='1' + ;; + '--logrotate') + if ! grep -qE '\b([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' <<< "$2";then + echo "error: Wrong format of time, it should be in the format of 12:34:56, under 10:00:00 should be start with 0, e.g. 01:23:45." + exit 1 + fi + LOGROTATE='1' + LOGROTATE_TIME="$2" + shift + ;; + *) + echo "$0: unknown option -- -" + return 1 + ;; esac shift done @@ -480,6 +500,27 @@ install_file() { } install_xray() { + # Install Xray binary to /usr/bin/ and /etc/xray (OpenWrt) + if [[ "$OPENWRT" -eq '1' ]]; then + cp "${TMP_DIRECTORY}/xray" "/usr/bin/xray" + chmod 755 "/usr/bin/xray" + mkdir -p /etc/xray + if [[ ! -f /etc/xray/config.json ]]; then + echo "{}" >"/etc/xray/config.json" + CONFIG_NEW='1' + fi + mkdir -p "/usr/share/xray" + cp "${TMP_DIRECTORY}/geoip.dat" "/usr/share/xray/geoip.dat" + cp "${TMP_DIRECTORY}/geosite.dat" "/usr/share/xray/geosite.dat" + mkdir -p /var/log/xray + chown -R "$INSTALL_USER_UID:$INSTALL_USER_GID" /var/log/xray + if [[ ! -f /var/log/xray/access.log ]]; then + touch /var/log/xray/access.log + touch /var/log/xray/error.log + LOG=1 + fi + return 0 + fi # Install Xray binary to /usr/local/bin/ and $DAT_PATH install_file xray # If the file exists, geoip.dat and geosite.dat will not be installed or updated @@ -521,6 +562,74 @@ install_xray() { } install_startup_service_file() { + if [[ "$OPENWRT" -eq '1' ]]; then + [[ -f /etc/init.d/xray ]] && return 0 + # Create OpenWrt init script + cat >/etc/init.d/xray <<'EOF' +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=99 + +CONF="xray" +PROG="/usr/bin/xray" + +start_service() { + config_load "$CONF" + + local enabled + config_get_bool enabled "enabled" "enabled" "0" + [ "$enabled" -eq "1" ] || return 1 + + local confdir + local conffiles + local datadir + local dialer + local format + + config_get confdir "config" "confdir" + config_get conffiles "config" "conffiles" + config_get datadir "config" "datadir" "/usr/share/xray" + config_get dialer "config" "dialer" + config_get format "config" "format" "json" + + procd_open_instance "$CONF" + procd_set_param command "$PROG" run + [ -n "$confdir" ] && procd_append_param command -confdir "$confdir" + [ -n "$conffiles" ] && { + for i in $conffiles + do + procd_append_param command -config "$i" + done + } + [ -n "$format" ] && procd_append_param command -format "$format" + [ -n "$dialer" ] && procd_set_param env XRAY_BROWSER_DIALER="$dialer" + procd_set_param env XRAY_LOCATION_ASSET="$datadir" + procd_set_param file $conffiles + + procd_set_param limits core="unlimited" + procd_set_param limits nofile="1000000 1000000" + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param respawn + + procd_close_instance +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "$CONF" +} +EOF + + chmod +x /etc/init.d/xray + /etc/init.d/xray enable + return 0 + fi mkdir -p '/etc/systemd/system/xray.service.d' mkdir -p '/etc/systemd/system/xray@.service.d/' local temp_CapabilityBoundingSet="CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE" @@ -613,6 +722,15 @@ ExecStart=/usr/local/bin/xray run -config ${JSON_PATH}/%i.json" > \ } start_xray() { + if [[ "$OPENWRT" -eq 1 ]]; then + if /etc/init.d/xray start; then + echo 'info: Start the Xray service.' + else + echo 'error: Failed to start Xray service.' + exit 1 + fi + return 0 + fi if [[ -f '/etc/systemd/system/xray.service' ]]; then systemctl start "${XRAY_CUSTOMIZE:-xray}" sleep 1s @@ -626,6 +744,11 @@ start_xray() { } stop_xray() { + if [[ "$OPENWRT" -eq '1' ]]; then + /etc/init.d/xray stop + echo 'info: Stop the Xray service.' + return 0 + fi XRAY_CUSTOMIZE="$(systemctl list-units | grep 'xray@' | awk -F ' ' '{print $1}')" if [[ -z "$XRAY_CUSTOMIZE" ]]; then local xray_daemon_to_stop='xray.service' @@ -642,7 +765,7 @@ stop_xray() { install_with_logrotate() { install_software 'logrotate' 'logrotate' if [[ -z "$LOGROTATE_TIME" ]]; then - LOGROTATE_TIME="00:00:00" + LOGROTATE_TIME="00:00:00" fi cat < /etc/systemd/system/logrotate@.service [Unit] @@ -665,8 +788,8 @@ Persistent=true WantedBy=timers.target EOF if [[ ! -d '/etc/logrotate.d/' ]]; then - install -d -m 700 -o "$INSTALL_USER_UID" -g "$INSTALL_USER_GID" /etc/logrotate.d/ - LOGROTATE_DIR='1' + install -d -m 700 -o "$INSTALL_USER_UID" -g "$INSTALL_USER_GID" /etc/logrotate.d/ + LOGROTATE_DIR='1' fi cat << EOF > /etc/logrotate.d/xray /var/log/xray/*.log { @@ -933,7 +1056,7 @@ main() { echo 'installed: /etc/systemd/system/logrotate@.service' echo 'installed: /etc/systemd/system/logrotate@.timer' if [[ "$LOGROTATE_DIR" -eq '1' ]]; then - echo 'installed: /etc/logrotate.d/' + echo 'installed: /etc/logrotate.d/' fi echo 'installed: /etc/logrotate.d/xray' systemctl start logrotate@xray.timer From 6fa27f3d104f5030b1ad56744e5fee7723a4a302 Mon Sep 17 00:00:00 2001 From: xiagw Date: Sat, 7 Dec 2024 22:14:43 +0800 Subject: [PATCH 3/3] Update README.md to standardize installation commands for Xray - Replaced `bash -c` commands with a more streamlined `curl` command format for installing, upgrading, and removing Xray-core and geodata. --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7d01dfc..3ed3b7c 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,19 @@ Notice: Xray will NOT log to `/var/log/xray/*.log` by default. Configure `"log"` **Install & Upgrade Xray-core and geodata with `User=nobody`, but will NOT overwrite `User` in existing service files** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - install ``` **Update geoip.dat and geosite.dat only** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install-geodata +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - install-geodata ``` **Remove Xray, except json and logs** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - remove ``` ## Advance @@ -45,13 +45,13 @@ bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release **Install & Upgrade Xray-core to a pre-release version** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install --beta +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - install --beta ``` **Install & Upgrade Xray-core and geodata with `logrotate`, `$time` can be in the format of 12:34:56** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install --logrotate $time +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - install --logrotate $time ``` ``` installed: /etc/systemd/system/logrotate@.service @@ -63,25 +63,25 @@ installed: /etc/logrotate.d/xray **Install & Upgrade Xray-core and geodata with `User=root`, which will overwrite `User` in existing service files** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -u root +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - install -u root ``` **Install & Upgrade Xray-core without geodata** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install --without-geodata +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - install --without-geodata ``` **Remove Xray, include json and logs** ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - remove --purge ``` ## More Usage ``` -bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ help +curl -fL https://github.com/XTLS/Xray-install/raw/main/install-release.sh | bash -s - help ``` ## Stargazers over time