Ctrl K
ComunidadGuías…

update.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# W-UI update script.
#
# Replaces the panel binary and the management script with a release and
# restarts the service. It asks nothing: the port, the URL path, the
# certificate, the database and the administrator are whatever this install
# already has. Only when a panel has no certificate at all is one offered,
# because a panel on plain HTTP is a panel handing its password to the wire.
#
# Usage:
#   bash <(curl -fsSL https://raw.githubusercontent.com/AbolfazlTafakori/w-ui/main/update.sh)
#   bash <(curl -fsSL .../update.sh) v1.2.0      a particular version
#   WUI_UPDATE_TAG=dev-latest bash <(curl -fsSL .../update.sh)
#                                               the rolling build of the latest commit
#
# The library of functions is the installer's own, so a download is verified
# the same way, a certificate is issued the same way, and the closing box is
# the same box.
set -eu

REPO="${WUI_REPO:-AbolfazlTafakori/w-ui}"
REF="${WUI_REF:-main}"
TAG="${1:-${WUI_UPDATE_TAG:-}}"
[[ -z "$TAG" || "$TAG" == v* || "$TAG" == dev-latest ]] || TAG="v$TAG"

[[ $EUID -eq 0 ]] || { printf '\n\033[0;31merror:\033[0m run as root (sudo bash %s)\n\n' "$0" >&2; exit 1; }
command -v curl >/dev/null 2>&1 || { printf '\n\033[0;31merror:\033[0m curl is required\n\n' >&2; exit 1; }

# Everything the installer knows, without the installer running: the same
# release resolution, checksum check, certificate issue and unit writer.
lib="$(mktemp)"
trap 'rm -f "$lib"' EXIT
curl -fsSL "https://raw.githubusercontent.com/${REPO}/${REF}/install.sh" -o "$lib" \
  || { printf '\n\033[0;31merror:\033[0m could not fetch the installer library from GitHub\n\n' >&2; exit 1; }
# shellcheck disable=SC1090
WUI_LIB_ONLY=1 source "$lib"

detect_os
printf '\n  %s%sW-UI%s  %s·%s  WireGuard · OpenVPN · OpenConnect · IKEv2 · L2TP · PPTP   %supdate%s\n' "${P:-}" "$B" "$N" "$D" "$N" "$D" "$N"
printf '  %s%s · kernel %s · %s%s\n' "$D" "$OS_NAME" "$KERNEL" "$ARCH" "$N"

[[ -f "$UNIT" || -x "$BIN_PATH" ]] || die "W-UI is not installed on this machine; run install.sh instead"

# ── which build ──────────────────────────────────────────────────────────────
step "Finding the release"
resolve_release() {
  local api json urls
  if [[ -n "$TAG" ]]; then
    api="https://api.github.com/repos/${REPO}/releases/tags/${TAG}"
  else
    api="https://api.github.com/repos/${REPO}/releases/latest"
  fi
  json="$(curl -fsSL --max-time 20 "$api" 2>/dev/null)" || return 1
  urls="$(printf '%s' "$json" | grep -o '"browser_download_url": *"[^"]*"' | sed 's/.*"browser_download_url": *"//; s/"$//')"
  RELEASE_TAG="$(printf '%s' "$json" | grep -o '"tag_name": *"[^"]*"' | head -1 | sed 's/.*"tag_name": *"//; s/"$//')"
  ASSET_URL="$(grep -E "linux[-_]${ARCH}$" <<<"$urls" | head -1)"
  SIG_URL="$(grep -E "linux[-_]${ARCH}\.sig$" <<<"$urls" | head -1)"
  # shellcheck disable=SC2034 # read by verify_download, from install.sh
  SUMS_URL="$(grep -E '/SHA256SUMS$' <<<"$urls" | head -1)"
  MENU_URL="$(grep -E '/w-ui\.sh$' <<<"$urls" | head -1)"
  [[ -n "$ASSET_URL" ]]
}
resolve_release || die "no release ${TAG:-(latest)} with a build for ${ARCH} was found"
current="$("$BIN_PATH" version 2>/dev/null || echo unknown)"
info "installed: $current"
info "available: $RELEASE_TAG"

# ── download and check ───────────────────────────────────────────────────────
step "Downloading W-UI $RELEASE_TAG"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp" "$lib"' EXIT
curl -fsSL --retry 4 --retry-all-errors --retry-delay 3 "$ASSET_URL" -o "$tmp/wui" || die "download failed"
verify_download "$tmp/wui" "${ASSET_URL##*/}"
# The signature, checked with the key baked into the panel already installed.
# A build that does not verify is not installed, whatever the checksum said.
if [[ -n "$SIG_URL" ]] && curl -fsSL --retry 4 --retry-all-errors --retry-delay 3 "$SIG_URL" -o "$tmp/wui.sig" 2>/dev/null; then
  # 0: signed by this project's key. 2: it is not, and it is not installed.
  # Anything else: the installed panel cannot check (no key baked in, or a
  # panel from before this command existed) -- said, and carried on with
  # the checksum alone.
  set +e
  out="$("$BIN_PATH" verify "$tmp/wui" "$tmp/wui.sig" 2>&1)"
  rc=$?
  set -e
  # A panel from before this command existed does not know "verify" and
  # tries to start instead; only an answer that begins "verify:" is one.
  if [[ $rc -eq 0 && "$out" == *"signature ok"* ]]; then
    ok "signature verified"
  elif [[ $rc -eq 2 && "$out" == *"verify:"* ]]; then
    die "signature check failed: the download is not a build this project signed"
  else
    warn "the installed panel cannot check signatures; the checksum is what was verified"
  fi
else
  warn "the release carries no signature for this build"
fi

# ── install ──────────────────────────────────────────────────────────────────
step "Installing"
# A release from before 3.0 has no L2TP agent. A tunnel this one carries is
# taken down by it first, while it is still here to do it; the panel is
# stopped for that, or it would describe the tunnel again, and the restart
# below brings it back.
if release_before_l2tp "$RELEASE_TAG" && [[ -f /etc/systemd/system/wui-l2tp.service || -f "$DATA_DIR/l2tp/state.json" ]]; then
  if have_systemd; then systemctl stop wui.service || true; fi
  remove_l2tp_agent
fi
# Nor a firewall helper: its unit runs `wui firewall-sync`, and an older
# binary given a subcommand it does not know starts the whole panel instead
# -- a second one, as root, at the next boot.
if release_before_l2tp "$RELEASE_TAG"; then
  remove_firewall_helper
fi
install -m 0755 "$tmp/wui" "$BIN_PATH.new" && mv -f "$BIN_PATH.new" "$BIN_PATH"
ok "$BIN_PATH"
if [[ -n "${MENU_URL:-}" ]] && curl -fsSL --retry 4 --retry-all-errors --retry-delay 3 "$MENU_URL" -o "$tmp/w-ui.sh"; then
  sed 's/\r$//' "$tmp/w-ui.sh" > "$tmp/w-ui.clean" && install -m 0755 "$tmp/w-ui.clean" "$MENU_PATH"
  ok "$MENU_PATH"
else
  warn "could not refresh the w-ui command; the one installed stays"
fi
# The helper that lets the panel install its own updates from here on. A
# server installed before it existed gets it now.
write_update_helper
# L2TP/IPsec, installed and left off, and the agent that runs it once a
# tunnel is made -- for a release that has one.
if ! release_before_l2tp "$RELEASE_TAG"; then
  install_l2tp
  install_proxy_cores
  write_l2tp_agent
fi
if have_systemd; then
  systemctl daemon-reload
  systemctl restart wui.service
  for _ in $(seq 1 20); do systemctl is-active --quiet wui.service && break; sleep 0.5; done
  systemctl is-active --quiet wui.service || die "the panel did not come back — see: journalctl -u wui -n 50 --no-pager"
  ok "wui.service restarted"
fi

# ── after the update ─────────────────────────────────────────────────────────
# What the panel answers on, read back; a missing URL path or certificate is
# put right, since neither is something a panel should be without.
step "Settings"
read_existing
# The panel's own environment -- the unit's lines, then db.env and wui.env --
# so what is read back is what the service runs with, not the defaults.
env_of() {
  (
    set -a
    # shellcheck disable=SC2034 # exported by set -a, for the panel binary
    WUI_DATA_DIR="$DATA_DIR"
    # shellcheck disable=SC2163 # each word is NAME=value, exported as such
    for kv in $(grep -oE 'WUI_[A-Z_]+=[^ ]+' "$UNIT" 2>/dev/null); do export "$kv"; done
    [[ -r "$CONF_DIR/db.env" ]] && . "$CONF_DIR/db.env"
    [[ -r "$CONF_DIR/wui.env" ]] && . "$CONF_DIR/wui.env"
    set +a
    "$BIN_PATH" "$@"
  )
}
env_of setting show 2>/dev/null | sed 's/^/    /' || true

# A certificate set from the menu lives in the database, not the unit; what
# the panel actually serves with is what setting show reports.
if [[ -z "$TLS_CERT" || -z "$TLS_KEY" ]]; then
  c="$(env_of setting show 2>/dev/null | sed -n 's/^cert: //p')"
  k="$(env_of setting show 2>/dev/null | sed -n 's/^key: //p')"
  if [[ -s "$c" && -s "$k" ]]; then TLS_CERT="$c"; TLS_KEY="$k"; TLS_MODE=files; fi
fi
base="$(env_of setting show 2>/dev/null | sed -n 's/^basePath: //p' | tr -d '/')"
[[ -n "$base" ]] || base="$BASE_PATH"
if (( ${#base} < 4 )); then
  BASE_PATH="$(gen_string 18)"
  warn "the URL path is missing or too short; a new one is set: /$BASE_PATH/"
  env_of setting set --base-path "/$BASE_PATH/" >/dev/null 2>&1 || true
  have_systemd && systemctl restart wui.service
else
  BASE_PATH="$base"
fi

if [[ -z "$TLS_CERT" || -z "$TLS_KEY" ]]; then
  printf '\n  %s═══════════════════════════════════════════%s\n' "$R" "$N"
  printf '  %s      ⚠ NO SSL CERTIFICATE DETECTED ⚠     %s\n' "$R" "$N"
  printf '  %s═══════════════════════════════════════════%s\n' "$R" "$N"
  printf '  %sFor security, a certificate is strongly recommended for every panel.%s\n' "$Y" "$N"
  printf "  %sLet's Encrypt supports both domains and IP addresses.%s\n\n" "$Y" "$N"
  open_tty
  if [[ "$INTERACTIVE" == 1 ]]; then
    ask_tls
    setup_tls
    if [[ -n "$TLS_CERT" && -n "$TLS_KEY" ]]; then
      write_unit
      have_systemd && systemctl restart wui.service
      # The subscription service on its own port gets the same certificate.
      env_of setting set --sub-cert "$TLS_CERT" --sub-key "$TLS_KEY" >/dev/null 2>&1 || true
    fi
  else
    warn "no terminal to ask on; get one later with: w-ui → 20"
  fi
else
  ok "certificate: $TLS_CERT"
fi

ip="$(public_ip 2>/dev/null || true)"
host="${ip:-<this server>}"
case "$TLS_MODE" in
  acme) [[ -n "${ACME_DOMAIN:-}" ]] && host="$ACME_DOMAIN" ;;
  files) [[ -n "${TLS_DOMAIN:-}" ]] && host="$TLS_DOMAIN" ;;
esac
if [[ -n "$TLS_CERT" ]]; then
  # The folder a certificate lives in is named for what it was issued to.
  n="$(basename "$(dirname "$TLS_CERT")")"
  [[ "$n" =~ ^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ || "$n" =~ ^[0-9.]+$ ]] && host="$n"
  scheme=https
else
  scheme=http
fi
printf '\n  %s═══════════════════════════════════════════%s\n' "$G" "$N"
printf '  %s     Panel Access Information              %s\n' "$G" "$N"
printf '  %s═══════════════════════════════════════════%s\n' "$G" "$N"
printf '  %sAccess URL:  %s://%s:%s/%s/%s\n' "$G" "$scheme" "$host" "$PANEL_PORT" "$BASE_PATH" "$N"
printf '  %s═══════════════════════════════════════════%s\n' "$G" "$N"

setup_fail2ban
printf '\n'
usage_box updating