Skip to content

Instantly share code, notes, and snippets.

@Yunuuuu
Last active July 14, 2026 05:29
Show Gist options
  • Select an option

  • Save Yunuuuu/c3f6790d96c9bf176ac2d196cbfac00e to your computer and use it in GitHub Desktop.

Select an option

Save Yunuuuu/c3f6790d96c9bf176ac2d196cbfac00e to your computer and use it in GitHub Desktop.
Install or update Xray from the SourceForge mirror.
# Install or update Xray from the SourceForge mirror.
#
# Usage:
# _install_xray [OPTIONS]
# _install_xray -h
# unset -f _install_xray
#
# Default mode: --user
#
# Default user layout:
# ${XDG_DATA_HOME:-$HOME/.local/share}/xray/xray
# ${XDG_DATA_HOME:-$HOME/.local/share}/xray/geoip.dat
# ${XDG_DATA_HOME:-$HOME/.local/share}/xray/geosite.dat
# ${XDG_CONFIG_HOME:-$HOME/.config}/xray/config.json
# $HOME/.local/bin/xray -> ${XDG_DATA_HOME:-$HOME/.local/share}/xray/xray
#
# Default system layout:
# /usr/local/share/xray/xray
# /usr/local/share/xray/geoip.dat
# /usr/local/share/xray/geosite.dat
# /usr/local/etc/xray/config.json
# /usr/local/bin/xray -> /usr/local/share/xray/xray
#
# Uninstall the default user installation:
# systemctl --user disable --now xray 2>/dev/null || true
# rm -f -- "$HOME/.local/bin/xray"
# rm -rf -- "${XDG_DATA_HOME:-$HOME/.local/share}/xray"
#
# Also remove the user configuration:
# rm -rf -- "${XDG_CONFIG_HOME:-$HOME/.config}/xray"
#
# Uninstall the default system installation:
# sudo systemctl disable --now xray 2>/dev/null || true
# sudo rm -f -- /usr/local/bin/xray
# sudo rm -rf -- /usr/local/share/xray
#
# Also remove the system configuration:
# sudo rm -rf -- /usr/local/etc/xray
_install_xray() {
local scope="user"
local scope_set=0
local data_home=""
local data_home_set=0
local bin_dir=""
local bin_dir_set=0
local config_home=""
local xray_home=""
local binary_mode=""
local data_dir_mode=""
local config_dir_mode=""
local bin_dir_mode=""
local machine=""
local archive_arch=""
local source_binary="xray"
local soft_float=0
local tmp=""
local source_dir=""
local latest_dir=""
local download_path=""
local new_xray=""
local file=""
local name=""
local rc=1
local base="https://sourceforge.net/projects/xray-core.mirror/files"
while (($# > 0)); do
case "$1" in
--user)
if ((scope_set)) && [[ $scope != user ]]; then
echo "Cannot use --user and --system together" >&2
return 2
fi
scope="user"
scope_set=1
shift
;;
--system)
if ((scope_set)) && [[ $scope != system ]]; then
echo "Cannot use --user and --system together" >&2
return 2
fi
scope="system"
scope_set=1
shift
;;
--data-home)
if (($# < 2)); then
echo "--data-home requires a value" >&2
return 2
fi
data_home="$2"
data_home_set=1
shift 2
;;
--data-home=*)
data_home="${1#*=}"
data_home_set=1
shift
;;
--bin-dir)
if (($# < 2)); then
echo "--bin-dir requires a value" >&2
return 2
fi
bin_dir="$2"
bin_dir_set=1
shift 2
;;
--bin-dir=*)
bin_dir="${1#*=}"
bin_dir_set=1
shift
;;
--soft-float)
soft_float=1
shift
;;
-h | --help)
cat <<'HELP'
Usage:
_install_xray [OPTIONS]
Options may appear in any order.
Options:
--user
Install for the current user. This is the default mode.
--system
Install system-wide. Root privileges are required.
--data-home PATH
--data-home=PATH
Set the parent directory of the Xray application directory.
Application files are installed into:
PATH/xray
Defaults:
user: ${XDG_DATA_HOME:-$HOME/.local/share}
system: /usr/local/share
--bin-dir PATH
--bin-dir=PATH
Create PATH/xray as a symbolic link to the installed executable.
Defaults:
user: $HOME/.local/bin
system: /usr/local/bin
Pass an empty value to skip link creation:
--bin-dir ""
--bin-dir=
Skipping link creation does not remove an existing link.
--soft-float
Use xray_softfloat from a MIPS32 or MIPS32LE archive.
-h, --help
Show this help.
Default user layout:
${XDG_DATA_HOME:-$HOME/.local/share}/xray/xray
${XDG_DATA_HOME:-$HOME/.local/share}/xray/geoip.dat
${XDG_DATA_HOME:-$HOME/.local/share}/xray/geosite.dat
${XDG_CONFIG_HOME:-$HOME/.config}/xray/config.json
$HOME/.local/bin/xray -> ${XDG_DATA_HOME:-$HOME/.local/share}/xray/xray
Default system layout:
/usr/local/share/xray/xray
/usr/local/share/xray/geoip.dat
/usr/local/share/xray/geosite.dat
/usr/local/etc/xray/config.json
/usr/local/bin/xray -> /usr/local/share/xray/xray
Examples:
_install_xray
_install_xray --user
_install_xray --system
_install_xray --bin-dir ""
_install_xray --soft-float
_install_xray \
--data-home "$HOME/.local/share" \
--bin-dir "$HOME/.local/bin"
_install_xray \
--system \
--data-home /usr/local/share \
--bin-dir /usr/local/bin
Run the default user installation:
xray run -c "${XDG_CONFIG_HOME:-$HOME/.config}/xray/config.json"
Run the default system installation:
xray run -c /usr/local/etc/xray/config.json
Uninstall the default user installation:
systemctl --user disable --now xray 2>/dev/null || true
rm -f -- "$HOME/.local/bin/xray"
rm -rf -- "${XDG_DATA_HOME:-$HOME/.local/share}/xray"
Also remove the user configuration:
rm -rf -- "${XDG_CONFIG_HOME:-$HOME/.config}/xray"
Uninstall the default system installation:
sudo systemctl disable --now xray 2>/dev/null || true
sudo rm -f -- /usr/local/bin/xray
sudo rm -rf -- /usr/local/share/xray
Also remove the system configuration:
sudo rm -rf -- /usr/local/etc/xray
HELP
return 0
;;
--)
shift
if (($# > 0)); then
echo "Unexpected positional argument: $1" >&2
return 2
fi
;;
-*)
echo "Unknown option: $1" >&2
return 2
;;
*)
echo "Unexpected positional argument: $1" >&2
echo "Use --data-home or --bin-dir to specify paths" >&2
return 2
;;
esac
done
case "$scope" in
user)
if ((data_home_set == 0)); then
data_home="${XDG_DATA_HOME:-$HOME/.local/share}"
fi
if ((bin_dir_set == 0)); then
bin_dir="$HOME/.local/bin"
fi
config_home="${XDG_CONFIG_HOME:-$HOME/.config}/xray"
binary_mode=700
data_dir_mode=700
config_dir_mode=700
bin_dir_mode=700
;;
system)
if ((EUID != 0)); then
echo "System installation requires root privileges" >&2
return 1
fi
if ((data_home_set == 0)); then
data_home="/usr/local/share"
fi
if ((bin_dir_set == 0)); then
bin_dir="/usr/local/bin"
fi
config_home="/usr/local/etc/xray"
binary_mode=755
data_dir_mode=755
config_dir_mode=755
bin_dir_mode=755
;;
esac
if [[ -z $data_home ]]; then
echo "Data home cannot be empty" >&2
return 2
fi
data_home="${data_home%/}"
xray_home="$data_home/xray"
if [[ -n $bin_dir ]]; then
bin_dir="${bin_dir%/}"
fi
machine="$(uname -m)"
case "$machine" in
x86_64 | amd64)
archive_arch="64"
;;
i386 | i486 | i586 | i686 | x86)
archive_arch="32"
;;
aarch64 | arm64)
archive_arch="arm64-v8a"
;;
armv8l | armv7* | armhf)
archive_arch="arm32-v7a"
;;
armv6*)
archive_arch="arm32-v6"
;;
armv5*)
archive_arch="arm32-v5"
;;
mips64el | mips64le)
archive_arch="mips64le"
;;
mips64)
archive_arch="mips64"
;;
mipsel | mipsle)
archive_arch="mips32le"
;;
mips)
archive_arch="mips32"
;;
ppc64le | powerpc64le)
archive_arch="ppc64le"
;;
ppc64 | powerpc64)
archive_arch="ppc64"
;;
riscv64)
archive_arch="riscv64"
;;
loongarch64 | loong64)
archive_arch="loong64"
;;
s390x)
archive_arch="s390x"
;;
*)
echo "Unsupported architecture: $machine" >&2
return 1
;;
esac
if ((soft_float)); then
case "$archive_arch" in
mips32 | mips32le)
source_binary="xray_softfloat"
;;
*)
echo "--soft-float is supported only on MIPS32 and MIPS32LE" >&2
return 2
;;
esac
fi
tmp="$(mktemp -d)" || {
echo "Failed to create a temporary directory" >&2
return 1
}
source_dir="$tmp/xray"
new_xray="$xray_home/.xray.new.$$"
latest_dir="$(
curl -fsSL "$base/" \
| grep -oE '/projects/xray-core\.mirror/files/v[0-9]+\.[0-9]+\.[0-9]+/' \
| sort -Vu \
| tail -n 1
)"
if [[ -z $latest_dir ]]; then
echo "Failed to find the latest Xray release" >&2
else
download_path="$(
curl -fsSL "https://sourceforge.net$latest_dir" \
| grep -oE "/projects/xray-core\.mirror/files/v[0-9]+\.[0-9]+\.[0-9]+/Xray-linux-${archive_arch}\.zip/download" \
| head -n 1
)"
if [[ -z $download_path ]]; then
echo "Failed to find Xray-linux-${archive_arch}.zip" >&2
elif ! curl -fL "https://sourceforge.net$download_path" -o "$tmp/xray.zip"; then
echo "Failed to download Xray" >&2
elif ! mkdir -p -- "$source_dir"; then
echo "Failed to create the Xray extraction directory" >&2
elif ! unzip -q "$tmp/xray.zip" -d "$source_dir"; then
echo "Failed to extract the Xray archive" >&2
elif [[ ! -f $source_dir/$source_binary ]]; then
echo "The Xray archive does not contain $source_binary" >&2
elif ! install -d -m "$data_dir_mode" "$xray_home"; then
echo "Failed to create the Xray application directory" >&2
elif ! install -d -m "$config_dir_mode" "$config_home"; then
echo "Failed to create the Xray configuration directory" >&2
elif [[ -n $bin_dir ]] && ! install -d -m "$bin_dir_mode" "$bin_dir"; then
echo "Failed to create the command directory" >&2
elif ! install -m "$binary_mode" "$source_dir/$source_binary" "$new_xray"; then
echo "Failed to stage the xray executable" >&2
else
rc=0
while IFS= read -r -d '' file; do
name="${file##*/}"
case "$name" in
xray | xray_softfloat)
continue
;;
config.json)
if [[ ! -e $config_home/$name && ! -L $config_home/$name ]]; then
install -m 600 "$file" "$config_home/$name" || rc=1
fi
;;
*)
rm -rf -- "$xray_home/$name" \
&& cp -a -- "$file" "$xray_home/$name" \
|| rc=1
;;
esac
done < <(find "$source_dir" -mindepth 1 -maxdepth 1 -print0)
if ((rc == 0)); then
mv -fT -- "$new_xray" "$xray_home/xray" || rc=1
fi
if ((rc == 0)) && [[ -n $bin_dir && $bin_dir != "$xray_home" ]]; then
ln -sfnT -- "$xray_home/xray" "$bin_dir/xray" || rc=1
fi
fi
fi
rm -rf -- "$tmp"
rm -f -- "$new_xray"
return "$rc"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment