#!/bin/bash # sing-box Xboard Integration Installation Script # This script automates the installation and configuration of sing-box with Xboard support. set -e # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # Configuration CONFIG_DIR="/etc/sing-box" CONFIG_FILE="$CONFIG_DIR/config.json" BINARY_PATH="/usr/local/bin/sing-box" SERVICE_FILE="/etc/systemd/system/sing-box.service" echo -e "${GREEN}Welcome to sing-box Xboard Installation Script${NC}" # Check root if [[ $EUID -ne 0 ]]; then echo -e "${RED}This script must be run as root${NC}" exit 1 fi # Detect Architecture ARCH=$(uname -m) case $ARCH in x86_64) BINARY_ARCH="amd64" ;; aarch64) BINARY_ARCH="arm64" ;; *) echo -e "${RED}Unsupported architecture: $ARCH${NC}"; exit 1 ;; esac # Prepare directories mkdir -p "$CONFIG_DIR" mkdir -p "/var/lib/sing-box" # Check and Install Go install_go() { echo -e "${YELLOW}Checking Go environment...${NC}" if command -v go >/dev/null 2>&1; then GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//' | cut -d. -f1,2) if [[ "$(printf '%s\n' "1.24" "$GO_VERSION" | sort -V | head -n1)" == "1.24" ]]; then echo -e "${GREEN}Go $GO_VERSION already installed.${NC}" return fi fi echo -e "${YELLOW}Installing Go 1.24.7...${NC}" GO_TAR="go1.24.7.linux-$BINARY_ARCH.tar.gz" curl -L "https://golang.org/dl/$GO_TAR" -o "$GO_TAR" rm -rf /usr/local/go && tar -C /usr/local -xzf "$GO_TAR" rm "$GO_TAR" # Add to PATH for current session export PATH=$PATH:/usr/local/go/bin if ! grep -q "/usr/local/go/bin" ~/.bashrc; then echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc fi echo -e "${GREEN}Go installed successfully.${NC}" } # Build sing-box build_sing_box() { echo -e "${YELLOW}Building sing-box from source...${NC}" # Check if we are in the source directory if [[ ! -f "go.mod" ]]; then echo -e "${YELLOW}Source not found in current directory. Cloning repository...${NC}" if ! command -v git >/dev/null 2>&1; then echo -e "${YELLOW}Installing git...${NC}" apt-get update && apt-get install -y git || yum install -y git fi git clone https://github.com/sagernet/sing-box.git sing-box-src cd sing-box-src else echo -e "${GREEN}Found go.mod in current directory. Building from local source.${NC}" fi # Build params from Makefile VERSION=$(git rev-parse --short HEAD 2>/dev/null || echo "custom") # Reduced tags for safer build on smaller servers TAGS="with_quic,with_utls,with_clash_api,with_gvisor" echo -e "${YELLOW}Starting compilation (this may take a few minutes)...${NC}" echo -e "${YELLOW}Note: Using -p 1 to save memory and avoid silent crashes.${NC}" # Use -o to be explicit about output location # Use -p 1 to limit parallel builds (prevent OOM spikes) # Redirect stderr to stdout to see errors clearly if ! go build -v -p 1 -trimpath \ -o "$BINARY_PATH" \ -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=$VERSION' -s -w" \ -tags "$TAGS" \ ./cmd/sing-box 2>&1; then echo -e "${RED}Compilation process failed or was terminated.${NC}" echo -e "${YELLOW}Checking system status...${NC}" free -m exit 1 fi if [[ -f "$BINARY_PATH" ]]; then chmod +x "$BINARY_PATH" echo -e "${GREEN}sing-box compiled successfully and installed to $BINARY_PATH${NC}" else echo -e "${RED}Compilation failed: binary not found!${NC}" exit 1 fi } install_go build_sing_box # Load .env if exists if [[ -f ".env" ]]; then echo -e "${YELLOW}Loading configuration from .env...${NC}" source .env fi # Interactive Prompts 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 "Enter Node Count [${NODE_COUNT:-1}]: " INPUT_COUNT NODE_COUNT=${INPUT_COUNT:-${NODE_COUNT:-1}} if ! [[ "$NODE_COUNT" =~ ^[0-9]+$ ]] || [[ "$NODE_COUNT" -lt 1 ]]; then echo -e "${RED}Node Count must be a positive integer${NC}" exit 1 fi declare -a NODE_IDS declare -a NODE_TYPES declare -a NODE_TAGS for ((i=1; i<=NODE_COUNT; i++)); do DEFAULT_NODE_ID="" DEFAULT_NODE_TYPE="${NODE_TYPE:-vless}" DEFAULT_NODE_TAG="" if [[ "$i" -eq 1 && -n "$NODE_ID" ]]; then DEFAULT_NODE_ID="$NODE_ID" fi read -p "Enter Node ID for node #$i [${DEFAULT_NODE_ID}]: " INPUT_ID CURRENT_NODE_ID=${INPUT_ID:-$DEFAULT_NODE_ID} if [[ -z "$CURRENT_NODE_ID" ]]; then echo -e "${RED}Node ID is required for node #$i${NC}" exit 1 fi read -p "Enter Node Type for node #$i [${DEFAULT_NODE_TYPE}]: " INPUT_TYPE CURRENT_NODE_TYPE=${INPUT_TYPE:-$DEFAULT_NODE_TYPE} read -p "Enter Tag for node #$i (optional) [${DEFAULT_NODE_TAG}]: " INPUT_TAG CURRENT_NODE_TAG=${INPUT_TAG:-$DEFAULT_NODE_TAG} NODE_IDS+=("$CURRENT_NODE_ID") NODE_TYPES+=("$CURRENT_NODE_TYPE") NODE_TAGS+=("$CURRENT_NODE_TAG") done # Sync time (Critical for SS 2022) echo -e "${YELLOW}Syncing system time...${NC}" timedatectl set-ntp true || true if [[ -z "$PANEL_URL" || -z "$PANEL_TOKEN" ]]; then echo -e "${RED}All fields are required!${NC}" exit 1 fi # Clean up trailing slash PANEL_URL="${PANEL_URL%/}" CONFIG_PANEL_URL=$PANEL_URL USER_PANEL_URL=$PANEL_URL SERVICE_JSON=$(cat < "$CONFIG_FILE" < "$SERVICE_FILE" <