From ee47aa26080ffda73f22da049146706cbd07bcef Mon Sep 17 00:00:00 2001 From: Kuzz007 Date: Mon, 27 Jul 2026 13:46:19 +0300 Subject: [PATCH] fix(install): preserve custom bin/ files (e.g. hand-added geoip) across updates Every reinstall/update wipes /usr/local/x-ui/ wholesale and re-extracts the release tarball, which only ships known assets (xray/mtg binaries, the bundled geoip*/geosite*.dat sets). A user-reported real incident: a hand-placed custom geoip file referenced from a routing rule via "ext::" got silently deleted on update, and Xray refused to start at all afterward ("failed to open : no such file or directory"), taking down every inbound until the file was manually restored from the user's own backup. install_x-ui now backs up the old bin/ before the wipe and restores, after extraction, only the files the fresh release doesn't provide -- bundled assets still get the newer per-release copy, nothing custom silently disappears. Verified in isolation: standard files (geoip.dat, the xray binary) end up as the fresh release's copy; a custom file absent from the release survives untouched. Co-Authored-By: Claude Sonnet 5 --- install.sh | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/install.sh b/install.sh index 57cb8e9dd..4793bbd4c 100644 --- a/install.sh +++ b/install.sh @@ -1688,6 +1688,7 @@ install_x-ui() { fi # Stop x-ui service and remove old resources + local custom_bin_backup="" if [[ -e ${xui_folder}/ ]]; then if [[ $release == "alpine" ]]; then rc-service x-ui stop @@ -1699,6 +1700,19 @@ install_x-ui() { # an inbound port with an outdated secret, silently breaking new clients. # The freshly installed panel respawns a clean mtg per inbound on start. pkill -f 'mtg-linux-[^ ]* run ' > /dev/null 2>&1 || true + + # bin/ is about to be wiped wholesale by the tar extraction below. The + # release only ships known assets (xray/mtg binaries, the bundled + # geoip*/geosite*.dat sets) -- anything else in bin/ was placed there + # by the admin (e.g. a hand-added custom geoip/geosite file referenced + # from a routing rule via "ext::") and would otherwise be + # silently deleted on every update, breaking Xray at next start with + # "failed to open : no such file or directory" for any routing + # rule that references it. + if [[ -d ${xui_folder}/bin ]]; then + custom_bin_backup=$(mktemp -d) + cp -a ${xui_folder}/bin/. "${custom_bin_backup}/" 2> /dev/null + fi rm ${xui_folder}/ -rf fi @@ -1707,6 +1721,7 @@ install_x-ui() { if [[ $? -ne 0 ]]; then rm x-ui-linux-$(arch).tar.gz -f rm -f "${xui_script_temp}" + [[ -n "${custom_bin_backup}" ]] && rm -rf "${custom_bin_backup}" echo -e "${red}Failed to extract the x-ui release archive -- the previous installation has already been removed, so the panel will not start until this is fixed; try running the installer again${plain}" exit 1 fi @@ -1715,12 +1730,34 @@ install_x-ui() { cd x-ui if [[ $? -ne 0 || ! -s x-ui ]]; then rm -f "${xui_script_temp}" + [[ -n "${custom_bin_backup}" ]] && rm -rf "${custom_bin_backup}" echo -e "${red}Extracted x-ui archive is missing the x-ui binary -- the previous installation has already been removed, so the panel will not start until this is fixed; try running the installer again${plain}" exit 1 fi chmod +x x-ui chmod +x x-ui.sh + # Restore anything from the old bin/ that the fresh release doesn't ship + # (custom geoip/geosite files, or anything else an admin hand-placed + # there) -- never overwrites a same-named file the new release provides, + # so bundled assets (geoip.dat, geoip_RU.dat, ...) still get the fresh + # per-release copy. + if [[ -n "${custom_bin_backup}" ]]; then + local restored_custom_bin=() + while IFS= read -r -d '' f; do + local rel="${f#"${custom_bin_backup}"/}" + if [[ ! -e "bin/${rel}" ]]; then + mkdir -p "bin/$(dirname "${rel}")" + cp -a "${f}" "bin/${rel}" + restored_custom_bin+=("${rel}") + fi + done < <(find "${custom_bin_backup}" -type f -print0) + rm -rf "${custom_bin_backup}" + if [[ ${#restored_custom_bin[@]} -gt 0 ]]; then + echo -e "${green}Restored custom file(s) in bin/ not shipped by this release: ${restored_custom_bin[*]}${plain}" + fi + fi + # Check the system's architecture and rename the file accordingly. # The panel binary maps GOARCH=arm to "arm32" (internal/xray/process.go), # so the Xray binary must be named xray-linux-arm32; mtg keeps plain "arm".