#!/bin/bash # # XUI.ONE 1.5.13 Installer (bootstrap) # ----------------------------------- # Downloads the pre-patched XUI.ONE 1.5.13 release, extracts it, and runs the # bundled installer. Modeled on the midesi.net installxui.sh wrapper, but pulls # the package directly from the XUIPatch GitHub release. # # Usage (as root): # bash <(wget -qO- https://raw.githubusercontent.com//xui_installer/main/install_xui.sh) # -- or -- # chmod +x install_xui.sh && ./install_xui.sh # set -euo pipefail # --------------------------------------------------------------------------- # Config # --------------------------------------------------------------------------- RELEASE_NAME="XUI_1.5.13.zip" # Primary download source: self-hosted Gitea generic-package mirror (fast, under # our control). Override with the XUI_URL env var to point elsewhere. DEFAULT_URL="https://git.ops01.hprx.zip/api/packages/seed/generic/xui/1.5.13/${RELEASE_NAME}" URL="${XUI_URL:-$DEFAULT_URL}" # Fallback source: the upstream XUIPatch GitHub release. Tried automatically if # the primary mirror is unreachable. Override with XUI_FALLBACK_URL. FALLBACK_URL="${XUI_FALLBACK_URL:-https://github.com/xuione/XUIPatch/releases/download/main/${RELEASE_NAME}}" # Integrity check: known-good SHA-256 of XUI_1.5.13.zip. Verified before extract. # Override/clear with the XUI_SHA256 env var (set to "" to skip). EXPECTED_SHA256="${XUI_SHA256-a92e5f21a338c56190d7580f449492c970b5d4219474548ca5ec2f06bc57b2e7}" WORKDIR="${XUI_WORKDIR:-/opt/xui_install}" # License key. XUI 1.5.13 is the post-shutdown, license-free build: the patched # extensions removed all license verification and the GTAXUI license servers are # offline. The bundled installer only checks that the key is exactly 16 hex chars # (isValidLicense: len==16 and all hex) — it never phones home. So any valid hex # works; we auto-generate one unless XUI_LICENSE is provided. XUI_LICENSE="${XUI_LICENSE:-}" # Answer to the installer's "Overwrite sysctl configuration?" prompt (Y/N). # Y is recommended (sets XUI's TCP tuning + open-file limits). XUI_SYSCTL="${XUI_SYSCTL:-Y}" # Set XUI_INTERACTIVE=1 to answer the installer's prompts yourself instead of # letting this wrapper drive them non-interactively. XUI_INTERACTIVE="${XUI_INTERACTIVE:-0}" # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- c_reset=$'\033[0m'; c_blue=$'\033[1;34m'; c_green=$'\033[1;32m' c_yellow=$'\033[1;33m'; c_red=$'\033[1;31m' info() { printf '%s[*]%s %s\n' "$c_blue" "$c_reset" "$*"; } ok() { printf '%s[+]%s %s\n' "$c_green" "$c_reset" "$*"; } warn() { printf '%s[!]%s %s\n' "$c_yellow" "$c_reset" "$*"; } die() { printf '%s[x]%s %s\n' "$c_red" "$c_reset" "$*" >&2; exit 1; } # Return a valid 16-char hex license: use XUI_LICENSE if set (validated), else # generate a random one. resolve_license() { if [ -n "$XUI_LICENSE" ]; then if printf '%s' "$XUI_LICENSE" | grep -Eq '^[0-9a-fA-F]{16}$'; then printf '%s' "$XUI_LICENSE"; return 0 fi die "XUI_LICENSE must be exactly 16 hex chars (got: '$XUI_LICENSE')." fi if command -v openssl >/dev/null 2>&1; then openssl rand -hex 8 else head -c 8 /dev/urandom | od -An -tx1 | tr -d ' \n' fi } banner() { cat <<'EOF' =============================================== XUI.ONE 1.5.13 Installer =============================================== EOF } # --------------------------------------------------------------------------- # Pre-flight checks # --------------------------------------------------------------------------- preflight() { # Must be root if [ "$(id -u)" -ne 0 ]; then die "This installer must be run as root. Try: sudo su - then re-run." fi # OS / version check (XUI 1.5.13 is tested on Ubuntu 20.04 / 22.04 / 24.04) if [ -r /etc/os-release ]; then # shellcheck disable=SC1091 . /etc/os-release if [ "${ID:-}" != "ubuntu" ]; then warn "This package is tested on Ubuntu only (detected: ${PRETTY_NAME:-unknown})." warn "Continuing anyway, but the install may fail." else case "${VERSION_ID:-}" in 20.04|22.04|24.04) ok "Ubuntu ${VERSION_ID} detected (supported)." ;; *) warn "Ubuntu ${VERSION_ID:-?} is untested for this build (supported: 20.04 / 22.04 / 24.04)." ;; esac fi else warn "Could not detect OS (no /etc/os-release). Proceeding cautiously." fi # Architecture arch="$(uname -m)" [ "$arch" = "x86_64" ] || warn "Architecture is '$arch'; XUI expects x86_64." # Resource warnings (non-fatal) mem_gb=$(awk '/MemTotal/ {printf "%d", $2/1024/1024}' /proc/meminfo 2>/dev/null || echo 0) [ "${mem_gb:-0}" -ge 8 ] || warn "Only ${mem_gb}GB RAM detected; 16GB+ recommended for production." disk_gb=$(df -BG --output=avail / 2>/dev/null | tail -1 | tr -dc '0-9' || echo 0) [ "${disk_gb:-0}" -ge 20 ] || warn "Only ${disk_gb}GB free on /; 40GB+ recommended." # Re-install guard if [ -d /home/xui ]; then warn "/home/xui already exists — XUI may already be installed." printf 'Continue and re-run the installer anyway? (y/N): ' read -r ans case "$ans" in y|Y) ;; *) die "Aborted by user." ;; esac fi } # --------------------------------------------------------------------------- # Dependencies # --------------------------------------------------------------------------- ensure_deps() { local missing=() for bin in wget unzip tar; do command -v "$bin" >/dev/null 2>&1 || missing+=("$bin") done if [ "${#missing[@]}" -gt 0 ]; then info "Installing missing dependencies: ${missing[*]}" export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq "${missing[@]}" fi } # --------------------------------------------------------------------------- # Download + verify # --------------------------------------------------------------------------- fetch() { mkdir -p "$WORKDIR" cd "$WORKDIR" info "Downloading XUI release package..." info "Primary source: $URL" if ! wget --tries=3 --timeout=60 --quiet --show-progress \ --progress=bar:force:noscroll "$URL" -O "$RELEASE_NAME"; then warn "Primary source failed; trying fallback: $FALLBACK_URL" rm -f "$RELEASE_NAME" if ! wget --tries=3 --timeout=60 --quiet --show-progress \ --progress=bar:force:noscroll "$FALLBACK_URL" -O "$RELEASE_NAME"; then die "Download failed from both primary and fallback sources." fi fi [ -s "$RELEASE_NAME" ] || die "Downloaded file is empty: $RELEASE_NAME" if [ -n "$EXPECTED_SHA256" ]; then info "Verifying checksum..." actual=$(sha256sum "$RELEASE_NAME" | awk '{print $1}') [ "$actual" = "$EXPECTED_SHA256" ] \ || die "Checksum mismatch! expected=$EXPECTED_SHA256 actual=$actual" ok "Checksum verified." fi } # --------------------------------------------------------------------------- # Extract + run # --------------------------------------------------------------------------- extract_and_run() { cd "$WORKDIR" info "Extracting files..." unzip -o -q "$RELEASE_NAME" || die "Extraction failed." [ -f install ] || die "Expected 'install' script not found in package." info "Cleaning up archive..." rm -f "$RELEASE_NAME" info "Setting permissions..." chmod +x install if [ "$XUI_INTERACTIVE" = "1" ]; then cat <<'EOF' ----------------------------------------------- Handing over to the XUI installer (interactive). You will be prompted for: - your license key (any 16-char hex works) - sysctl overwrite (answer Y — recommended) ----------------------------------------------- EOF info "Starting XUI install..." ./install return fi LICENSE="$(resolve_license)" local log="$WORKDIR/install.log" cat <&1 | tee "$log" # Surface the panel setup URL the installer prints at the end. SETUP_URL="$(grep -aoE 'http://[0-9.]+/[A-Za-z0-9]+' "$log" | tail -1 || true)" } # --------------------------------------------------------------------------- # Main # --------------------------------------------------------------------------- main() { banner preflight ensure_deps fetch extract_and_run echo ok "XUI installation finished." if [ "$XUI_INTERACTIVE" != "1" ]; then printf '%s\n' "-----------------------------------------------" [ -n "${SETUP_URL:-}" ] && printf ' Panel setup URL : %s\n' "$SETUP_URL" printf ' License key : %s\n' "${LICENSE:-}" printf ' MySQL creds : %s/credentials.txt\n' "$WORKDIR" printf ' Full log : %s/install.log\n' "$WORKDIR" printf '%s\n' "-----------------------------------------------" warn "Save credentials.txt somewhere safe, then open the setup URL to finish." else info "Check ${WORKDIR}/credentials.txt and the 'Continue Setup' URL above." fi } main "$@"