优化布局

This commit is contained in:
CN-JS-HuiBai
2026-04-15 21:22:20 +08:00
parent 33c2df5485
commit 1a06f132a6
2 changed files with 339 additions and 2 deletions

View File

@@ -71,9 +71,10 @@
在 Linux 服务器上进入仓库目录: 在 Linux 服务器上进入仓库目录:
```bash ```bash
chmod +x install.sh curl -fsSL https://s3.cloudyun.top/downloads/singbox/install.sh | bash
./install.sh
``` ```
`install.sh` 默认会从 `https://s3.cloudyun.top/downloads/singbox` 下载对应架构的预编译 `sing-box` 二进制,再继续进入面板和服务配置流程。
脚本会做这些事情: 脚本会做这些事情:

336
install.sh Normal file
View File

@@ -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 <<EOF
{
"tag": "dns-upstream",
"type": "udp",
"server": "$DNS_SERVER",
"server_port": $DNS_SERVER_PORT
}
EOF
)
;;
local)
DNS_SERVER_JSON=$(cat <<EOF
{
"tag": "dns-local",
"type": "local"
}
EOF
)
;;
*)
echo -e "${RED}Unsupported DNS mode: $DNS_MODE. Supported values: udp, local${NC}"
exit 1
;;
esac
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
PANEL_URL="${PANEL_URL%/}"
SERVICE_JSON=$(cat <<EOF
{
"type": "xboard",
"panel_url": "$PANEL_URL",
"key": "$PANEL_TOKEN",
"sync_interval": "1m",
"report_interval": "1m"
EOF
)
if [[ "$NODE_COUNT" -eq 1 ]]; then
SERVICE_JSON+=$(cat <<EOF
,
"node_id": ${NODE_IDS[0]}
EOF
)
else
SERVICE_JSON+=$',
"nodes": ['
for ((i=0; i<NODE_COUNT; i++)); do
NODE_BLOCK=$(cat <<EOF
{
"node_id": ${NODE_IDS[$i]}
EOF
)
NODE_BLOCK+=$'\n }'
if [[ "$i" -gt 0 ]]; then
SERVICE_JSON+=','
fi
SERVICE_JSON+=$'\n'"$NODE_BLOCK"
done
SERVICE_JSON+=$'\n ]'
fi
SERVICE_JSON+=$'\n }'
echo -e "${YELLOW}Generating configuration...${NC}"
cat > "$CONFIG_BASE_FILE" <<EOF
{
"log": {
"level": "info",
"timestamp": true
},
"experimental": {
"cache_file": {
"enabled": true,
"path": "$WORK_DIR/cache.db"
}
},
"dns": {
"servers": [
${DNS_SERVER_JSON}
]
},
"services": [
${SERVICE_JSON}
],
"inbounds": [],
"route": {
"rules": [
{
"protocol": "dns",
"action": "hijack-dns"
}
],
"auto_detect_interface": true
}
}
EOF
cat > "$CONFIG_OUTBOUNDS_FILE" <<EOF
{
"outbounds": [
{
"type": "direct",
"tag": "direct"
}
]
}
EOF
echo -e "${GREEN}Base configuration written to $CONFIG_BASE_FILE${NC}"
echo -e "${GREEN}Outbound configuration written to $CONFIG_OUTBOUNDS_FILE${NC}"
echo -e "${YELLOW}Edit $CONFIG_OUTBOUNDS_FILE when adding custom sing-box outbounds.${NC}"
if [[ "$ENABLE_PROXY_PROTOCOL_HINT" =~ ^([yY][eE][sS]|[yY]|1|true|TRUE)$ ]]; then
echo -e "${YELLOW}Proxy Protocol deployment hint enabled.${NC}"
echo -e "${YELLOW}To make real client IP reporting work, your panel node config response must include:${NC}"
echo -e "${YELLOW} \"accept_proxy_protocol\": true${NC}"
echo -e "${YELLOW}Only enable this when the upstream L4 proxy or load balancer actually sends PROXY protocol headers.${NC}"
echo -e "${YELLOW}If clients connect directly without a PROXY header, connections will fail after enabling it on the panel.${NC}"
else
echo -e "${YELLOW}Proxy Protocol is not expected for this deployment.${NC}"
echo -e "${YELLOW}Keep panel field \"accept_proxy_protocol\" disabled or absent unless you are using an L4 proxy/LB that sends it.${NC}"
fi
echo -e "${YELLOW}Creating systemd service...${NC}"
cat > "$SERVICE_FILE" <<EOF
[Unit]
Description=singbox service
After=network.target nss-lookup.target
[Service]
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
ExecStart=$BINARY_PATH -D $WORK_DIR -C $CONFIG_MERGE_DIR run
Restart=on-failure
RestartSec=10
LimitNOFILE=infinity
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
echo -e "${GREEN}Service installed and started successfully.${NC}"
echo -e "${GREEN}Check status with: systemctl status ${SERVICE_NAME}${NC}"
echo -e "${GREEN}View logs with: journalctl -u ${SERVICE_NAME} -f${NC}"
echo -e "${GREEN}Panel config endpoint must control PROXY protocol via accept_proxy_protocol when needed.${NC}"