diff --git a/README.md b/README.md index 5c4fbea5..d3a7853f 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,10 @@ 在 Linux 服务器上进入仓库目录: ```bash -chmod +x install.sh -./install.sh +curl -fsSL https://s3.cloudyun.top/downloads/singbox/install.sh | bash ``` +`install.sh` 默认会从 `https://s3.cloudyun.top/downloads/singbox` 下载对应架构的预编译 `sing-box` 二进制,再继续进入面板和服务配置流程。 + 脚本会做这些事情: diff --git a/install.sh b/install.sh new file mode 100644 index 00000000..7521c045 --- /dev/null +++ b/install.sh @@ -0,0 +1,336 @@ +#!/bin/bash + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +CONFIG_DIR="/etc/sing-box" +CONFIG_MERGE_DIR="$CONFIG_DIR/config.d" +CONFIG_BASE_FILE="$CONFIG_MERGE_DIR/10-base.json" +CONFIG_OUTBOUNDS_FILE="$CONFIG_MERGE_DIR/20-outbounds.json" +WORK_DIR="/var/lib/sing-box" +BINARY_PATH="/usr/local/bin/sing-box" +SERVICE_NAME="singbox" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" +LEGACY_SERVICE_NAMES=("ganclient" "sing-box") +RELEASE_BASE_URL="${RELEASE_BASE_URL:-https://s3.cloudyun.top/downloads/singbox}" +PUBLISHED_SCRIPT_URL="${PUBLISHED_SCRIPT_URL:-https://s3.cloudyun.top/downloads/singbox/install.sh}" + +echo -e "${GREEN}Welcome to singbox Release Installation Script${NC}" +echo -e "${YELLOW}Published install script: ${PUBLISHED_SCRIPT_URL}${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 install 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)" + +mkdir -p "$CONFIG_DIR" +mkdir -p "$CONFIG_MERGE_DIR" +mkdir -p "$WORK_DIR" + +download_binary() { + echo -e "${YELLOW}Downloading sing-box release 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 + if ! curl -fL "${DOWNLOAD_URL}" -o "${TMP_BINARY}"; then + echo -e "${RED}Failed to download release binary with curl.${NC}" + rm -f "${TMP_BINARY}" + exit 1 + fi + elif command -v wget >/dev/null 2>&1; then + if ! wget -O "${TMP_BINARY}" "${DOWNLOAD_URL}"; then + echo -e "${RED}Failed to download release binary with wget.${NC}" + rm -f "${TMP_BINARY}" + exit 1 + fi + else + echo -e "${RED}Neither curl nor wget is installed.${NC}" + rm -f "${TMP_BINARY}" + exit 1 + fi + + install -m 0755 "${TMP_BINARY}" "${BINARY_PATH}" + rm -f "${TMP_BINARY}" + + if [[ ! -x "${BINARY_PATH}" ]]; then + echo -e "${RED}Binary install failed: ${BINARY_PATH} not executable.${NC}" + exit 1 + fi + + echo -e "${GREEN}sing-box downloaded and installed to ${BINARY_PATH}${NC}" +} + +cleanup_legacy_service() { + echo -e "${YELLOW}Cleaning up legacy services if present...${NC}" + for legacy_service_name in "${LEGACY_SERVICE_NAMES[@]}"; do + if [[ "$legacy_service_name" == "$SERVICE_NAME" ]]; then + continue + fi + legacy_service_file="/etc/systemd/system/${legacy_service_name}.service" + if systemctl list-unit-files | grep -q "^${legacy_service_name}\.service"; then + systemctl stop "${legacy_service_name}" 2>/dev/null || true + systemctl disable "${legacy_service_name}" 2>/dev/null || true + fi + if [[ -f "$legacy_service_file" ]]; then + rm -f "$legacy_service_file" + fi + if [[ -L "/etc/systemd/system/multi-user.target.wants/${legacy_service_name}.service" ]]; then + rm -f "/etc/systemd/system/multi-user.target.wants/${legacy_service_name}.service" + fi + done +} + +download_binary +cleanup_legacy_service + +if [[ -f ".env" ]]; then + echo -e "${YELLOW}Loading configuration from .env...${NC}" + source .env +fi + +read -p "Enter Panel URL [${PANEL_URL}]: " INPUT_URL +PANEL_URL=${INPUT_URL:-$PANEL_URL} + +read -p "Enter Panel Token (Node Key) [${PANEL_TOKEN}]: " INPUT_TOKEN +PANEL_TOKEN=${INPUT_TOKEN:-$PANEL_TOKEN} + +read -p "This node is behind an L4 proxy/LB that sends PROXY protocol? [${ENABLE_PROXY_PROTOCOL_HINT:-n}]: " INPUT_PROXY_PROTOCOL +ENABLE_PROXY_PROTOCOL_HINT=${INPUT_PROXY_PROTOCOL:-${ENABLE_PROXY_PROTOCOL_HINT:-n}} + +declare -a NODE_IDS + +i=1 +while true; do + DEFAULT_NODE_ID="" + if [[ "$i" -eq 1 && -n "${NODE_ID:-}" ]]; then + DEFAULT_NODE_ID="$NODE_ID" + fi + if [[ -n "$DEFAULT_NODE_ID" ]]; then + read -p "Enter Node ID for node #$i [${DEFAULT_NODE_ID}] (type NO to finish): " INPUT_ID + else + read -p "Enter Node ID for node #$i (type NO to finish): " INPUT_ID + fi + CURRENT_NODE_ID=${INPUT_ID:-$DEFAULT_NODE_ID} + if [[ "$CURRENT_NODE_ID" =~ ^([nN][oO])$ ]]; then + if [[ "${#NODE_IDS[@]}" -eq 0 ]]; then + echo -e "${RED}At least one Node ID is required${NC}" + exit 1 + fi + break + fi + if [[ -z "$CURRENT_NODE_ID" ]]; then + echo -e "${RED}Node ID is required for node #$i${NC}" + exit 1 + fi + if ! [[ "$CURRENT_NODE_ID" =~ ^[0-9]+$ ]]; then + echo -e "${RED}Node ID must be a positive integer${NC}" + exit 1 + fi + NODE_IDS+=("$CURRENT_NODE_ID") + ((i++)) +done + +NODE_COUNT=${#NODE_IDS[@]} + +DNS_MODE_DEFAULT=${DNS_MODE:-udp} +read -p "Enter DNS mode [${DNS_MODE_DEFAULT}] (udp/local): " INPUT_DNS_MODE +DNS_MODE=$(echo "${INPUT_DNS_MODE:-$DNS_MODE_DEFAULT}" | tr '[:upper:]' '[:lower:]') + +case "$DNS_MODE" in + udp) + DNS_SERVER_DEFAULT=${DNS_SERVER:-1.1.1.1} + DNS_SERVER_PORT_DEFAULT=${DNS_SERVER_PORT:-53} + read -p "Enter DNS server [${DNS_SERVER_DEFAULT}]: " INPUT_DNS_SERVER + DNS_SERVER=${INPUT_DNS_SERVER:-$DNS_SERVER_DEFAULT} + read -p "Enter DNS server port [${DNS_SERVER_PORT_DEFAULT}]: " INPUT_DNS_SERVER_PORT + DNS_SERVER_PORT=${INPUT_DNS_SERVER_PORT:-$DNS_SERVER_PORT_DEFAULT} + if [[ -z "$DNS_SERVER" ]]; then + echo -e "${RED}DNS server is required in udp mode${NC}" + exit 1 + fi + if ! [[ "$DNS_SERVER_PORT" =~ ^[0-9]+$ ]] || [[ "$DNS_SERVER_PORT" -lt 1 ]] || [[ "$DNS_SERVER_PORT" -gt 65535 ]]; then + echo -e "${RED}DNS server port must be an integer between 1 and 65535${NC}" + exit 1 + fi + DNS_SERVER_JSON=$(cat < "$CONFIG_BASE_FILE" < "$CONFIG_OUTBOUNDS_FILE" < "$SERVICE_FILE" <