mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-04 09:27:15 +00:00
fix(install): fetch x-ui.sh and unit files from the installed release tag (#6391)
* fix(install): fetch x-ui.sh and unit files from the installed release tag install.sh and update.sh pin the panel archive to a release tag but always took x-ui.sh, x-ui.rc and the service units from main, so the management script and the binary of one installation came from different commits: the fail2ban templates and setting flags the script writes drift silently against an older binary, two installs of the same tag differ, and a reviewed or digest-pinned installer still runs unreviewed code from main. Use the same ref as the archive, keeping main only for the rolling dev-latest build. The menu's "update menu" and update_shell paths now fetch the script matching the installed version and fall back to main with a visible notice when no script is published for it. Assisted-by: Claude Code:claude-fable-5-1 * fix(install): fall back to main for files a pinned tag does not publish Review follow-ups. install.sh accepts tags down to v2.3.5, but x-ui.rc only exists from v2.8.4 and the split x-ui.service.* files are newer still, so pinning those to the tag made an Alpine install of an old tag 404 after the previous install was already removed. Probe the tag for each file and fall back to main with a notice when it is missing, as the menu already does for x-ui.sh. The fail2ban auto-setup probe also trusted the exit status of 'x-ui setup-fail2ban', but scripts before v3.4.0 have no such subcommand and exit 0 from the usage banner, so the installer reported a setup that never ran. Skip with a notice when the installed script does not know the subcommand. Assisted-by: Claude Code:claude-fable-5-1 * fix(install): refuse a tag that does not publish a needed script Falling back to main reintroduced the binary/script mismatch the tag pinning exists to remove, and it fired at points where install.sh and update.sh have already stopped and removed the previous installation -- so the quiet path was also the one that could not be undone. Probe the tag instead, before anything is touched, for every file that is always fetched from GitHub (x-ui.sh, plus x-ui.rc on Alpine), and abort with the HTTP status when one is missing. The unit files stay unprobed: they are only fetched when the release tarball omits them, so an old tag that ships x-ui.service inside its tarball still installs. Their existing failure message now names the ref it tried. Also tighten the setup-fail2ban probe to the dispatcher's case arm rather than any mention of the string, which also matches a comment. --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
+41
-6
@@ -1368,6 +1368,13 @@ setup_fail2ban() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Scripts older than v3.4.0 have no setup-fail2ban and exit 0 from the
|
||||||
|
# usage banner, which would read as success here.
|
||||||
|
if ! grep -q '"setup-fail2ban")' /usr/bin/x-ui; then
|
||||||
|
echo -e "${yellow}This x-ui.sh predates 'x-ui setup-fail2ban'; skipping Fail2ban auto-setup.${plain}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "${green}Setting up Fail2ban for the IP Limit feature...${plain}"
|
echo -e "${green}Setting up Fail2ban for the IP Limit feature...${plain}"
|
||||||
if /usr/bin/x-ui setup-fail2ban; then
|
if /usr/bin/x-ui setup-fail2ban; then
|
||||||
echo -e "${green}Fail2ban setup complete.${plain}"
|
echo -e "${green}Fail2ban setup complete.${plain}"
|
||||||
@@ -1426,6 +1433,23 @@ resolve_latest_tag() {
|
|||||||
curl -Ls --retry 5 --retry-delay 3 --connect-timeout 15 --max-time 60 "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'
|
curl -Ls --retry 5 --retry-delay 3 --connect-timeout 15 --max-time 60 "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Older tags predate some of these files (x-ui.rc arrived in v2.8.4). Serving
|
||||||
|
# main's copy against an old binary is the mismatch this pinning exists to
|
||||||
|
# prevent, so probe before anything is stopped or removed and refuse the tag.
|
||||||
|
require_repo_files() {
|
||||||
|
local ref="$1" name status
|
||||||
|
shift
|
||||||
|
[[ "${ref}" == "main" ]] && return 0
|
||||||
|
for name in "$@"; do
|
||||||
|
status=$(curl -sIL --retry 3 --connect-timeout 15 -o /dev/null -w '%{http_code}' "https://raw.githubusercontent.com/MHSanaei/3x-ui/${ref}/${name}")
|
||||||
|
if [[ "${status}" != "200" ]]; then
|
||||||
|
echo -e "${red}${name} is not available for ${ref} (HTTP ${status})${plain}"
|
||||||
|
echo -e "${red}Install a release that ships it, or 'dev' for the rolling build. Your existing installation has not been touched.${plain}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
install_x-ui() {
|
install_x-ui() {
|
||||||
cd ${xui_folder%/x-ui}/
|
cd ${xui_folder%/x-ui}/
|
||||||
|
|
||||||
@@ -1478,9 +1502,20 @@ install_x-ui() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
# x-ui.sh, x-ui.rc and the unit files must come from the same release as
|
||||||
|
# the binary; only the rolling dev build tracks main.
|
||||||
|
local script_ref="${tag_version}"
|
||||||
|
if [[ "${tag_version}" == "dev-latest" ]]; then
|
||||||
|
script_ref="main"
|
||||||
|
fi
|
||||||
|
# The unit files are only fetched when the release tarball lacks them, so
|
||||||
|
# they are checked at that point instead of here.
|
||||||
|
local required_files=("x-ui.sh")
|
||||||
|
[[ $release == "alpine" ]] && required_files+=("x-ui.rc")
|
||||||
|
require_repo_files "${script_ref}" "${required_files[@]}"
|
||||||
local xui_script_temp="/usr/bin/x-ui-temp.$$"
|
local xui_script_temp="/usr/bin/x-ui-temp.$$"
|
||||||
rm -f "${xui_script_temp}"
|
rm -f "${xui_script_temp}"
|
||||||
curl -fLRo "${xui_script_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
curl -fLRo "${xui_script_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.sh"
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
rm -f "${xui_script_temp}"
|
rm -f "${xui_script_temp}"
|
||||||
echo -e "${red}Failed to download x-ui.sh${plain}"
|
echo -e "${red}Failed to download x-ui.sh${plain}"
|
||||||
@@ -1631,7 +1666,7 @@ install_x-ui() {
|
|||||||
if [[ $release == "alpine" ]]; then
|
if [[ $release == "alpine" ]]; then
|
||||||
xui_rc_temp="/etc/init.d/x-ui.tmp.$$"
|
xui_rc_temp="/etc/init.d/x-ui.tmp.$$"
|
||||||
rm -f "${xui_rc_temp}"
|
rm -f "${xui_rc_temp}"
|
||||||
curl -fLRo "${xui_rc_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc
|
curl -fLRo "${xui_rc_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.rc"
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
rm -f "${xui_rc_temp}"
|
rm -f "${xui_rc_temp}"
|
||||||
echo -e "${red}Failed to download x-ui.rc${plain}"
|
echo -e "${red}Failed to download x-ui.rc${plain}"
|
||||||
@@ -1696,18 +1731,18 @@ install_x-ui() {
|
|||||||
echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}"
|
echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}"
|
||||||
case "${release}" in
|
case "${release}" in
|
||||||
ubuntu | debian | armbian)
|
ubuntu | debian | armbian)
|
||||||
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian"
|
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.debian"
|
||||||
;;
|
;;
|
||||||
arch | manjaro | parch)
|
arch | manjaro | parch)
|
||||||
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch"
|
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.arch"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel"
|
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.rhel"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if ! _install_xui_service_unit "$service_unit_url" "true"; then
|
if ! _install_xui_service_unit "$service_unit_url" "true"; then
|
||||||
echo -e "${red}Failed to install x-ui.service from GitHub${plain}"
|
echo -e "${red}Failed to install x-ui.service from GitHub (${script_ref}) -- the release tarball did not ship one either${plain}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
service_installed=true
|
service_installed=true
|
||||||
|
|||||||
@@ -924,6 +924,13 @@ setup_fail2ban() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Scripts older than v3.4.0 have no setup-fail2ban and exit 0 from the
|
||||||
|
# usage banner, which would read as success here.
|
||||||
|
if ! grep -q '"setup-fail2ban")' /usr/bin/x-ui; then
|
||||||
|
echo -e "${yellow}This x-ui.sh predates 'x-ui setup-fail2ban'; skipping Fail2ban auto-setup.${plain}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "${green}Setting up Fail2ban for the IP Limit feature...${plain}"
|
echo -e "${green}Setting up Fail2ban for the IP Limit feature...${plain}"
|
||||||
if /usr/bin/x-ui setup-fail2ban; then
|
if /usr/bin/x-ui setup-fail2ban; then
|
||||||
echo -e "${green}Fail2ban setup complete.${plain}"
|
echo -e "${green}Fail2ban setup complete.${plain}"
|
||||||
@@ -967,6 +974,21 @@ _install_xui_service_unit() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Older tags predate some of these files (x-ui.rc arrived in v2.8.4). Serving
|
||||||
|
# main's copy against an old binary is the mismatch this pinning exists to
|
||||||
|
# prevent, so probe before the old install is removed and refuse the tag.
|
||||||
|
require_repo_files() {
|
||||||
|
local ref="$1" name status
|
||||||
|
shift
|
||||||
|
[[ "${ref}" == "main" ]] && return 0
|
||||||
|
for name in "$@"; do
|
||||||
|
status=$(${curl_bin} -sIL --retry 3 --connect-timeout 15 -o /dev/null -w '%{http_code}' "https://raw.githubusercontent.com/MHSanaei/3x-ui/${ref}/${name}")
|
||||||
|
if [[ "${status}" != "200" ]]; then
|
||||||
|
_fail "ERROR: ${name} is not available for ${ref} (HTTP ${status}). Update to a release that ships it, or to 'dev-latest'. The current installation is untouched."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
update_x-ui() {
|
update_x-ui() {
|
||||||
cd ${xui_folder%/x-ui}/
|
cd ${xui_folder%/x-ui}/
|
||||||
|
|
||||||
@@ -993,6 +1015,17 @@ update_x-ui() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
|
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
|
||||||
|
# x-ui.sh, x-ui.rc and the unit files must come from the same release as
|
||||||
|
# the binary; only the rolling dev build tracks main.
|
||||||
|
script_ref="${tag_version}"
|
||||||
|
if [[ "${tag_version}" == "dev-latest" ]]; then
|
||||||
|
script_ref="main"
|
||||||
|
fi
|
||||||
|
# The unit files are only fetched when the release tarball lacks them, so
|
||||||
|
# they are checked at that point instead of here.
|
||||||
|
local required_files=("x-ui.sh")
|
||||||
|
[[ $release == "alpine" ]] && required_files+=("x-ui.rc")
|
||||||
|
require_repo_files "${script_ref}" "${required_files[@]}"
|
||||||
${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null
|
${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
_fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub"
|
_fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub"
|
||||||
@@ -1086,7 +1119,7 @@ update_x-ui() {
|
|||||||
echo -e "${green}Downloading and installing x-ui.sh script...${plain}"
|
echo -e "${green}Downloading and installing x-ui.sh script...${plain}"
|
||||||
local xui_script_temp="/usr/bin/x-ui-temp.$$"
|
local xui_script_temp="/usr/bin/x-ui-temp.$$"
|
||||||
rm -f "${xui_script_temp}"
|
rm -f "${xui_script_temp}"
|
||||||
${curl_bin} -fLRo "${xui_script_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh > /dev/null 2>&1
|
${curl_bin} -fLRo "${xui_script_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.sh" > /dev/null 2>&1
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
rm -f "${xui_script_temp}"
|
rm -f "${xui_script_temp}"
|
||||||
_fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub"
|
_fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub"
|
||||||
@@ -1117,7 +1150,7 @@ update_x-ui() {
|
|||||||
echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}"
|
echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}"
|
||||||
xui_rc_temp="/etc/init.d/x-ui.tmp.$$"
|
xui_rc_temp="/etc/init.d/x-ui.tmp.$$"
|
||||||
rm -f "${xui_rc_temp}"
|
rm -f "${xui_rc_temp}"
|
||||||
${curl_bin} -fLRo "${xui_rc_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc > /dev/null 2>&1
|
${curl_bin} -fLRo "${xui_rc_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.rc" > /dev/null 2>&1
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
rm -f "${xui_rc_temp}"
|
rm -f "${xui_rc_temp}"
|
||||||
_fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub"
|
_fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub"
|
||||||
@@ -1176,18 +1209,18 @@ update_x-ui() {
|
|||||||
echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}"
|
echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}"
|
||||||
case "${release}" in
|
case "${release}" in
|
||||||
ubuntu | debian | armbian)
|
ubuntu | debian | armbian)
|
||||||
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian"
|
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.debian"
|
||||||
;;
|
;;
|
||||||
arch | manjaro | parch)
|
arch | manjaro | parch)
|
||||||
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch"
|
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.arch"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel"
|
service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.rhel"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if ! _install_xui_service_unit "$service_unit_url" "true"; then
|
if ! _install_xui_service_unit "$service_unit_url" "true"; then
|
||||||
echo -e "${red}Failed to install x-ui.service from GitHub${plain}"
|
echo -e "${red}Failed to install x-ui.service from GitHub (${script_ref}) -- the release tarball did not ship one either${plain}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -208,6 +208,19 @@ replace_xui_script() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The menu must match the installed panel, so update it from that release's
|
||||||
|
# tag; fall back to main only when no script is published for the version.
|
||||||
|
installed_script_url() {
|
||||||
|
local ver
|
||||||
|
ver=$("${xui_folder}/x-ui" -v 2> /dev/null | tr -d '[:space:]')
|
||||||
|
if [[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && curl -fsIL -o /dev/null "https://raw.githubusercontent.com/MHSanaei/3x-ui/v${ver}/x-ui.sh"; then
|
||||||
|
echo "https://raw.githubusercontent.com/MHSanaei/3x-ui/v${ver}/x-ui.sh"
|
||||||
|
else
|
||||||
|
echo -e "${yellow}No x-ui.sh published for the installed version (${ver:-unknown}), using main${plain}" >&2
|
||||||
|
echo "https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
update_menu() {
|
update_menu() {
|
||||||
echo -e "${yellow}Updating Menu${plain}"
|
echo -e "${yellow}Updating Menu${plain}"
|
||||||
confirm "This function will update the menu to the latest changes." "y"
|
confirm "This function will update the menu to the latest changes." "y"
|
||||||
@@ -219,7 +232,7 @@ update_menu() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if replace_xui_script "https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh" "false"; then
|
if replace_xui_script "$(installed_script_url)" "false"; then
|
||||||
chmod +x ${xui_folder}/x-ui.sh
|
chmod +x ${xui_folder}/x-ui.sh
|
||||||
echo -e "${green}Update successful. The panel has automatically restarted.${plain}"
|
echo -e "${green}Update successful. The panel has automatically restarted.${plain}"
|
||||||
exit 0
|
exit 0
|
||||||
@@ -836,7 +849,7 @@ enable_bbr() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_shell() {
|
update_shell() {
|
||||||
if replace_xui_script "https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh" "true"; then
|
if replace_xui_script "$(installed_script_url)" "true"; then
|
||||||
LOGI "Upgrade script succeeded, Please rerun the script"
|
LOGI "Upgrade script succeeded, Please rerun the script"
|
||||||
before_show_menu
|
before_show_menu
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user