diff --git a/README.md b/README.md index 89ea64c3..3593a822 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ - [install.sh](./install.sh) Linux 安装脚本 +- [update.sh](./update.sh) + Linux 升级脚本 - [option/xboard.go](./option/xboard.go) `services.xboard` 配置结构 - [service/xboard/service.go](./service/xboard/service.go) @@ -76,6 +78,13 @@ curl -fsSL https://s3.cloudyun.top/downloads/singbox/install.sh | bash ``` `install.sh` 默认会从 `https://s3.cloudyun.top/downloads/singbox` 下载对应架构的预编译 `sing-box` 二进制,再继续进入面板和服务配置流程。 +升级已安装的 sing-box: + +```bash +curl -fsSL https://s3.cloudyun.top/downloads/singbox/update.sh | bash +``` +`update.sh` 会从同一发布地址下载对应架构的 `sing-box` 二进制,并自动重启已检测到的 `singbox` 或 `sing-box` 服务。 + 脚本会做这些事情: diff --git a/update.sh b/update.sh new file mode 100644 index 00000000..43489b2c --- /dev/null +++ b/update.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +BINARY_PATH="${BINARY_PATH:-/usr/local/bin/sing-box}" +RELEASE_BASE_URL="${RELEASE_BASE_URL:-https://s3.cloudyun.top/downloads/singbox}" +SERVICE_CANDIDATES=("${SERVICE_NAME:-}" "singbox" "sing-box") + +echo -e "${GREEN}sing-box binary update script${NC}" + +if [[ ${EUID} -ne 0 ]]; then + echo -e "${RED}This script must be run as root${NC}" + exit 1 +fi + +OS="$(uname -s)" +if [[ "$OS" != "Linux" ]]; then + echo -e "${RED}This update script currently supports Linux only. Current OS: ${OS}${NC}" + exit 1 +fi + +ARCH="$(uname -m)" +case "$ARCH" in + x86_64) BINARY_ARCH="amd64" ;; + aarch64|arm64) BINARY_ARCH="arm64" ;; + armv7l|armv7) BINARY_ARCH="armv7" ;; + *) + echo -e "${RED}Unsupported architecture: ${ARCH}${NC}" + exit 1 + ;; +esac + +DOWNLOAD_TARGET="${DOWNLOAD_TARGET:-linux-${BINARY_ARCH}}" +DOWNLOAD_URL="${DOWNLOAD_URL:-${RELEASE_BASE_URL}/sing-box-${DOWNLOAD_TARGET}}" +TMP_BINARY="$(mktemp)" +BACKUP_BINARY="$(mktemp)" + +cleanup() { + rm -f "${TMP_BINARY}" "${BACKUP_BINARY}" +} +trap cleanup EXIT + +detect_service_name() { + local candidate + for candidate in "${SERVICE_CANDIDATES[@]}"; do + if [[ -z "${candidate}" ]]; then + continue + fi + if systemctl list-unit-files --type=service --no-legend 2>/dev/null | awk '{print $1}' | grep -Fxq "${candidate}.service"; then + printf '%s\n' "${candidate}" + return 0 + fi + done + return 1 +} + +download_binary() { + echo -e "${YELLOW}Downloading sing-box binary...${NC}" + echo -e "${YELLOW}Target: ${DOWNLOAD_TARGET}${NC}" + echo -e "${YELLOW}URL: ${DOWNLOAD_URL}${NC}" + + if command -v curl >/dev/null 2>&1; then + curl -fL "${DOWNLOAD_URL}" -o "${TMP_BINARY}" + elif command -v wget >/dev/null 2>&1; then + wget -O "${TMP_BINARY}" "${DOWNLOAD_URL}" + else + echo -e "${RED}Neither curl nor wget is installed.${NC}" + exit 1 + fi + + chmod 0755 "${TMP_BINARY}" +} + +validate_binary() { + if ! "${TMP_BINARY}" version >/dev/null 2>&1; then + echo -e "${RED}Downloaded file is not a valid sing-box binary.${NC}" + exit 1 + fi +} + +current_version() { + if [[ -x "${BINARY_PATH}" ]]; then + "${BINARY_PATH}" version 2>/dev/null | head -n 1 || true + fi +} + +new_version() { + "${TMP_BINARY}" version 2>/dev/null | head -n 1 || true +} + +rollback() { + echo -e "${RED}Update failed, rolling back to previous binary...${NC}" + install -m 0755 "${BACKUP_BINARY}" "${BINARY_PATH}" + if [[ -n "${SERVICE_NAME_DETECTED:-}" ]]; then + systemctl restart "${SERVICE_NAME_DETECTED}" || true + fi +} + +download_binary +validate_binary + +OLD_VERSION="$(current_version)" +NEW_VERSION="$(new_version)" + +if [[ -n "${OLD_VERSION}" ]]; then + echo -e "${YELLOW}Current version: ${OLD_VERSION}${NC}" +else + echo -e "${YELLOW}Current version: not installed or unreadable${NC}" +fi +echo -e "${YELLOW}New version: ${NEW_VERSION}${NC}" + +if [[ -x "${BINARY_PATH}" ]]; then + cp -f "${BINARY_PATH}" "${BACKUP_BINARY}" +else + : > "${BACKUP_BINARY}" +fi + +install -m 0755 "${TMP_BINARY}" "${BINARY_PATH}" + +SERVICE_NAME_DETECTED="$(detect_service_name || true)" +if [[ -n "${SERVICE_NAME_DETECTED}" ]]; then + echo -e "${YELLOW}Restarting service: ${SERVICE_NAME_DETECTED}${NC}" + if ! systemctl restart "${SERVICE_NAME_DETECTED}"; then + if [[ -s "${BACKUP_BINARY}" ]]; then + rollback + fi + exit 1 + fi + echo -e "${GREEN}Service restarted successfully.${NC}" +else + echo -e "${YELLOW}No systemd service detected. Binary updated only.${NC}" +fi + +echo -e "${GREEN}sing-box has been updated successfully.${NC}" +echo -e "${GREEN}Binary: ${BINARY_PATH}${NC}" +echo -e "${GREEN}Version: $(current_version)${NC}"