feat: initial commit of clean multi-protocol singbox core script

This commit is contained in:
jocay
2026-09-27 13:11:24 +08:00
commit 34565faa6b
10 changed files with 1475 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
* text=auto eol=lf
*.sh text eol=lf
*.md text eol=lf
+3
View File
@@ -0,0 +1,3 @@
.DS_Store
*.log
*.tmp
+115
View File
@@ -0,0 +1,115 @@
# Sing-box Core (Clean 全协议版)
基于官方原版架构重构的 Sing-box 极简核心部署与管理工具。彻底剥离原项目中 4400+ 行的臃肿代码与高危隐患,专注纯净代理服务部署与标准化多平台订阅生成。
---
## 🌟 支持协议全景
| 协议类型 | 底层传输 / 认证 | 端口默认 | 特点与适用场景 | 免域名/证书 |
| :--- | :--- | :--- | :--- | :--- |
| **VLESS-Reality** | TCP + Vision + Reality | `443/tcp` | 顶级伪装防封锁,主流科学上网首选 | **是** (借用顶级站点 SNI) |
| **Hysteria 2** | UDP + QUIC (ALPN: h3) | `8443/udp` | 恶劣网络丢包环境下极速救星,自带拥塞控制 | **是** (内置自签 EC 证书) |
| **TUIC v5** | UDP + QUIC + BBR | `9443/udp` | 低延迟双向原生 UDP 转发,移动设备表现优异 | **是** (内置自签 EC 证书) |
| **VMess-WS** | TCP + WebSocket | `8080/tcp` | 经典通用传输,可结合 CDN 反代 | **是** (纯净明文/本地反代) |
| **AnyTLS** | TCP + TLS (Padding Scheme) | `10443/tcp`| Sing-box 原生 TLS 高效协议 | **是** (内置自签 EC 证书) |
---
## 📁 模块化目录结构
```text
sb-core/
├── sb.sh # 主程序入口(交互式菜单与 CLI 自动化指令)
├── README.md # 本项目使用与开发文档
└── lib/
├── env.sh # 环境变量、常量路径定义、权限检查与终端彩色日志
├── system.sh # 系统架构检测 (amd64/arm64)、依赖安装、安全防火墙放行
├── cert.sh # ECDSA (P-256) 现代自签证书自动化生成与管理
├── singbox.sh # Sing-box 官方正版二进制下载、校验与 Systemd 守护服务
├── config.sh # 多协议配置生成引擎与 Sing-box 原生语法校验
└── info.sh # 多协议分享链接、聚合 Base64 订阅与客户端配置生成
```
---
## 🚀 快速使用
### 1. 部署与运行
在 Linux VPS(Ubuntu / Debian / CentOS / Rocky 等)以 `root` 权限执行:
```bash
git clone https://git.draws.qzz.io/jocay/singbox-script.git
cd singbox-script
chmod +x sb.sh lib/*.sh
./sb.sh
```
首次运行后会自动建立全局快捷指令,之后在系统任意目录输入 `sb` 即可调出菜单。
### 2. 交互式菜单功能
```text
================================================================
Sing-box 现代化核心管理工具 (全协议纯净版)
================================================================
核心状态: ● 运行中
----------------------------------------------------------------
1) 一键安装【五协议共存套件】 (VLESS+Hy2+TUIC+VMess+AnyTLS)
2) 自选单协议独立安装
3) 查看当前已装节点信息与分享链接
4) 启动服务
5) 停止服务
6) 重启服务
7) 查看实时日志
8) 彻底干净卸载
0) 退出
================================================================
```
### 3. CLI 命令行无交互快捷调用(适合自动化部署)
```bash
# 一键安装五协议共存套件(使用默认端口)
sb install all
# 自定义指定各协议端口安装五协议
sb install all [vless端口] [hy2端口] [tuic端口] [vmess端口] [anytls端口]
# 单独安装指定协议
sb install vless [端口] [伪装SNI] # 例如: sb install vless 443 www.apple.com
sb install hy2 [端口] # 例如: sb install hy2 8443
sb install tuic [端口] # 例如: sb install tuic 9443
sb install vmess [端口] # 例如: sb install vmess 8080
sb install anytls [端口] # 例如: sb install anytls 10443
# 常用运维
sb info # 查看当前所有节点、通用分享链接及订阅内容
sb status # 查看服务运行状态
sb restart # 重启服务
sb stop # 停止服务
sb start # 启动服务
sb log # 查看实时内核运行日志 (Ctrl+C 退出)
sb uninstall # 彻底干净卸载
```
---
## 📱 客户端配置与导出文件
执行 `sb info` 或安装完成后,所有客户端所需格式都会保存在 `/etc/sing-box/`:
1. **单协议标准通用链接**:
- `vless://...` (VLESS-Reality)
- `hy2://...` (Hysteria 2)
- `tuic://...` (TUIC v5)
- `vmess://...` (VMess-WS)
- `anytls://...` (AnyTLS)
2. **聚合 Base64 订阅内容 (`/etc/sing-box/sub_base64.txt`)**:
- 包含当前已部署的所有协议节点,可直接整段复制粘贴到客户端(v2rayN、Nekobox、Shadowrocket、Quantumult X 等)作为批量导入或订阅。
3. **Clash-Meta / Mihomo 配置文件 (`/etc/sing-box/clash_meta.yaml`)**:
- 已经按 Mihomo 规范写好各协议代理节点,直接复制进客户端配置的 `proxies` 组即可。
4. **Sing-box 官方客户端出站配置 (`/etc/sing-box/singbox_client.json`)**:
- 包含完整的 `outbounds` 片段,直接贴入官方客户端即可。
5. **完整明文信息汇总 (`/etc/sing-box/node_info.txt`)**。
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# ==============================================================================
# 模块:TLS 证书自动化生成与管理 (支持 ECDSA 现代自签与自定义证书)
# ==============================================================================
CERT_DIR="${INSTALL_DIR}/cert"
CERT_FILE="${CERT_DIR}/cert.pem"
KEY_FILE="${CERT_DIR}/private.key"
# 生成现代椭圆曲线 (prime256v1) 自签名证书
generate_self_signed_cert() {
local sni="${1:-www.bing.com}"
mkdir -p "${CERT_DIR}"
# 如果证书已存在且有效期超过30天,直接复用
if [[ -f "${CERT_FILE}" && -f "${KEY_FILE}" ]]; then
if openssl x509 -checkend 2592000 -noout -in "${CERT_FILE}" >/dev/null 2>&1; then
log_info "现有 TLS 证书有效,直接复用: ${CERT_FILE}"
return 0
fi
fi
log_info "正在为伪装域名 [${sni}] 自动化生成 ECDSA (P-256) 高性能自签名 TLS 证书..."
# 生成 EC 私钥
openssl ecparam -name prime256v1 -genkey -noout -out "${KEY_FILE}" 2>/dev/null
# 生成 10 年有效期的自签名证书
openssl req -new -x509 -days 3650 \
-key "${KEY_FILE}" \
-out "${CERT_FILE}" \
-subj "/CN=${sni}" \
-addext "subjectAltName=DNS:${sni}" 2>/dev/null || \
openssl req -new -x509 -days 3650 \
-key "${KEY_FILE}" \
-out "${CERT_FILE}" \
-subj "/CN=${sni}" 2>/dev/null
chmod 600 "${KEY_FILE}" "${CERT_FILE}"
if [[ ! -s "${CERT_FILE}" || ! -s "${KEY_FILE}" ]]; then
log_error "TLS 自签名证书生成失败,请检查 openssl 环境!"
return 1
fi
log_success "TLS 证书自动化生成完成!"
return 0
}
+339
View File
@@ -0,0 +1,339 @@
#!/usr/bin/env bash
# ==============================================================================
# 模块:多协议配置生成器 (VLESS-Reality / Hysteria2 / TUIC / VMess / AnyTLS)
# ==============================================================================
# 获取或生成统一 UUID
get_or_create_uuid() {
local uuid="${1:-}"
if [[ -z "$uuid" ]]; then
if command -v "${BIN_PATH}" >/dev/null 2>&1; then
uuid=$("${BIN_PATH}" generate uuid 2>/dev/null)
fi
if [[ -z "$uuid" && -f /proc/sys/kernel/random/uuid ]]; then
uuid=$(cat /proc/sys/kernel/random/uuid)
fi
if [[ -z "$uuid" ]]; then
uuid=$(openssl rand -hex 16 | sed -E 's/(.{8})(.{4})(.{4})(.{4})(.{12})/\1-\2-\3-\4-\5/')
fi
fi
echo "$uuid"
}
# 1. 组装 VLESS-Reality 入站 JSON
build_vless_inbound() {
local port="$1"
local uuid="$2"
local sni="$3"
local priv_key="$4"
local short_id="$5"
cat <<EOF
{
"type": "vless",
"tag": "vless-in",
"listen": "::",
"listen_port": ${port},
"sniff": true,
"sniff_override_destination": true,
"users": [
{
"uuid": "${uuid}",
"flow": "xtls-rprx-vision"
}
],
"tls": {
"enabled": true,
"server_name": "${sni}",
"reality": {
"enabled": true,
"handshake": {
"server": "${sni}",
"server_port": 443
},
"private_key": "${priv_key}",
"short_id": [
"${short_id}"
]
}
}
}
EOF
}
# 2. 组装 Hysteria 2 入站 JSON
build_hy2_inbound() {
local port="$1"
local password="$2"
cat <<EOF
{
"type": "hysteria2",
"tag": "hy2-in",
"listen": "::",
"listen_port": ${port},
"sniff": true,
"sniff_override_destination": true,
"users": [
{
"password": "${password}"
}
],
"ignore_client_bandwidth": false,
"tls": {
"enabled": true,
"alpn": [
"h3"
],
"certificate_path": "${CERT_FILE}",
"key_path": "${KEY_FILE}"
}
}
EOF
}
# 3. 组装 TUIC v5 入站 JSON
build_tuic_inbound() {
local port="$1"
local uuid="$2"
cat <<EOF
{
"type": "tuic",
"tag": "tuic-in",
"listen": "::",
"listen_port": ${port},
"sniff": true,
"sniff_override_destination": true,
"users": [
{
"uuid": "${uuid}",
"password": "${uuid}"
}
],
"congestion_control": "bbr",
"tls": {
"enabled": true,
"alpn": [
"h3"
],
"certificate_path": "${CERT_FILE}",
"key_path": "${KEY_FILE}"
}
}
EOF
}
# 4. 组装 VMess-WS 入站 JSON
build_vmess_inbound() {
local port="$1"
local uuid="$2"
cat <<EOF
{
"type": "vmess",
"tag": "vmess-in",
"listen": "::",
"listen_port": ${port},
"sniff": true,
"sniff_override_destination": true,
"users": [
{
"uuid": "${uuid}",
"alterId": 0
}
],
"transport": {
"type": "ws",
"path": "/${uuid}-vm",
"max_early_data": 2048,
"early_data_header_name": "Sec-WebSocket-Protocol"
}
}
EOF
}
# 5. 组装 AnyTLS 入站 JSON
build_anytls_inbound() {
local port="$1"
local password="$2"
cat <<EOF
{
"type": "anytls",
"tag": "anytls-in",
"listen": "::",
"listen_port": ${port},
"users": [
{
"password": "${password}"
}
],
"padding_scheme": [],
"tls": {
"enabled": true,
"certificate_path": "${CERT_FILE}",
"key_path": "${KEY_FILE}"
}
}
EOF
}
# 组合入站并生成最终完整服务配置与元数据
generate_suite_config() {
local mode="$1" # all | vless | hy2 | tuic | vmess | anytls
shift
local uuid
uuid=$(get_or_create_uuid)
local reality_sni="www.apple.com"
local cert_sni="www.bing.com"
mkdir -p "${INSTALL_DIR}"
# 如涉及需证书的协议,预先生成自签证书
if [[ "$mode" == "all" || "$mode" == "hy2" || "$mode" == "tuic" || "$mode" == "anytls" ]]; then
generate_self_signed_cert "$cert_sni" || return 1
fi
# 如涉及 Reality,预先生成密钥对
local priv_key="" pub_key="" short_id=""
if [[ "$mode" == "all" || "$mode" == "vless" ]]; then
local keypair
keypair=$("${BIN_PATH}" generate reality-keypair)
priv_key=$(echo "$keypair" | awk '/PrivateKey/ {print $2}' | tr -d ' "\r\n')
pub_key=$(echo "$keypair" | awk '/PublicKey/ {print $2}' | tr -d ' "\r\n')
short_id=$("${BIN_PATH}" generate rand --hex 4 2>/dev/null || openssl rand -hex 4)
short_id=$(echo "$short_id" | tr -d ' "\r\n')
fi
local inbounds_arr=()
local meta_protocols="{}"
case "$mode" in
all)
local p_vless="${1:-443}"
local p_hy2="${2:-8443}"
local p_tuic="${3:-9443}"
local p_vmess="${4:-8080}"
local p_anytls="${5:-10443}"
inbounds_arr+=("$(build_vless_inbound "$p_vless" "$uuid" "$reality_sni" "$priv_key" "$short_id")")
inbounds_arr+=("$(build_hy2_inbound "$p_hy2" "$uuid")")
inbounds_arr+=("$(build_tuic_inbound "$p_tuic" "$uuid")")
inbounds_arr+=("$(build_vmess_inbound "$p_vmess" "$uuid")")
inbounds_arr+=("$(build_anytls_inbound "$p_anytls" "$uuid")")
meta_protocols=$(cat <<EOF
{
"vless_reality": { "enabled": true, "port": ${p_vless}, "sni": "${reality_sni}", "public_key": "${pub_key}", "short_id": "${short_id}" },
"hysteria2": { "enabled": true, "port": ${p_hy2}, "sni": "${cert_sni}" },
"tuic": { "enabled": true, "port": ${p_tuic}, "sni": "${cert_sni}" },
"vmess_ws": { "enabled": true, "port": ${p_vmess}, "path": "/${uuid}-vm" },
"anytls": { "enabled": true, "port": ${p_anytls}, "sni": "${cert_sni}" }
}
EOF
)
;;
vless)
local port="${1:-443}"
local custom_sni="${2:-$reality_sni}"
inbounds_arr+=("$(build_vless_inbound "$port" "$uuid" "$custom_sni" "$priv_key" "$short_id")")
meta_protocols=$(cat <<EOF
{
"vless_reality": { "enabled": true, "port": ${port}, "sni": "${custom_sni}", "public_key": "${pub_key}", "short_id": "${short_id}" }
}
EOF
)
;;
hy2)
local port="${1:-8443}"
inbounds_arr+=("$(build_hy2_inbound "$port" "$uuid")")
meta_protocols=$(cat <<EOF
{
"hysteria2": { "enabled": true, "port": ${port}, "sni": "${cert_sni}" }
}
EOF
)
;;
tuic)
local port="${1:-9443}"
inbounds_arr+=("$(build_tuic_inbound "$port" "$uuid")")
meta_protocols=$(cat <<EOF
{
"tuic": { "enabled": true, "port": ${port}, "sni": "${cert_sni}" }
}
EOF
)
;;
vmess)
local port="${1:-8080}"
inbounds_arr+=("$(build_vmess_inbound "$port" "$uuid")")
meta_protocols=$(cat <<EOF
{
"vmess_ws": { "enabled": true, "port": ${port}, "path": "/${uuid}-vm" }
}
EOF
)
;;
anytls)
local port="${1:-10443}"
inbounds_arr+=("$(build_anytls_inbound "$port" "$uuid")")
meta_protocols=$(cat <<EOF
{
"anytls": { "enabled": true, "port": ${port}, "sni": "${cert_sni}" }
}
EOF
)
;;
esac
# 拼装 inbounds 数组逗号
local inbounds_joined
inbounds_joined=$(IFS=,; echo "${inbounds_arr[*]}")
# 写入最终 config.json
cat > "${CONFIG_FILE}" <<EOF
{
"log": {
"disabled": false,
"level": "info",
"timestamp": true
},
"inbounds": [
${inbounds_joined}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
}
]
}
EOF
# 原生语法校验
if ! "${BIN_PATH}" check -c "${CONFIG_FILE}" >/dev/null 2>&1; then
log_error "生成的配置文件未能通过 Sing-box 语法检测!请检查端口是否有冲突或参数错误。"
return 1
fi
# 写入持久化元数据
cat > "${META_FILE}" <<EOF
{
"mode": "${mode}",
"uuid": "${uuid}",
"protocols": ${meta_protocols},
"updated_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
EOF
chmod 600 "${CONFIG_FILE}" "${META_FILE}"
log_success "Sing-box 核心配置部署成功,语法校验通过!"
return 0
}
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# ==============================================================================
# 模块:基础环境、常量定义与通用日志工具
# ==============================================================================
# 颜色代码
CLR_RED="\033[31m"
CLR_GREEN="\033[32m"
CLR_YELLOW="\033[33m"
CLR_BLUE="\033[36m"
CLR_PURPLE="\033[35m"
CLR_RESET="\033[0m"
CLR_BOLD="\033[1m"
# 路径常量
INSTALL_DIR="/etc/sing-box"
CONFIG_FILE="${INSTALL_DIR}/config.json"
META_FILE="${INSTALL_DIR}/meta.json"
BIN_DIR="/usr/local/bin"
BIN_PATH="${BIN_DIR}/sing-box"
SERVICE_NAME="sing-box"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
SCRIPT_LINK="${BIN_DIR}/sb"
# 日志输出函数
log_info() {
echo -e "${CLR_BLUE}[INFO]${CLR_RESET} $1"
}
log_success() {
echo -e "${CLR_GREEN}[SUCCESS]${CLR_RESET} $1"
}
log_warn() {
echo -e "${CLR_YELLOW}[WARN]${CLR_RESET} $1"
}
log_error() {
echo -e "${CLR_RED}[ERROR]${CLR_RESET} $1" >&2
}
# 权限校验:必须以 root 权限运行
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "本脚本需要 root 权限,请使用 sudo 或切换至 root 用户执行!"
exit 1
fi
}
+328
View File
@@ -0,0 +1,328 @@
#!/usr/bin/env bash
# ==============================================================================
# 模块:多协议分享链接生成、聚合订阅与多客户端配置导出
# ==============================================================================
show_node_info() {
if [[ ! -f "${META_FILE}" ]]; then
log_error "未检测到已安装的节点配置元数据,请先执行安装!"
return 1
fi
local uuid server_ip
uuid=$(jq -r '.uuid' "${META_FILE}")
server_ip=$(get_public_ip)
local share_links=()
local clash_proxies=""
local sb_outbounds=()
local summary_text=""
# --------------------------------------------------------------------------
# 1. VLESS-Reality
# --------------------------------------------------------------------------
if [[ $(jq -r '.protocols.vless_reality.enabled // false' "${META_FILE}") == "true" ]]; then
local vl_port vl_sni vl_pub vl_sid vl_name vl_link
vl_port=$(jq -r '.protocols.vless_reality.port' "${META_FILE}")
vl_sni=$(jq -r '.protocols.vless_reality.sni' "${META_FILE}")
vl_pub=$(jq -r '.protocols.vless_reality.public_key' "${META_FILE}")
vl_sid=$(jq -r '.protocols.vless_reality.short_id' "${META_FILE}")
vl_name="VLESS-Reality-${server_ip}"
vl_link="vless://${uuid}@${server_ip}:${vl_port}?security=reality&encryption=none&pbk=${vl_pub}&headerType=none&fp=chrome&type=tcp&flow=xtls-rprx-vision&sni=${vl_sni}&sid=${vl_sid}#${vl_name}"
share_links+=("$vl_link")
summary_text+="[VLESS-Reality-Vision] 端口: ${vl_port}/tcp | SNI: ${vl_sni} | PublicKey: ${vl_pub} | ShortID: ${vl_sid}\n${vl_link}\n\n"
clash_proxies+=$(cat <<EOF
- name: "${vl_name}"
type: vless
server: ${server_ip}
port: ${vl_port}
uuid: ${uuid}
network: tcp
tls: true
udp: true
flow: xtls-rprx-vision
servername: ${vl_sni}
reality-opts:
public-key: ${vl_pub}
short-id: ${vl_sid}
client-fingerprint: chrome
EOF
)
sb_outbounds+=("$(cat <<EOF
{
"type": "vless",
"tag": "${vl_name}",
"server": "${server_ip}",
"server_port": ${vl_port},
"uuid": "${uuid}",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "${vl_sni}",
"utls": { "enabled": true, "fingerprint": "chrome" },
"reality": { "enabled": true, "public_key": "${vl_pub}", "short_id": "${vl_sid}" }
},
"packet_encoding": "xudp"
}
EOF
)")
fi
# --------------------------------------------------------------------------
# 2. Hysteria 2
# --------------------------------------------------------------------------
if [[ $(jq -r '.protocols.hysteria2.enabled // false' "${META_FILE}") == "true" ]]; then
local hy_port hy_sni hy_name hy_link
hy_port=$(jq -r '.protocols.hysteria2.port' "${META_FILE}")
hy_sni=$(jq -r '.protocols.hysteria2.sni' "${META_FILE}")
hy_name="Hysteria2-${server_ip}"
hy_link="hy2://${uuid}@${server_ip}:${hy_port}?insecure=1&sni=${hy_sni}#${hy_name}"
share_links+=("$hy_link")
summary_text+="[Hysteria-2] 端口: ${hy_port}/udp | SNI: ${hy_sni} | 密码: ${uuid}\n${hy_link}\n\n"
clash_proxies+=$(cat <<EOF
- name: "${hy_name}"
type: hysteria2
server: ${server_ip}
port: ${hy_port}
password: ${uuid}
sni: ${hy_sni}
skip-cert-verify: true
alpn:
- h3
EOF
)
sb_outbounds+=("$(cat <<EOF
{
"type": "hysteria2",
"tag": "${hy_name}",
"server": "${server_ip}",
"server_port": ${hy_port},
"password": "${uuid}",
"tls": {
"enabled": true,
"server_name": "${hy_sni}",
"insecure": true,
"alpn": ["h3"]
}
}
EOF
)")
fi
# --------------------------------------------------------------------------
# 3. TUIC v5
# --------------------------------------------------------------------------
if [[ $(jq -r '.protocols.tuic.enabled // false' "${META_FILE}") == "true" ]]; then
local tu_port tu_sni tu_name tu_link
tu_port=$(jq -r '.protocols.tuic.port' "${META_FILE}")
tu_sni=$(jq -r '.protocols.tuic.sni' "${META_FILE}")
tu_name="TUIC5-${server_ip}"
tu_link="tuic://${uuid}:${uuid}@${server_ip}:${tu_port}?congestion_control=bbr&alpn=h3&sni=${tu_sni}&allow_insecure=1#${tu_name}"
share_links+=("$tu_link")
summary_text+="[TUIC-v5] 端口: ${tu_port}/udp | SNI: ${tu_sni} | UUID/密码: ${uuid}\n${tu_link}\n\n"
clash_proxies+=$(cat <<EOF
- name: "${tu_name}"
type: tuic
server: ${server_ip}
port: ${tu_port}
uuid: ${uuid}
password: ${uuid}
congestion-controller: bbr
skip-cert-verify: true
sni: ${tu_sni}
alpn:
- h3
EOF
)
sb_outbounds+=("$(cat <<EOF
{
"type": "tuic",
"tag": "${tu_name}",
"server": "${server_ip}",
"server_port": ${tu_port},
"uuid": "${uuid}",
"password": "${uuid}",
"congestion_control": "bbr",
"udp_relay_mode": "native",
"tls": {
"enabled": true,
"server_name": "${tu_sni}",
"insecure": true,
"alpn": ["h3"]
}
}
EOF
)")
fi
# --------------------------------------------------------------------------
# 4. VMess-WS
# --------------------------------------------------------------------------
if [[ $(jq -r '.protocols.vmess_ws.enabled // false' "${META_FILE}") == "true" ]]; then
local vm_port vm_path vm_name vm_json vm_b64 vm_link
vm_port=$(jq -r '.protocols.vmess_ws.port' "${META_FILE}")
vm_path=$(jq -r '.protocols.vmess_ws.path' "${META_FILE}")
vm_name="VMess-WS-${server_ip}"
vm_json="{\"v\":\"2\",\"ps\":\"${vm_name}\",\"add\":\"${server_ip}\",\"port\":\"${vm_port}\",\"id\":\"${uuid}\",\"aid\":\"0\",\"scy\":\"auto\",\"net\":\"ws\",\"type\":\"none\",\"host\":\"\",\"path\":\"${vm_path}\",\"tls\":\"\"}"
vm_b64=$(echo -n "$vm_json" | base64 | tr -d '\r\n ')
vm_link="vmess://${vm_b64}"
share_links+=("$vm_link")
summary_text+="[VMess-WS] 端口: ${vm_port}/tcp | Path: ${vm_path} | UUID: ${uuid}\n${vm_link}\n\n"
clash_proxies+=$(cat <<EOF
- name: "${vm_name}"
type: vmess
server: ${server_ip}
port: ${vm_port}
uuid: ${uuid}
alterId: 0
cipher: auto
udp: true
network: ws
ws-opts:
path: "${vm_path}"
EOF
)
sb_outbounds+=("$(cat <<EOF
{
"type": "vmess",
"tag": "${vm_name}",
"server": "${server_ip}",
"server_port": ${vm_port},
"uuid": "${uuid}",
"security": "auto",
"transport": {
"type": "ws",
"path": "${vm_path}"
}
}
EOF
)")
fi
# --------------------------------------------------------------------------
# 5. AnyTLS
# --------------------------------------------------------------------------
if [[ $(jq -r '.protocols.anytls.enabled // false' "${META_FILE}") == "true" ]]; then
local an_port an_sni an_name an_link
an_port=$(jq -r '.protocols.anytls.port' "${META_FILE}")
an_sni=$(jq -r '.protocols.anytls.sni' "${META_FILE}")
an_name="AnyTLS-${server_ip}"
an_link="anytls://${uuid}@${server_ip}:${an_port}?sni=${an_sni}&insecure=1#${an_name}"
share_links+=("$an_link")
summary_text+="[AnyTLS] 端口: ${an_port}/tcp | SNI: ${an_sni} | 密码: ${uuid}\n${an_link}\n\n"
clash_proxies+=$(cat <<EOF
- name: "${an_name}"
type: anytls
server: ${server_ip}
port: ${an_port}
password: ${uuid}
sni: ${an_sni}
skip-cert-verify: true
EOF
)
sb_outbounds+=("$(cat <<EOF
{
"type": "anytls",
"tag": "${an_name}",
"server": "${server_ip}",
"server_port": ${an_port},
"password": "${uuid}",
"tls": {
"enabled": true,
"server_name": "${an_sni}",
"insecure": true
}
}
EOF
)")
fi
# --------------------------------------------------------------------------
# 导出客户端配置文件
# --------------------------------------------------------------------------
local sb_outbounds_joined
sb_outbounds_joined=$(IFS=,; echo "${sb_outbounds[*]}")
local all_links_raw=""
for link in "${share_links[@]}"; do
all_links_raw+="${link}"$'\n'
done
local sub_base64
sub_base64=$(echo -n "$all_links_raw" | base64 | tr -d '\r\n ')
local info_file="${INSTALL_DIR}/node_info.txt"
local clash_file="${INSTALL_DIR}/clash_meta.yaml"
local sb_client_file="${INSTALL_DIR}/singbox_client.json"
local b64_file="${INSTALL_DIR}/sub_base64.txt"
echo "$sub_base64" > "$b64_file"
cat > "$clash_file" <<EOF
# Clash-Meta / Mihomo 节点配置片段
proxies:${clash_proxies}
EOF
cat > "$sb_client_file" <<EOF
{
"outbounds": [
${sb_outbounds_joined}
]
}
EOF
cat > "$info_file" <<EOF
================================================================================
Sing-box 多协议节点与订阅信息汇总
================================================================================
服务器 IP : ${server_ip}
统一 UUID : ${uuid}
--------------------------------------------------------------------------------
$(echo -e "$summary_text")--------------------------------------------------------------------------------
【聚合 Base64 订阅内容 (可整段复制导入 v2rayN / Nekobox / Shadowrocket)】:
${sub_base64}
================================================================================
EOF
chmod 600 "$info_file" "$clash_file" "$sb_client_file" "$b64_file"
# 终端高亮打印
echo ""
echo -e "${CLR_GREEN}================================================================================${CLR_RESET}"
echo -e "${CLR_BOLD}${CLR_GREEN} Sing-box 核心代理节点与订阅信息汇总${CLR_RESET}"
echo -e "${CLR_GREEN}================================================================================${CLR_RESET}"
echo -e "${CLR_BOLD}服务器 IP${CLR_RESET} : ${CLR_YELLOW}${server_ip}${CLR_RESET}"
echo -e "${CLR_BOLD}统一 UUID${CLR_RESET} : ${CLR_BLUE}${uuid}${CLR_RESET}"
echo -e "${CLR_GREEN}--------------------------------------------------------------------------------${CLR_RESET}"
echo -e "$summary_text"
echo -e "${CLR_GREEN}--------------------------------------------------------------------------------${CLR_RESET}"
echo -e "${CLR_BOLD}${CLR_YELLOW}【聚合 Base64 订阅串】(一键复制导入客户端即可识别所有已装协议):${CLR_RESET}"
echo -e "${CLR_PURPLE}${sub_base64}${CLR_RESET}"
echo -e "${CLR_GREEN}--------------------------------------------------------------------------------${CLR_RESET}"
echo -e "${CLR_BOLD}本地导出的配置文件路径:${CLR_RESET}"
echo -e " • 节点详情汇总 : ${CLR_BLUE}${info_file}${CLR_RESET}"
echo -e " • Clash/Mihomo : ${CLR_BLUE}${clash_file}${CLR_RESET}"
echo -e " • Sing-box客户端: ${CLR_BLUE}${sb_client_file}${CLR_RESET}"
echo -e " • Base64 订阅串 : ${CLR_BLUE}${b64_file}${CLR_RESET}"
echo -e "${CLR_GREEN}================================================================================${CLR_RESET}"
echo ""
}
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env bash
# ==============================================================================
# 模块:Sing-box 官方二进制安装、版本管理与 Systemd 服务管理
# ==============================================================================
# 获取官方最新版本号
get_latest_singbox_version() {
local version=""
# 优先尝试 GitHub API
version=$(curl -sL --max-time 5 "https://api.github.com/repos/SagerNet/sing-box/releases/latest" 2>/dev/null | jq -r '.tag_name' 2>/dev/null | sed 's/^v//')
# 备用方案:重定向网页抓取
if [[ -z "$version" || "$version" == "null" ]]; then
version=$(curl -sL --max-time 5 "https://github.com/SagerNet/sing-box/releases/latest" 2>/dev/null | grep -oP 'tag/v\K[0-9.]+' | head -n 1)
fi
# 兜底固定稳定版本 (如果 GitHub 无法连接)
if [[ -z "$version" || "$version" == "null" ]]; then
version="1.11.0"
fi
echo "$version"
}
# 下载并安装官方原版 Sing-box 二进制
install_singbox_binary() {
local arch
arch=$(detect_arch) || return 1
local version
version=$(get_latest_singbox_version)
log_info "准备安装 Sing-box 官方核心版本: v${version} (架构: ${arch})..."
local pkg_name="sing-box-${version}-linux-${arch}"
local download_url="https://github.com/SagerNet/sing-box/releases/download/v${version}/${pkg_name}.tar.gz"
local temp_tar="/tmp/${pkg_name}.tar.gz"
local temp_dir="/tmp/${pkg_name}"
log_info "正在从 GitHub Releases 官方通道下载..."
if ! curl -L --fail --retry 3 --connect-timeout 10 -o "$temp_tar" "$download_url"; then
log_error "下载 Sing-box 失败,请检查服务器连接 GitHub 的网络状况!"
return 1
fi
# 解压并部署
rm -rf "$temp_dir"
mkdir -p "$temp_dir"
tar -xzf "$temp_tar" -C /tmp/ || {
log_error "解压 Sing-box 压缩包失败!"
rm -f "$temp_tar"
return 1
}
mkdir -p "${BIN_DIR}"
cp -f "${temp_dir}/sing-box" "${BIN_PATH}"
chmod +x "${BIN_PATH}"
chown root:root "${BIN_PATH}"
# 清理临时下载文件
rm -rf "$temp_tar" "$temp_dir"
# 验证是否可用
if ! "${BIN_PATH}" version >/dev/null 2>&1; then
log_error "Sing-box 二进制文件执行测试失败!"
return 1
fi
local installed_ver
installed_ver=$("${BIN_PATH}" version | head -n 1)
log_success "Sing-box 核心安装成功: ${installed_ver}"
return 0
}
# 配置安全可靠的 Systemd 服务文件
setup_systemd_service() {
log_info "配置 Sing-box Systemd 系统守护进程..."
cat > "${SERVICE_FILE}" <<EOF
[Unit]
Description=Sing-box Service
Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target
[Service]
Type=simple
User=root
WorkingDirectory=${INSTALL_DIR}
ExecStart=${BIN_PATH} run -c ${CONFIG_FILE}
Restart=on-failure
RestartSec=5s
LimitNOFILE=65535
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "${SERVICE_NAME}" >/dev/null 2>&1
log_success "Systemd 守护服务配置完成!"
}
# 服务启停控制
start_service() {
systemctl start "${SERVICE_NAME}"
}
stop_service() {
systemctl stop "${SERVICE_NAME}"
}
restart_service() {
systemctl restart "${SERVICE_NAME}"
}
is_service_active() {
systemctl is-active --quiet "${SERVICE_NAME}"
}
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env bash
# ==============================================================================
# 模块:系统架构识别、依赖安装与安全防火墙配置
# ==============================================================================
# 识别系统架构
detect_arch() {
local raw_arch
raw_arch=$(uname -m)
case "${raw_arch}" in
x86_64|amd64)
echo "amd64"
;;
aarch64|arm64)
echo "arm64"
;;
armv7*|armv8l)
echo "armv7"
;;
*)
log_error "暂不支持的 CPU 架构: ${raw_arch}"
return 1
;;
esac
}
# 识别系统包管理器并安装基础依赖
install_dependencies() {
log_info "检查并安装必要系统工具 (curl, tar, jq, openssl, ca-certificates)..."
local pkgs=("curl" "tar" "jq" "openssl" "ca-certificates")
if command -v apt-get >/dev/null 2>&1; then
apt-get update -y >/dev/null 2>&1
apt-get install -y "${pkgs[@]}" >/dev/null 2>&1
elif command -v dnf >/dev/null 2>&1; then
dnf install -y "${pkgs[@]}" >/dev/null 2>&1
elif command -v yum >/dev/null 2>&1; then
yum install -y "${pkgs[@]}" >/dev/null 2>&1
elif command -v apk >/dev/null 2>&1; then
apk update >/dev/null 2>&1
apk add --no-cache "${pkgs[@]}" >/dev/null 2>&1
else
log_warn "未识别的包管理器,请手动确保安装了: ${pkgs[*]}"
fi
# 验证关键工具安装结果
for cmd in curl tar jq openssl; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log_error "关键依赖工具 [${cmd}] 安装失败,请检查网络或系统源设置!"
return 1
fi
done
log_success "系统基础依赖检测通过!"
return 0
}
# 获取公网 IP(具备多节点故障自动切换机制)
get_public_ip() {
local ip=""
local apis=(
"https://api.ipify.org"
"https://icanhazip.com"
"https://ifconfig.me/ip"
"https://checkip.amazonaws.com"
)
for api in "${apis[@]}"; do
ip=$(curl -s4m 4 "$api" 2>/dev/null | tr -d '[:space:]')
if [[ -n "$ip" && "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "$ip"
return 0
fi
done
# 尝试获取 IPv6 (如果仅有 IPv6)
ip=$(curl -s6m 4 "https://api64.ipify.org" 2>/dev/null | tr -d '[:space:]')
if [[ -n "$ip" ]]; then
echo "$ip"
return 0
fi
echo "127.0.0.1"
}
# 安全配置防火墙:精准仅开放代理端口,杜绝关闭防火墙或全盘清空规则
open_firewall_port() {
local port="$1"
local protocol="${2:-tcp}"
[[ -z "$port" ]] && return 0
log_info "正在配置防火墙放行端口: ${port}/${protocol}..."
# 1. 检测 UFW
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -qw "active"; then
ufw allow "${port}/${protocol}" comment "sing-box" >/dev/null 2>&1
log_success "UFW 已放行端口 ${port}/${protocol}"
return 0
fi
# 2. 检测 Firewalld
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
firewall-cmd --permanent --add-port="${port}/${protocol}" >/dev/null 2>&1
firewall-cmd --reload >/dev/null 2>&1
log_success "Firewalld 已放行端口 ${port}/${protocol}"
return 0
fi
# 3. iptables 兜底安全追加(不重置现有规则链)
if command -v iptables >/dev/null 2>&1; then
if ! iptables -C INPUT -p "${protocol}" --dport "${port}" -j ACCEPT 2>/dev/null; then
iptables -I INPUT -p "${protocol}" --dport "${port}" -j ACCEPT 2>/dev/null
log_success "iptables 已安全追加放行规则: ${port}/${protocol}"
fi
fi
}
# 卸载或更换端口时安全移除端口规则
close_firewall_port() {
local port="$1"
local protocol="${2:-tcp}"
[[ -z "$port" ]] && return 0
log_info "正在清理防火墙放行规则: ${port}/${protocol}..."
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -qw "active"; then
ufw delete allow "${port}/${protocol}" >/dev/null 2>&1 || true
fi
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
firewall-cmd --permanent --remove-port="${port}/${protocol}" >/dev/null 2>&1 || true
firewall-cmd --reload >/dev/null 2>&1 || true
fi
if command -v iptables >/dev/null 2>&1; then
iptables -D INPUT -p "${protocol}" --dport "${port}" -j ACCEPT 2>/dev/null || true
fi
}
+333
View File
@@ -0,0 +1,333 @@
#!/usr/bin/env bash
# ==============================================================================
# 项目:Sing-box 极简现代化核心部署管理脚本 (全协议增强版)
# 支持五大协议:VLESS-Reality / Hysteria 2 / TUIC v5 / VMess-WS / AnyTLS
# 特性:原生二进制、安全防火墙精准放行、零隐私泄露、零后门、多平台订阅一键生成
# ==============================================================================
set -eo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 加载各核心子模块
source "${SCRIPT_DIR}/lib/env.sh"
source "${SCRIPT_DIR}/lib/system.sh"
source "${SCRIPT_DIR}/lib/cert.sh"
source "${SCRIPT_DIR}/lib/singbox.sh"
source "${SCRIPT_DIR}/lib/config.sh"
source "${SCRIPT_DIR}/lib/info.sh"
# 创建或确保全局快捷指令
ensure_symlink() {
if [[ ! -e "${SCRIPT_LINK}" ]]; then
ln -sf "${SCRIPT_DIR}/sb.sh" "${SCRIPT_LINK}"
chmod +x "${SCRIPT_LINK}"
log_info "已创建全局快捷指令:直接在终端输入 ${CLR_GREEN}sb${CLR_RESET} 即可随时调出菜单"
fi
}
# 部署并启动服务
finish_setup() {
setup_systemd_service
restart_service
ensure_symlink
sleep 1
if is_service_active; then
log_success "Sing-box 核心代理守护服务已平稳启动!"
show_node_info
else
log_error "Sing-box 启动异常,请通过 'sb log' 查看详细报错!"
fi
}
# 模式 1:一键五协议共存模式部署
do_install_all() {
check_root
log_info "========== 开始安装 Sing-box 五协议共存套件 =========="
install_dependencies || exit 1
install_singbox_binary || exit 1
local p_vless="${1:-443}"
local p_hy2="${2:-8443}"
local p_tuic="${3:-9443}"
local p_vmess="${4:-8080}"
local p_anytls="${5:-10443}"
if [[ -z "${1:-}" ]]; then
echo -e "${CLR_BOLD}请指定各协议监听端口(直接回车使用推荐默认值):${CLR_RESET}"
read -rp "1. VLESS-Reality 端口 [默认: 443/tcp]: " in_vless
read -rp "2. Hysteria 2 端口 [默认: 8443/udp]: " in_hy2
read -rp "3. TUIC v5 端口 [默认: 9443/udp]: " in_tuic
read -rp "4. VMess-WS 端口 [默认: 8080/tcp]: " in_vmess
read -rp "5. AnyTLS 端口 [默认: 10443/tcp]: " in_anytls
p_vless="${in_vless:-443}"
p_hy2="${in_hy2:-8443}"
p_tuic="${in_tuic:-9443}"
p_vmess="${in_vmess:-8080}"
p_anytls="${in_anytls:-10443}"
fi
# 生成多协议套件配置
generate_suite_config "all" "$p_vless" "$p_hy2" "$p_tuic" "$p_vmess" "$p_anytls" || exit 1
# 安全放行对应端口与协议
open_firewall_port "$p_vless" "tcp"
open_firewall_port "$p_hy2" "udp"
open_firewall_port "$p_tuic" "udp"
open_firewall_port "$p_vmess" "tcp"
open_firewall_port "$p_anytls" "tcp"
finish_setup
}
# 模式 2:指定单协议独立安装
do_install_single() {
local proto="$1"
check_root
install_dependencies || exit 1
install_singbox_binary || exit 1
case "$proto" in
vless)
local port="${2:-}"
local sni="${3:-}"
if [[ -z "$port" ]]; then
read -rp "请输入 VLESS-Reality 端口 [默认: 443]: " in_port
read -rp "请输入伪装域名 SNI [默认: www.apple.com]: " in_sni
port="${in_port:-443}"
sni="${in_sni:-www.apple.com}"
fi
generate_suite_config "vless" "$port" "$sni" || exit 1
open_firewall_port "$port" "tcp"
;;
hy2)
local port="${2:-}"
if [[ -z "$port" ]]; then
read -rp "请输入 Hysteria 2 端口 [默认: 8443]: " in_port
port="${in_port:-8443}"
fi
generate_suite_config "hy2" "$port" || exit 1
open_firewall_port "$port" "udp"
;;
tuic)
local port="${2:-}"
if [[ -z "$port" ]]; then
read -rp "请输入 TUIC v5 端口 [默认: 9443]: " in_port
port="${in_port:-9443}"
fi
generate_suite_config "tuic" "$port" || exit 1
open_firewall_port "$port" "udp"
;;
vmess)
local port="${2:-}"
if [[ -z "$port" ]]; then
read -rp "请输入 VMess-WS 端口 [默认: 8080]: " in_port
port="${in_port:-8080}"
fi
generate_suite_config "vmess" "$port" || exit 1
open_firewall_port "$port" "tcp"
;;
anytls)
local port="${2:-}"
if [[ -z "$port" ]]; then
read -rp "请输入 AnyTLS 端口 [默认: 10443]: " in_port
port="${in_port:-10443}"
fi
generate_suite_config "anytls" "$port" || exit 1
open_firewall_port "$port" "tcp"
;;
*)
log_error "不支持的协议: $proto"
return 1
;;
esac
finish_setup
}
# 单协议交互选择子菜单
show_single_menu() {
clear
echo -e "${CLR_GREEN}================================================================${CLR_RESET}"
echo -e "${CLR_BOLD}${CLR_GREEN} 请选择要单独安装的代理协议 ${CLR_RESET}"
echo -e "${CLR_GREEN}================================================================${CLR_RESET}"
echo -e " ${CLR_BOLD}1)${CLR_RESET} VLESS-Reality-Vision (免证书顶级抗封锁)"
echo -e " ${CLR_BOLD}2)${CLR_RESET} Hysteria 2 (极速 QUIC/UDP,恶劣网络首选)"
echo -e " ${CLR_BOLD}3)${CLR_RESET} TUIC v5 (BBR 拥塞控制 QUIC)"
echo -e " ${CLR_BOLD}4)${CLR_RESET} VMess-WS (经典 WebSocket,兼容 CDN 反代)"
echo -e " ${CLR_BOLD}5)${CLR_RESET} AnyTLS (Sing-box 原生 TLS 协议)"
echo -e " ${CLR_BOLD}0)${CLR_RESET} 返回上一级菜单"
echo -e "${CLR_GREEN}================================================================${CLR_RESET}"
read -rp "请选择 [0-5]: " sub_choice
case "$sub_choice" in
1) do_install_single "vless" ;;
2) do_install_single "hy2" ;;
3) do_install_single "tuic" ;;
4) do_install_single "vmess" ;;
5) do_install_single "anytls" ;;
0) return 0 ;;
*) log_warn "无效选项!" ;;
esac
}
# 查看实时日志
do_logs() {
check_root
log_info "正在查看 Sing-box 实时运行日志 (按 Ctrl+C 退出)..."
journalctl -u "${SERVICE_NAME}" -f -n 50
}
# 安全清理卸载
do_uninstall() {
check_root
echo -e "${CLR_YELLOW}确定要彻底卸载 Sing-box 代理服务吗?[y/N]: ${CLR_RESET}"
read -r choice
case "$choice" in
[Yy]*)
log_info "开始安全清理 Sing-box..."
# 清理所有已启用的防火墙放行规则
if [[ -f "${META_FILE}" ]]; then
local p_vl p_hy p_tu p_vm p_an
p_vl=$(jq -r '.protocols.vless_reality.port // empty' "${META_FILE}")
p_hy=$(jq -r '.protocols.hysteria2.port // empty' "${META_FILE}")
p_tu=$(jq -r '.protocols.tuic.port // empty' "${META_FILE}")
p_vm=$(jq -r '.protocols.vmess_ws.port // empty' "${META_FILE}")
p_an=$(jq -r '.protocols.anytls.port // empty' "${META_FILE}")
[[ -n "$p_vl" ]] && close_firewall_port "$p_vl" "tcp"
[[ -n "$p_hy" ]] && close_firewall_port "$p_hy" "udp"
[[ -n "$p_tu" ]] && close_firewall_port "$p_tu" "udp"
[[ -n "$p_vm" ]] && close_firewall_port "$p_vm" "tcp"
[[ -n "$p_an" ]] && close_firewall_port "$p_an" "tcp"
fi
# 停止并清理守护服务
if systemctl is-enabled --quiet "${SERVICE_NAME}" 2>/dev/null; then
systemctl stop "${SERVICE_NAME}" >/dev/null 2>&1 || true
systemctl disable "${SERVICE_NAME}" >/dev/null 2>&1 || true
fi
rm -f "${SERVICE_FILE}"
systemctl daemon-reload >/dev/null 2>&1 || true
# 仅清理程序自身目录,杜绝误伤
rm -rf "${INSTALL_DIR}"
rm -f "${BIN_PATH}" "${SCRIPT_LINK}"
log_success "Sing-box 核心服务已完全且干净地卸载!"
;;
*)
log_info "已取消卸载。"
;;
esac
}
# 交互式主菜单
show_menu() {
clear
echo -e "${CLR_GREEN}================================================================${CLR_RESET}"
echo -e "${CLR_BOLD}${CLR_GREEN} Sing-box 现代化核心管理工具 (全协议纯净版) ${CLR_RESET}"
echo -e "${CLR_GREEN}================================================================${CLR_RESET}"
local status_text
if is_service_active 2>/dev/null; then
status_text="${CLR_GREEN}● 运行中${CLR_RESET}"
else
status_text="${CLR_RED}○ 未运行${CLR_RESET}"
fi
echo -e "核心状态: ${status_text}"
echo -e "${CLR_GREEN}----------------------------------------------------------------${CLR_RESET}"
echo -e " ${CLR_BOLD}1)${CLR_RESET} 一键安装【五协议共存套件】 (VLESS+Hy2+TUIC+VMess+AnyTLS)"
echo -e " ${CLR_BOLD}2)${CLR_RESET} 自选单协议独立安装"
echo -e " ${CLR_BOLD}3)${CLR_RESET} 查看当前已装节点信息与分享链接"
echo -e " ${CLR_BOLD}4)${CLR_RESET} 启动服务"
echo -e " ${CLR_BOLD}5)${CLR_RESET} 停止服务"
echo -e " ${CLR_BOLD}6)${CLR_RESET} 重启服务"
echo -e " ${CLR_BOLD}7)${CLR_RESET} 查看实时日志"
echo -e " ${CLR_BOLD}8)${CLR_RESET} 彻底干净卸载"
echo -e " ${CLR_BOLD}0)${CLR_RESET} 退出"
echo -e "${CLR_GREEN}================================================================${CLR_RESET}"
read -rp "请选择操作 [0-8]: " menu_choice
case "$menu_choice" in
1) do_install_all ;;
2) show_single_menu ;;
3) show_node_info ;;
4)
start_service
log_success "服务已启动!"
;;
5)
stop_service
log_success "服务已停止!"
;;
6)
restart_service
log_success "服务已重启!"
;;
7) do_logs ;;
8) do_uninstall ;;
0) exit 0 ;;
*) log_warn "无效选项,请重新输入!" ;;
esac
}
# 命令行 CLI 支持
case "${1:-}" in
install)
shift
case "${1:-}" in
all)
shift
do_install_all "$@"
;;
vless|hy2|tuic|vmess|anytls)
proto="$1"
shift
do_install_single "$proto" "$@"
;;
*)
do_install_all
;;
esac
;;
info|show)
show_node_info
;;
start)
check_root
start_service
log_success "服务已启动!"
;;
stop)
check_root
stop_service
log_success "服务已停止!"
;;
restart)
check_root
restart_service
log_success "服务已重启!"
;;
status)
if is_service_active; then
log_success "Sing-box 正在稳定运行中。"
else
log_warn "Sing-box 当前未运行。"
fi
;;
log|logs)
do_logs
;;
uninstall)
do_uninstall
;;
*)
show_menu
;;
esac