├── debian ├── clean_nft.sh ├── check_config.sh ├── check_environment.sh ├── set_defaults.sh ├── stop_singbox.sh ├── switch_mode.sh ├── configure_tun.sh ├── update_config.sh ├── check_update.sh ├── set_network.sh ├── start_singbox.sh ├── optimize.sh ├── ufw.sh ├── manual_input.sh ├── auto_update.sh ├── kernel.sh ├── manage_autostart.sh ├── configure_tproxy.sh ├── manual_update.sh ├── commands.sh ├── update_scripts.sh ├── install_singbox.sh ├── update_ui.sh ├── delaytest.sh ├── setup.sh └── menu.sh ├── openwrt ├── clean_nft.sh ├── check_environment.sh ├── check_config.sh ├── set_defaults.sh ├── stop_singbox.sh ├── switch_mode.sh ├── start_singbox.sh ├── configure_tun.sh ├── commands.sh ├── install_singbox.sh ├── manage_autostart.sh ├── manual_input.sh ├── auto_update.sh ├── configure_tproxy.sh ├── update_scripts.sh ├── manual_update.sh ├── menu.sh └── update_ui.sh ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.yml │ └── bug_request.yml ├── README.md ├── config_template ├── server │ └── config.json ├── config_tproxy.json ├── config_tun.json ├── config_trpoxy12.json ├── config_fakeiptun12.json └── config_fakeiptrpoxy12.json └── sbshall.sh /debian/clean_nft.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 清理防火墙规则并停止服务 4 | sudo systemctl stop sing-box 5 | nft flush ruleset 6 | 7 | echo "sing-box 服务已停止,防火墙规则已清理." 8 | -------------------------------------------------------------------------------- /openwrt/clean_nft.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | nft list table inet sing-box >/dev/null 2>&1 && nft delete table inet sing-box 4 | 5 | echo "sing-box 服务已停止, sing-box 相关的防火墙规则已清理." 6 | -------------------------------------------------------------------------------- /openwrt/check_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$(id -u)" != "0" ]; then 4 | echo "错误: 此脚本需要 root 权限" 5 | exit 1 6 | fi 7 | 8 | if command -v sing-box &> /dev/null; then 9 | current_version=$(sing-box version | grep 'sing-box version' | awk '{print $3}') 10 | echo "sing-box 已安装,版本:$current_version" 11 | else 12 | echo "sing-box 未安装" 13 | fi -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: "Suggest an idea for this project" 3 | title: "[Feature Request]" 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: 功能描述 10 | description: 在此描述你想要的功能 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: additional_context 15 | attributes: 16 | label: 附加信息 17 | description: 你觉得对添加此功能有帮助的其它信息 18 | validations: 19 | required: false -------------------------------------------------------------------------------- /debian/check_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # No Color 7 | 8 | CONFIG_FILE="/etc/sing-box/config.json" 9 | 10 | 11 | if [ -f "$CONFIG_FILE" ]; then 12 | echo -e "${CYAN}检查配置文件 ${CONFIG_FILE} ...${NC}" 13 | 14 | if sing-box check -c "$CONFIG_FILE"; then 15 | echo -e "${CYAN}配置文件验证通过!${NC}" 16 | else 17 | echo -e "${RED}配置文件验证失败!${NC}" 18 | exit 1 19 | fi 20 | else 21 | echo -e "${RED}配置文件 ${CONFIG_FILE} 不存在!${NC}" 22 | exit 1 23 | fi 24 | -------------------------------------------------------------------------------- /openwrt/check_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # No Color 7 | 8 | CONFIG_FILE="/etc/sing-box/config.json" 9 | 10 | # 检查配置文件是否存在 11 | if [ -f "$CONFIG_FILE" ]; then 12 | echo -e "${CYAN}检查配置文件 ${CONFIG_FILE} ...${NC}" 13 | # 验证配置文件 14 | if sing-box check -c "$CONFIG_FILE"; then 15 | echo -e "${CYAN}配置文件验证通过!${NC}" 16 | else 17 | echo -e "${RED}配置文件验证失败!${NC}" 18 | exit 1 19 | fi 20 | else 21 | echo -e "${RED}配置文件 ${CONFIG_FILE} 不存在!${NC}" 22 | exit 1 23 | fi 24 | -------------------------------------------------------------------------------- /debian/check_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$(id -u)" != "0" ]; then 4 | echo "错误: 此脚本需要 root 权限" 5 | exit 1 6 | fi 7 | 8 | if command -v sing-box &> /dev/null; then 9 | current_version=$(sing-box version | grep 'sing-box version' | awk '{print $3}') 10 | echo "sing-box 已安装,版本:$current_version" 11 | else 12 | echo "sing-box 未安装" 13 | fi 14 | 15 | ipv4_forward=$(sysctl net.ipv4.ip_forward | awk '{print $3}') 16 | ipv6_forward=$(sysctl net.ipv6.conf.all.forwarding | awk '{print $3}') 17 | 18 | if [ "$ipv4_forward" -eq 1 ] && [ "$ipv6_forward" -eq 1 ]; then 19 | echo "IP 转发已开启" 20 | else 21 | echo "开启 IP 转发..." 22 | sudo sed -i '/net.ipv4.ip_forward/s/^#//;/net.ipv6.conf.all.forwarding/s/^#//' /etc/sysctl.conf 23 | sudo sysctl -p 24 | echo "IP 转发已成功开启" 25 | fi -------------------------------------------------------------------------------- /openwrt/set_defaults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DEFAULTS_FILE="/etc/sing-box/defaults.conf" 4 | 5 | read -rp "请输入后端地址: " BACKEND_URL 6 | BACKEND_URL=${BACKEND_URL:-$(grep BACKEND_URL $DEFAULTS_FILE | cut -d '=' -f2)} 7 | 8 | read -rp "请输入订阅地址: " SUBSCRIPTION_URL 9 | SUBSCRIPTION_URL=${SUBSCRIPTION_URL:-$(grep SUBSCRIPTION_URL $DEFAULTS_FILE | cut -d '=' -f2)} 10 | 11 | read -rp "请输入TProxy配置文件地址: " TPROXY_TEMPLATE_URL 12 | TPROXY_TEMPLATE_URL=${TPROXY_TEMPLATE_URL:-$(grep TPROXY_TEMPLATE_URL $DEFAULTS_FILE | cut -d '=' -f2)} 13 | 14 | read -rp "请输入TUN配置文件地址: " TUN_TEMPLATE_URL 15 | TUN_TEMPLATE_URL=${TUN_TEMPLATE_URL:-$(grep TUN_TEMPLATE_URL $DEFAULTS_FILE | cut -d '=' -f2)} 16 | 17 | # 更新默认配置文件 18 | cat > $DEFAULTS_FILE < $DEFAULTS_FILE < /dev/null; then 10 | echo "请安装 sing-box 后再执行。" 11 | bash /etc/sing-box/scripts/install_singbox.sh 12 | exit 1 13 | fi 14 | 15 | # 确定文件存在 16 | mkdir -p /etc/sing-box/ 17 | [ -f /etc/sing-box/mode.conf ] || touch /etc/sing-box/mode.conf 18 | chmod 777 /etc/sing-box/mode.conf 19 | 20 | echo "切换模式开始...请根据提示输入操作。" 21 | 22 | 23 | while true; do 24 | # 选择模式 25 | read -rp "请选择模式(1: TProxy 模式, 2: TUN 模式): " mode_choice 26 | 27 | /etc/init.d/sing-box stop 28 | 29 | case $mode_choice in 30 | 1) 31 | echo "MODE=TProxy" | tee /etc/sing-box/mode.conf > /dev/null 32 | echo -e "${GREEN}当前选择模式为:TProxy 模式${NC}" 33 | break 34 | ;; 35 | 2) 36 | echo "MODE=TUN" | tee /etc/sing-box/mode.conf > /dev/null 37 | echo -e "${GREEN}当前选择模式为:TUN 模式${NC}" 38 | break 39 | ;; 40 | *) 41 | echo -e "${RED}无效的选择,请重新输入。${NC}" 42 | ;; 43 | esac 44 | done 45 | -------------------------------------------------------------------------------- /debian/switch_mode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | GREEN='\033[0;32m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | # 检查 sing-box 是否已安装 9 | if ! command -v sing-box &> /dev/null; then 10 | echo "请安装 sing-box 后再执行。" 11 | sudo bash /etc/sing-box/scripts/install_singbox.sh 12 | exit 1 13 | fi 14 | 15 | # 停止 sing-box 服务 16 | function stop_singbox() { 17 | sudo systemctl stop sing-box 18 | if ! systemctl is-active --quiet sing-box; then 19 | echo "sing-box 已停止" >/dev/null 20 | else 21 | exit 1 22 | fi 23 | } 24 | 25 | # 切换模式的逻辑 26 | echo "切换模式开始...请根据提示输入操作。" 27 | 28 | while true; do 29 | # 选择模式 30 | read -rp "请选择模式(1: TProxy 模式, 2: TUN 模式): " mode_choice 31 | 32 | case $mode_choice in 33 | 1) 34 | stop_singbox 35 | echo "MODE=TProxy" | sudo tee /etc/sing-box/mode.conf > /dev/null 36 | echo -e "${GREEN}当前选择模式为:TProxy 模式${NC}" 37 | break 38 | ;; 39 | 2) 40 | stop_singbox 41 | echo "MODE=TUN" | sudo tee /etc/sing-box/mode.conf > /dev/null 42 | echo -e "${GREEN}当前选择模式为:TUN 模式${NC}" 43 | break 44 | ;; 45 | *) 46 | echo -e "${RED}无效的选择,请重新输入。${NC}" 47 | ;; 48 | esac 49 | done 50 | -------------------------------------------------------------------------------- /debian/configure_tun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 配置参数 4 | PROXY_FWMARK=1 5 | PROXY_ROUTE_TABLE=100 6 | INTERFACE=$(ip route show default | awk '/default/ {print $5}') 7 | 8 | # 读取当前模式 9 | MODE=$(grep -oP '(?<=^MODE=).*' /etc/sing-box/mode.conf) 10 | 11 | # 清理 TProxy 模式的防火墙规则 12 | clearTProxyRules() { 13 | nft list table inet sing-box >/dev/null 2>&1 && nft delete table inet sing-box 14 | ip rule del fwmark $PROXY_FWMARK lookup $PROXY_ROUTE_TABLE 2>/dev/null 15 | ip route del local default dev "$INTERFACE" table $PROXY_ROUTE_TABLE 2>/dev/null 16 | echo "清理 TProxy 模式的防火墙规则" 17 | } 18 | 19 | if [ "$MODE" = "TUN" ]; then 20 | echo "应用 TUN 模式下的防火墙规则..." 21 | 22 | # 清理 TProxy 模式的防火墙规则 23 | clearTProxyRules 24 | 25 | # 确保目录存在 26 | sudo mkdir -p /etc/sing-box/tun 27 | 28 | # 设置 TUN 模式的具体配置 29 | cat > /etc/sing-box/tun/nftables.conf < /etc/nftables.conf 44 | 45 | echo "TUN 模式的防火墙规则已应用。" 46 | else 47 | echo "当前模式不是 TUN 模式,跳过防火墙规则配置。" >/dev/null 2>&1 48 | fi 49 | -------------------------------------------------------------------------------- /openwrt/start_singbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | MAGENTA='\033[0;35m' 7 | RED='\033[0;31m' 8 | NC='\033[0m' # 无颜色 9 | 10 | # 检查当前模式 11 | check_mode() { 12 | if nft list chain inet sing-box prerouting_tproxy &>/dev/null || nft list chain inet sing-box output_tproxy &>/dev/null; then 13 | echo "TProxy 模式" 14 | else 15 | echo "TUN 模式" 16 | fi 17 | } 18 | 19 | # 启动 sing-box 服务 20 | start_singbox() { 21 | echo -e "${CYAN}检测是否处于非代理环境...${NC}" 22 | STATUS_CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "https://www.google.com") 23 | 24 | if [ "$STATUS_CODE" -eq 200 ]; then 25 | echo -e "${RED}当前网络处于代理环境, 启动 sing-box 需要直连!${NC}" 26 | else 27 | echo -e "${CYAN}当前网络环境非代理网络,可以启动 sing-box。${NC}" 28 | fi 29 | 30 | # 启动 sing-box 服务 31 | /etc/init.d/sing-box start 32 | 33 | sleep 2 # 等待 sing-box 启动 34 | 35 | 36 | if /etc/init.d/sing-box status | grep -q "running"; then 37 | echo -e "${GREEN}sing-box 启动成功${NC}" 38 | 39 | mode=$(check_mode) 40 | echo -e "${MAGENTA}当前启动模式: ${mode}${NC}" 41 | else 42 | echo -e "${RED}sing-box 启动失败,请检查日志${NC}" 43 | fi 44 | } 45 | 46 | # 提示用户确认是否启动 47 | read -rp "是否启动 sing-box?(y/n): " confirm_start 48 | if [[ "$confirm_start" =~ ^[Yy]$ ]]; then 49 | start_singbox 50 | else 51 | echo -e "${CYAN}已取消启动 sing-box。${NC}" 52 | exit 0 53 | fi 54 | -------------------------------------------------------------------------------- /openwrt/configure_tun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 配置参数 4 | PROXY_FWMARK=1 5 | PROXY_ROUTE_TABLE=100 6 | INTERFACE=$(ip route show default | awk '/default/ {print $5}') 7 | 8 | # 读取当前模式 9 | MODE=$(grep -E '^MODE=' /etc/sing-box/mode.conf | sed 's/^MODE=//') 10 | 11 | # 清理 TProxy 模式的防火墙规则 12 | clearTProxyRules() { 13 | nft list table inet sing-box >/dev/null 2>&1 && nft delete table inet sing-box 14 | ip rule del fwmark $PROXY_FWMARK lookup $PROXY_ROUTE_TABLE 2>/dev/null 15 | ip route del local default dev "$INTERFACE" table $PROXY_ROUTE_TABLE 2>/dev/null 16 | echo "清理 TProxy 模式的防火墙规则" 17 | } 18 | 19 | if [ "$MODE" = "TUN" ]; then 20 | echo "应用 TUN 模式下的防火墙规则..." 21 | 22 | # 清理 TProxy 模式的防火墙规则 23 | clearTProxyRules 24 | 25 | # 确保目录存在 26 | mkdir -p /etc/sing-box/tun 27 | 28 | # 设置 TUN 模式的具体配置 29 | cat > /etc/sing-box/tun/nftables.conf < /etc/nftables.conf 48 | 49 | echo "TUN 模式的防火墙规则已应用。" 50 | else 51 | echo "当前模式不是 TUN 模式,跳过防火墙规则配置。" >/dev/null 2>&1 52 | fi 53 | -------------------------------------------------------------------------------- /debian/update_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CYAN='\033[0;36m' 4 | GREEN='\033[0;32m' 5 | YELLOW='\033[1;33m' 6 | RED='\033[0;31m' 7 | NC='\033[0m' 8 | 9 | CONFIG_DIR="/etc/sing-box" 10 | CONFIG_FILE="${CONFIG_DIR}/config.json" 11 | CONFIG_URL_FILE="${CONFIG_DIR}/config.url" 12 | DEFAULT_CONFIG_URL="https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/config_template/server/config.json" 13 | 14 | if [ ! -d "$CONFIG_DIR" ]; then 15 | echo -e "${RED}sing-box 未安装或配置文件目录不存在,请先执行安装。${NC}" 16 | exit 1 17 | fi 18 | 19 | config_url="" 20 | if [ -s "$CONFIG_URL_FILE" ]; then 21 | config_url=$(cat "$CONFIG_URL_FILE") 22 | echo -e "${YELLOW}当前配置链接为: ${NC}$config_url" 23 | read -rp "是否更换配置链接? (y/N): " change_url 24 | if [[ "$change_url" =~ ^[Yy]$ ]]; then 25 | read -rp "请输入新的配置链接: " config_url 26 | fi 27 | else 28 | read -rp "首次使用,请输入配置链接 [回车使用默认]: " config_url 29 | [ -z "$config_url" ] && config_url="$DEFAULT_CONFIG_URL" 30 | fi 31 | 32 | if [ -z "$config_url" ]; then 33 | echo -e "${RED}配置链接不能为空,操作已取消。${NC}" 34 | exit 1 35 | fi 36 | 37 | echo -e "${CYAN}正在从以下链接下载配置文件: ${NC}$config_url" 38 | if wget -O "$CONFIG_FILE" --no-check-certificate "$config_url"; then 39 | echo -e "${GREEN}配置文件下载成功!${NC}" 40 | echo "$config_url" > "$CONFIG_URL_FILE" 41 | echo -e "${CYAN}正在重启 sing-box 服务...${NC}" 42 | systemctl restart sing-box 43 | echo -e "${GREEN}服务已重启。${NC}" 44 | else 45 | echo -e "${RED}配置文件下载失败,请检查链接是否正确或网络连接。${NC}" 46 | exit 1 47 | fi 48 | -------------------------------------------------------------------------------- /openwrt/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | MAGENTA='\033[0;35m' 6 | YELLOW='\033[1;33m' 7 | RED='\033[0;31m' 8 | NC='\033[0m' # 无颜色 9 | 10 | function view_firewall_rules() { 11 | echo -e "${YELLOW}查看防火墙规则...${NC}" 12 | nft list ruleset 13 | read -rp "按回车键返回二级菜单..." 14 | } 15 | 16 | function check_config() { 17 | echo -e "${YELLOW}检查配置文件...${NC}" 18 | bash /etc/sing-box/scripts/check_config.sh 19 | read -rp "按回车键返回二级菜单..." 20 | } 21 | 22 | function view_logs() { 23 | echo -e "${YELLOW}日志生成中,请等待...${NC}" 24 | echo -e "${RED}按 Ctrl + C 结束日志输出${NC}" 25 | logread -f | grep sing-box 26 | read -rp "按回车键返回二级菜单..." 27 | } 28 | 29 | function show_submenu() { 30 | echo -e "${CYAN}=========== 二级菜单选项 ===========${NC}" 31 | echo -e "${MAGENTA}1. 查看防火墙规则${NC}" 32 | echo -e "${MAGENTA}2. 检查配置文件${NC}" 33 | echo -e "${MAGENTA}3. 查看实时日志${NC}" 34 | echo -e "${MAGENTA}0. 返回主菜单${NC}" 35 | echo -e "${CYAN}===================================${NC}" 36 | } 37 | 38 | function handle_submenu_choice() { 39 | while true; do 40 | read -rp "请选择操作: " choice 41 | case $choice in 42 | 1) view_firewall_rules ;; 43 | 2) check_config ;; 44 | 3) view_logs ;; 45 | 0) return 0 ;; 46 | *) echo -e "${RED}无效的选择${NC}" ;; 47 | esac 48 | show_submenu 49 | done 50 | return 0 # 确保函数结束时返回 0 51 | } 52 | 53 | # 显示并处理二级菜单 54 | menu_active=true 55 | while $menu_active; do 56 | show_submenu 57 | handle_submenu_choice 58 | choice_returned=$? # 捕获函数返回值 59 | if [[ $choice_returned -eq 0 ]]; then 60 | menu_active=false 61 | fi 62 | done -------------------------------------------------------------------------------- /openwrt/install_singbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | if command -v sing-box &> /dev/null; then 9 | echo -e "${CYAN}sing-box 已安装,跳过安装步骤${NC}" 10 | else 11 | echo "正在更新包列表并安装 sing-box,请稍候..." 12 | opkg update >/dev/null 2>&1 13 | opkg install kmod-nft-tproxy >/dev/null 2>&1 14 | opkg install sing-box >/dev/null 2>&1 15 | 16 | if command -v sing-box &> /dev/null; then 17 | echo -e "${CYAN}sing-box 安装成功${NC}" 18 | else 19 | echo -e "${RED}sing-box 安装失败,请检查日志或网络配置${NC}" 20 | exit 1 21 | fi 22 | fi 23 | 24 | # 添加启动和停止命令到现有服务脚本 25 | if [ -f /etc/init.d/sing-box ]; then 26 | sed -i '/start_service()/,/}/d' /etc/init.d/sing-box 27 | sed -i '/stop_service()/,/}/d' /etc/init.d/sing-box 28 | fi 29 | 30 | cat << 'EOF' >> /etc/init.d/sing-box 31 | 32 | start_service() { 33 | procd_open_instance 34 | procd_set_param command /usr/bin/sing-box run -c /etc/sing-box/config.json 35 | procd_set_param respawn 36 | procd_set_param stderr 1 37 | procd_set_param stdout 1 38 | procd_close_instance 39 | 40 | # 等待服务完全启动 41 | sleep 3 42 | 43 | # 读取模式并应用防火墙规则 44 | MODE=$(grep -oE '^MODE=.*' /etc/sing-box/mode.conf | cut -d'=' -f2) 45 | if [ "$MODE" = "TProxy" ]; then 46 | /etc/sing-box/scripts/configure_tproxy.sh 47 | elif [ "$MODE" = "TUN" ]; then 48 | /etc/sing-box/scripts/configure_tun.sh 49 | fi 50 | } 51 | 52 | stop_service() { 53 | procd_kill "$NAME" 2>/dev/null 54 | } 55 | EOF 56 | 57 | chmod +x /etc/init.d/sing-box 58 | 59 | /etc/init.d/sing-box enable 60 | /etc/init.d/sing-box start 61 | 62 | echo -e "${CYAN}sing-box 服务已启用并启动${NC}" 63 | -------------------------------------------------------------------------------- /debian/check_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CYAN='\033[0;36m' 4 | RED='\033[0;31m' 5 | NC='\033[0m' # No Color 6 | 7 | echo "正在检测sing-box最新版本..." 8 | sudo apt-get update -qq > /dev/null 2>&1 9 | 10 | if command -v sing-box &> /dev/null; then 11 | current_version=$(sing-box version | grep 'sing-box version' | awk '{print $3}') 12 | echo -e "${CYAN}当前安装的sing-box版本为:${NC} $current_version" 13 | 14 | stable_version=$(apt-cache policy sing-box | grep Candidate | awk '{print $2}') 15 | beta_version=$(apt-cache policy sing-box-beta | grep Candidate | awk '{print $2}') 16 | 17 | echo -e "${CYAN}稳定版最新版本:${NC} $stable_version" 18 | echo -e "${CYAN}测试版最新版本:${NC} $beta_version" 19 | 20 | while true; do 21 | read -rp "是否切换版本(1: 稳定版, 2: 测试版) (当前版本: $current_version, 回车取消操作): " switch_choice 22 | case $switch_choice in 23 | 1) 24 | echo "下载稳定版..." 25 | apt-get download sing-box 26 | sudo apt-get remove --auto-remove sing-box-beta -y 27 | sudo dpkg -i sing-box_*.deb 28 | rm -f sing-box_*.deb 29 | break 30 | ;; 31 | 2) 32 | echo "下载测试版..." 33 | apt-get download sing-box-beta 34 | sudo apt-get remove --auto-remove sing-box -y 35 | sudo dpkg -i sing-box-beta_*.deb 36 | rm -f sing-box-beta_*.deb 37 | break 38 | ;; 39 | '') 40 | echo "不进行版本切换" 41 | break 42 | ;; 43 | *) 44 | echo -e "${RED}无效的选择,请输入 1 或 2。${NC}" 45 | ;; 46 | esac 47 | done 48 | else 49 | echo -e "${RED}sing-box 未安装${NC}" 50 | fi 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_request.yml: -------------------------------------------------------------------------------- 1 | name: 错误反馈 2 | description: "提交出现的问题" 3 | body: 4 | - type: dropdown 5 | attributes: 6 | label: 操作系统 7 | description: 请提供操作系统类型 8 | options: 9 | - ubuntu 10 | - debian 11 | - openwrt 12 | validations: 13 | required: true 14 | - type: input 15 | attributes: 16 | label: 系统版本 17 | description: 请提供操作系统版本 18 | validations: 19 | required: true 20 | - type: dropdown 21 | attributes: 22 | label: 安装类型 23 | description: 请提供该 sing-box 安装类型 24 | options: 25 | - sing-box 发行版 26 | - sing-box beta版 27 | - sing-box alpha版 28 | validations: 29 | required: true 30 | - type: textarea 31 | attributes: 32 | label: 描述 33 | description: 请提供错误的详细描述。 34 | validations: 35 | required: true 36 | - type: textarea 37 | attributes: 38 | label: 重现方式 39 | description: 请提供重现错误的步骤,必须包括可以在本地(不依赖与远程服务器)使用 sing-box 原始命令行程序重现错误的配置文件与流程。 40 | validations: 41 | required: true 42 | - type: textarea 43 | attributes: 44 | label: 日志 45 | description: |- 46 | 请提供完整的 sing-box 日志,必须包括可以在本地(不依赖与远程服务器)使用 sing-box 原始命令行程序重现错误的配置文件与流程。 47 | 如果日志过长,请使用 [gist](https://gist.github.com/) 或者 [pastebin](https://pastebin.com/) 等服务上传,并在下面提供链接。 48 | render: shell 49 | - type: checkboxes 50 | attributes: 51 | label: 完整性要求 52 | description: |- 53 | 请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。 54 | sing-box 不是讨好无法作出任何意义上的贡献的最终用户并获取非道德影响力的项目,如果您在此处欺骗以故意浪费开发者的时间,您将被永久封锁。 55 | options: 56 | - label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。 57 | required: true 58 | - label: 我保证提供了可用于重现我报告的错误的最简配置,或尝试使用了样本配置。 59 | required: true 60 | - label: 我保证提供了完整的配置文件与日志,而不是出于对自身智力的自信而仅提供了部分认为有用的部分。 61 | required: true -------------------------------------------------------------------------------- /openwrt/manage_autostart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | GREEN='\033[0;32m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | echo -e "${GREEN}设置开机自启动...${NC}" 9 | echo "请选择操作(1: 启用自启动, 2: 禁用自启动)" 10 | read -rp "(1/2): " autostart_choice 11 | 12 | apply_firewall() { 13 | MODE=$(grep -oP '(?<=^MODE=).*' /etc/sing-box/mode.conf) 14 | if [ "$MODE" = "TProxy" ]; then 15 | echo "应用 TProxy 模式下的防火墙规则..." 16 | bash /etc/sing-box/scripts/configure_tproxy.sh 17 | elif [ "$MODE" = "TUN" ]; then 18 | echo "应用 TUN 模式下的防火墙规则..." 19 | bash /etc/sing-box/scripts/configure_tun.sh 20 | else 21 | echo "无效的模式,跳过防火墙规则应用。" 22 | exit 1 23 | fi 24 | } 25 | 26 | case $autostart_choice in 27 | 1) 28 | # 检查自启动是否已经开启 29 | if [ -f /etc/rc.d/S99sing-box ]; then 30 | echo -e "${GREEN}自启动已经开启,无需操作。${NC}" 31 | exit 0 # 返回主菜单 32 | fi 33 | 34 | echo -e "${GREEN}启用自启动...${NC}" 35 | 36 | # 启用并启动服务 37 | /etc/init.d/sing-box enable 38 | /etc/init.d/sing-box start 39 | cmd_status=$? 40 | 41 | if [ "$cmd_status" -eq 0 ]; then 42 | echo -e "${GREEN}自启动已成功启用。${NC}" 43 | else 44 | echo -e "${RED}启用自启动失败。${NC}" 45 | fi 46 | ;; 47 | 2) 48 | # 检查自启动是否已经禁用 49 | if [ ! -f /etc/rc.d/S99sing-box ]; then 50 | echo -e "${GREEN}自启动已经禁用,无需操作。${NC}" 51 | exit 0 # 返回主菜单 52 | fi 53 | 54 | echo -e "${RED}禁用自启动...${NC}" 55 | 56 | # 禁用并停止服务 57 | /etc/init.d/sing-box disable 58 | cmd_status=$? 59 | 60 | if [ "$cmd_status" -eq 0 ]; then 61 | echo -e "${GREEN}自启动已成功禁用。${NC}" 62 | else 63 | echo -e "${RED}禁用自启动失败。${NC}" 64 | fi 65 | ;; 66 | *) 67 | echo -e "${RED}无效的选择${NC}" 68 | ;; 69 | esac 70 | 71 | # 调用应用防火墙规则的函数 72 | if [ "$1" = "apply_firewall" ]; then 73 | apply_firewall 74 | fi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sbshell 2 | ⚠️⚠️请注意禁止搬运到中国大陆,请遵守属地法律法律⚠️⚠️ 3 | Sbshell 是一款针对 官方sing-box 的辅助运行脚本,旨在让官方sing-box更方便使用: 4 | 5 | - **系统支持**:支持系统为Debian/Ubuntu/Armbian以及OpenWrt。 6 | - **客户端运行**:客户端保持 sing-box 以官方裸核形式运行,追求极致精简与性能。 7 | - **服务端运行**:支持服务端配置搭建使用,使用方法自行google油管教程和翻阅sing-box官方文档。 8 | - **双模支持**:兼容 TUN 和 TProxy 模式,可随时一键切换,灵活适应不同需求。 9 | - **版本管理**:支持一键切换稳定版与测试版内核,检测并更新至最新版本,操作简单高效。 10 | - **灵活配置**:支持手动输入后端地址、订阅链接、配置文件链接,并可设置默认值,提升使用效率。 11 | - **订阅管理**:支持手动更新、定时自动更新,确保订阅和配置始终保持最新。 12 | - **启动控制**:支持手动启动、停止和开机自启管理,操作直观。 13 | - **网络配置**:内置网络配置模块,可快速修改系统 IP、网关和 DNS,自动提示是否需要调整。 14 | - **便捷命令**:集成常用命令,避免手动查找与复制的繁琐。 15 | - **在线更新**:支持脚本在线更新,始终保持最新版本。 16 | - **面板更新**:支持clash系面板在线更新/切换。 17 | 18 | 19 | ## 设备支持: 20 | 21 | 目前支持系统为deiban/ubuntu/armbian以及openwrt! 22 | 23 | ## 一键脚本:(请自行安装curl和bash,如果缺少的话) 24 | ``` 25 | bash <(curl -sL https://ghfast.top/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/sbshall.sh) 26 | ``` 27 | - 初始化运行结束,输入“**sb**”进入菜单 28 | - 目前支持系统为deiban/ubuntu/armbian/openwrt。 29 | - 防火墙仅支持nftables,不支持iptables。 30 | - 非openwrt并使用2.1.2之前版本的用户想要升级并且使用1.12.X版本内核建议卸载重装 31 | 32 | ### 系统信息自动显示美化脚本: 33 | ``` 34 | bash <(curl -sL https://gh-proxy.com/https://raw.githubusercontent.com/qljsyph/DPInfo-script/refs/heads/main/auto-sysinfo.sh) 35 | ``` 36 | 执行后每次进入ssh会自动显示很多必要信息! 37 | 仓库: 38 | https://github.com/qljsyph/DPInfo-script 39 | 40 | ## 适配配置文件: 41 | 42 | ### 发行版1.12: 43 | fakeiptrpoxy: 44 | https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/config_template/config_fakeiptrpoxy12.json 45 | 46 | fakeiptun: 47 | https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/config_template/config_fakeiptun12.json 48 | 49 | tproxy: 50 | https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/config_template/config_trpoxy12.json 51 | 52 | ### 发行版1.11:   53 | tproxy: 54 | https://gh-proxy.com/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/config_template/config_tproxy.json 55 | 56 | tun: 57 | https://gh-proxy.com/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/config_template/config_tun.json   58 | 59 | ## 其他问题: 60 | 61 | **请查看[wiki](https://github.com/qljsyph/sbshell/wiki)** 62 | **网络优化功能不懂的不要使用会影响游戏性** 63 | 64 | 65 | -------------------------------------------------------------------------------- /debian/set_network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | GREEN='\033[0;32m' 5 | RED='\033[0;31m' 6 | YELLOW='\033[1;33m' 7 | NC='\033[0m' # 无颜色 8 | 9 | # 捕获 Ctrl+C 信号并处理 10 | trap 'echo -e "\n${RED}操作已取消,返回到网络设置菜单。${NC}"; exit 1' SIGINT 11 | 12 | # 获取当前系统的 IP 地址、网关和 DNS 13 | CURRENT_IP=$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}') 14 | CURRENT_GATEWAY=$(ip route show default | awk '{print $3}') 15 | CURRENT_DNS=$(grep 'nameserver' /etc/resolv.conf | awk '{print $2}') 16 | 17 | echo -e "${YELLOW}当前 IP 地址: $CURRENT_IP${NC}" 18 | echo -e "${YELLOW}当前网关地址: $CURRENT_GATEWAY${NC}" 19 | echo -e "${YELLOW}当前 DNS 服务器: $CURRENT_DNS${NC}" 20 | 21 | # 获取网卡名称 22 | INTERFACE=$(ip -br link show | awk '{print $1}' | grep -v "lo" | head -n 1) 23 | [ -z "$INTERFACE" ] && { echo -e "${RED}未找到网络接口,程序退出。${NC}"; exit 1; } 24 | 25 | echo -e "${YELLOW}检测到的网络接口是: $INTERFACE${NC}" 26 | 27 | while true; do 28 | # 提示用户输入静态 IP 地址、网关和 DNS 29 | read -rp "请输入静态 IP 地址: " IP_ADDRESS 30 | read -rp "请输入网关地址: " GATEWAY 31 | read -rp "请输入 DNS 服务器地址 (多个地址用空格分隔): " DNS_SERVERS 32 | 33 | echo -e "${YELLOW}你输入的配置信息如下:${NC}" 34 | echo -e "IP 地址: $IP_ADDRESS" 35 | echo -e "网关地址: $GATEWAY" 36 | echo -e "DNS 服务器: $DNS_SERVERS" 37 | 38 | read -rp "是否确认上述配置信息? (y/n): " confirm_choice 39 | if [[ "$confirm_choice" =~ ^[Yy]$ ]]; then 40 | # 配置文件路径 41 | INTERFACES_FILE="/etc/network/interfaces" 42 | RESOLV_CONF_FILE="/etc/resolv.conf" 43 | 44 | # 更新网络配置 45 | cat > $INTERFACES_FILE < $RESOLV_CONF_FILE 60 | for dns in $DNS_SERVERS; do 61 | echo "nameserver $dns" >> $RESOLV_CONF_FILE 62 | done 63 | 64 | # 重启网络服务 65 | sudo systemctl restart networking 66 | 67 | # 输出配置结果 68 | echo -e "${GREEN}静态 IP 地址和 DNS 配置完成!${NC}" 69 | break 70 | else 71 | echo -e "${RED}请重新输入配置信息。${NC}" 72 | fi 73 | done 74 | -------------------------------------------------------------------------------- /debian/start_singbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | MAGENTA='\033[0;35m' 7 | RED='\033[0;31m' 8 | NC='\033[0m' # 无颜色 9 | 10 | # 脚本下载目录 11 | SCRIPT_DIR="/etc/sing-box/scripts" 12 | 13 | # 检查当前模式 14 | check_mode() { 15 | if nft list chain inet sing-box prerouting_tproxy &>/dev/null || nft list chain inet sing-box output_tproxy &>/dev/null; then 16 | echo "TProxy 模式" 17 | else 18 | echo "TUN 模式" 19 | fi 20 | } 21 | 22 | # 应用防火墙规则 23 | apply_firewall() { 24 | MODE=$(grep -oP '(?<=^MODE=).*' /etc/sing-box/mode.conf) 25 | if [ "$MODE" = "TProxy" ]; then 26 | bash "$SCRIPT_DIR/configure_tproxy.sh" 27 | elif [ "$MODE" = "TUN" ]; then 28 | bash "$SCRIPT_DIR/configure_tun.sh" 29 | fi 30 | } 31 | 32 | # 启动 sing-box 服务 33 | start_singbox() { 34 | echo -e "${CYAN}检测是否处于非代理环境...${NC}" 35 | STATUS_CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "https://www.google.com") 36 | 37 | if [ "$STATUS_CODE" -eq 200 ]; then 38 | echo -e "${RED}当前网络处于代理环境, 启动 sing-box 需要直连, 请设置!${NC}" 39 | read -rp "是否执行网络设置脚本(暂只支持debian)?(y/n/skip): " network_choice 40 | if [[ "$network_choice" =~ ^[Yy]$ ]]; then 41 | bash "$SCRIPT_DIR/set_network.sh" 42 | STATUS_CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "https://www.google.com") 43 | if [ "$STATUS_CODE" -eq 200 ]; then 44 | echo -e "${RED}网络配置更改后依然处于代理环境,请检查网络配置!${NC}" 45 | exit 1 46 | fi 47 | elif [[ "$network_choice" =~ ^[Ss]kip$ ]]; then 48 | echo -e "${CYAN}跳过网络检查,直接启动 sing-box。${NC}" 49 | else 50 | echo -e "${RED}请切换到非代理环境后再启动 sing-box。${NC}" 51 | exit 1 52 | fi 53 | else 54 | echo -e "${CYAN}当前网络环境非代理网络,可以启动 sing-box。${NC}" 55 | fi 56 | 57 | sudo systemctl restart sing-box &>/dev/null 58 | 59 | apply_firewall 60 | 61 | if systemctl is-active --quiet sing-box; then 62 | echo -e "${GREEN}sing-box 启动成功${NC}" 63 | mode=$(check_mode) 64 | echo -e "${MAGENTA}当前启动模式: ${mode}${NC}" 65 | else 66 | echo -e "${RED}sing-box 启动失败,请检查日志${NC}" 67 | fi 68 | } 69 | 70 | # 提示用户确认是否启动 71 | read -rp "是否启动 sing-box?(y/n): " confirm_start 72 | if [[ "$confirm_start" =~ ^[Yy]$ ]]; then 73 | start_singbox 74 | else 75 | echo -e "${CYAN}已取消启动 sing-box。${NC}" 76 | exit 0 77 | fi 78 | -------------------------------------------------------------------------------- /debian/optimize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # ===== 时间同步 ===== 5 | if ! command -v chronyd >/dev/null 2>&1; then 6 | apt-get update && apt-get install -y chrony 7 | fi 8 | if ! systemctl is-active --quiet chronyd; then 9 | systemctl enable --now chronyd 10 | fi 11 | timedatectl set-timezone Asia/Shanghai 2>/dev/null || true 12 | 13 | # ===== 文件描述符限制 ===== 14 | echo "1048576" > /proc/sys/fs/file-max 15 | ulimit -n 1048576 16 | 17 | # ===== 内核参数优化 ===== 18 | chattr -i /etc/sysctl.conf 19 | cat > /etc/sysctl.conf << EOF 20 | # ====== 内存管理 ====== 21 | vm.swappiness = 5 22 | vm.dirty_ratio = 10 23 | vm.dirty_background_ratio = 5 24 | 25 | # ====== 文件描述符与连接数限制 ====== 26 | fs.file-max = 1048576 27 | net.core.somaxconn = 32768 28 | net.ipv4.tcp_max_syn_backlog = 65536 29 | 30 | # ====== 网络缓冲区调优 ====== 31 | net.core.rmem_max = 67108864 32 | net.core.wmem_max = 67108864 33 | net.core.optmem_max = 8388608 34 | net.ipv4.tcp_rmem = 4096 87380 67108864 35 | net.ipv4.tcp_wmem = 4096 16384 67108864 36 | net.ipv4.udp_rmem_min = 16384 37 | net.ipv4.udp_wmem_min = 16384 38 | net.core.netdev_max_backlog = 65536 39 | 40 | # ====== TCP低延迟优化 ====== 41 | net.ipv4.tcp_congestion_control = bbr 42 | net.core.default_qdisc = fq 43 | net.ipv4.tcp_low_latency = 1 44 | net.ipv4.tcp_slow_start_after_idle = 0 45 | net.ipv4.tcp_no_metrics_save = 1 46 | net.ipv4.tcp_adv_win_scale = 1 47 | 48 | # ====== TCP连接管理 ====== 49 | net.ipv4.tcp_tw_reuse = 1 50 | net.ipv4.tcp_fin_timeout = 15 51 | net.ipv4.tcp_keepalive_time = 300 52 | net.ipv4.tcp_keepalive_intvl = 30 53 | net.ipv4.tcp_keepalive_probes = 3 54 | net.ipv4.tcp_synack_retries = 2 55 | 56 | # ====== 协议栈特性 ====== 57 | net.ipv4.tcp_fastopen = 3 58 | net.ipv4.tcp_mtu_probing = 1 59 | net.ipv4.tcp_timestamps = 1 60 | net.ipv4.tcp_sack = 1 61 | net.ipv4.tcp_rfc1337 = 1 62 | 63 | # ====== 路由与转发 ====== 64 | net.ipv4.ip_forward = 1 65 | net.ipv4.conf.all.rp_filter = 1 66 | net.ipv6.conf.all.forwarding = 1 67 | 68 | EOF 69 | 70 | # 应用内核参数 71 | sysctl -p 72 | 73 | # ===== 安全限制配置 ===== 74 | # 设置用户/进程资源限制 75 | cat > /etc/security/limits.conf << EOF 76 | # 文件描述符限制 77 | * soft nofile 1048576 78 | * hard nofile 1048576 79 | 80 | # 进程数限制 81 | * soft nproc 65535 82 | * hard nproc 65535 83 | 84 | # 内存锁定 85 | * soft memlock unlimited 86 | * hard memlock unlimited 87 | 88 | # Core dump大小 89 | * soft core unlimited 90 | * hard core unlimited 91 | 92 | # root用户专属限制 93 | root soft nofile 1048576 94 | root hard nofile 1048576 95 | root soft nproc 65535 96 | root hard nproc 65535 97 | root soft memlock unlimited 98 | root hard memlock unlimited 99 | root soft core unlimited 100 | root hard core unlimited 101 | EOF 102 | 103 | # 应用安全限制 104 | ulimit -n 1048576 # 打开文件数 105 | ulimit -u 65535 # 用户进程数 106 | ulimit -l unlimited # 锁定内存 107 | ulimit -c unlimited # Core dumps -------------------------------------------------------------------------------- /debian/ufw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | RED='\033[0;31m' 7 | YELLOW='\033[1;33m' 8 | NC='\033[0m' 9 | 10 | # --- 非交互式/自动模式 --- 11 | if [ "$1" == "--auto" ]; then 12 | # 确保 UFW 已安装 13 | if ! command -v ufw &>/dev/null; then 14 | sudo apt-get update >/dev/null 2>&1 15 | sudo apt-get install -y ufw >/dev/null 2>&1 16 | fi 17 | # 应用基本规则 18 | sudo ufw default deny incoming >/dev/null 19 | sudo ufw default allow outgoing >/dev/null 20 | sudo ufw allow ssh >/dev/null 21 | sudo ufw allow http >/dev/null 22 | sudo ufw allow https >/dev/null 23 | # 强制启用 24 | sudo ufw --force enable >/dev/null 25 | exit 0 26 | fi 27 | 28 | # --- 交互式模式 --- 29 | 30 | # 1. 更新和安装 31 | echo -e "${CYAN}正在更新软件包列表...${NC}" 32 | sudo apt-get update >/dev/null 2>&1 33 | 34 | if ! command -v ufw &>/dev/null; then 35 | echo -e "${CYAN}正在安装 UFW 防火墙...${NC}" 36 | if sudo apt-get install -y ufw >/dev/null 2>&1; then 37 | echo -e "${GREEN}UFW 安装成功。${NC}" 38 | else 39 | echo -e "${RED}UFW 安装失败!请检查 apt 源或手动安装。${NC}" 40 | exit 1 41 | fi 42 | else 43 | echo -e "${GREEN}UFW 已安装,跳过安装步骤。${NC}" 44 | fi 45 | 46 | # 2. 手动放行端口 47 | echo -e "\n${CYAN}请输入需要放行的端口(支持多个,用空格或英文逗号分隔):${NC}" 48 | read -rp "要放行的端口: " ports_input 49 | 50 | # 处理输入,替换逗号为空格 51 | ports=$(echo "$ports_input" | tr ',' ' ') 52 | 53 | if [ -n "$ports" ]; then 54 | for port in $ports; do 55 | if [[ "$port" =~ ^[0-9]+$ ]]; then 56 | sudo ufw allow "$port"/tcp >/dev/null 57 | sudo ufw allow "$port"/udp >/dev/null 58 | echo -e "${GREEN}已放行端口 $port (TCP/UDP)。${NC}" 59 | else 60 | echo -e "${YELLOW}已跳过无效输入: $port${NC}" 61 | fi 62 | done 63 | else 64 | echo -e "${YELLOW}未输入任何端口,跳过此步骤。${NC}" 65 | fi 66 | 67 | # 3. 启用 UFW 68 | echo -e "\n${CYAN}正在启用 UFW 防火墙...${NC}" 69 | sudo ufw --force enable >/dev/null 70 | 71 | # 4. 修改 SSH 端口 (可选) 72 | echo -e "\n${CYAN}是否需要修改 SSH 端口?(y/n)${NC}" 73 | read -rp "选择 [n]: " ssh_modify 74 | 75 | if [[ "$ssh_modify" =~ ^[Yy]$ ]]; then 76 | read -rp "请输入新的 SSH 端口 (1025-65535): " new_ssh_port 77 | if [[ "$new_ssh_port" =~ ^[0-9]+$ ]] && [ "$new_ssh_port" -gt 1024 ] && [ "$new_ssh_port" -le 65535 ]; then 78 | # 修改 sshd_config 79 | sudo sed -i "s/^#*Port .*/Port $new_ssh_port/" /etc/ssh/sshd_config 80 | echo -e "${GREEN}SSH 配置文件已更新为端口 $new_ssh_port。${NC}" 81 | 82 | # 在防火墙中允许新端口 83 | sudo ufw allow "$new_ssh_port"/tcp >/dev/null 84 | echo -e "${GREEN}防火墙已放行新 SSH 端口 $new_ssh_port。${NC}" 85 | 86 | # 重启 SSH 服务 87 | sudo systemctl restart sshd 88 | echo -e "${GREEN}SSH 服务已重启,新端口已生效。${NC}" 89 | echo -e "${YELLOW}请记得使用新端口 ($new_ssh_port) 重新连接!${NC}" 90 | else 91 | echo -e "${RED}端口输入无效,未修改 SSH 端口。${NC}" 92 | fi 93 | else 94 | echo -e "${CYAN}未修改 SSH 端口。${NC}" 95 | fi 96 | 97 | echo -e "\n${GREEN}UFW 防火墙配置完成。${NC}" 98 | -------------------------------------------------------------------------------- /openwrt/manual_input.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | # 手动输入的配置文件 9 | MANUAL_FILE="/etc/sing-box/manual.conf" 10 | DEFAULTS_FILE="/etc/sing-box/defaults.conf" 11 | 12 | # 获取当前模式 13 | MODE=$(grep -E '^MODE=' /etc/sing-box/mode.conf | sed 's/^MODE=//') 14 | 15 | prompt_user_input() { 16 | read -rp "请输入后端地址(回车使用默认值可留空): " BACKEND_URL 17 | if [ -z "$BACKEND_URL" ]; then 18 | BACKEND_URL=$(grep BACKEND_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 19 | echo -e "${CYAN}使用默认后端地址: $BACKEND_URL${NC}" 20 | fi 21 | 22 | read -rp "请输入订阅地址(回车使用默认值可留空): " SUBSCRIPTION_URL 23 | if [ -z "$SUBSCRIPTION_URL" ]; then 24 | SUBSCRIPTION_URL=$(grep SUBSCRIPTION_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 25 | echo -e "${CYAN}使用默认订阅地址: $SUBSCRIPTION_URL${NC}" 26 | fi 27 | 28 | read -rp "请输入配置文件地址(回车使用默认值可留空): " TEMPLATE_URL 29 | if [ -z "$TEMPLATE_URL" ]; then 30 | if [ "$MODE" = "TProxy" ]; then 31 | TEMPLATE_URL=$(grep TPROXY_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 32 | echo -e "${CYAN}使用默认 TProxy 配置文件地址: $TEMPLATE_URL${NC}" 33 | elif [ "$MODE" = "TUN" ]; then 34 | TEMPLATE_URL=$(grep TUN_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 35 | echo -e "${CYAN}使用默认 TUN 配置文件地址: $TEMPLATE_URL${NC}" 36 | else 37 | echo -e "${RED}未知的模式: $MODE${NC}" 38 | exit 1 39 | fi 40 | fi 41 | } 42 | 43 | while true; do 44 | prompt_user_input 45 | 46 | echo -e "${CYAN}你输入的配置信息如下:${NC}" 47 | echo "后端地址: $BACKEND_URL" 48 | echo "订阅地址: $SUBSCRIPTION_URL" 49 | echo "配置文件地址: $TEMPLATE_URL" 50 | 51 | read -rp "确认输入的配置信息?(y/n): " confirm_choice 52 | if [[ "$confirm_choice" =~ ^[Yy]$ ]]; then 53 | # 更新手动输入的配置文件 54 | cat > "$MANUAL_FILE" </dev/null | cut -d'=' -f2-) 20 | echo -e "${CYAN}使用默认后端地址: $BACKEND_URL${NC}" 21 | fi 22 | 23 | read -rp "请输入订阅地址(回车使用默认值可留空): " SUBSCRIPTION_URL 24 | if [ -z "$SUBSCRIPTION_URL" ]; then 25 | SUBSCRIPTION_URL=$(grep SUBSCRIPTION_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 26 | echo -e "${CYAN}使用默认订阅地址: $SUBSCRIPTION_URL${NC}" 27 | fi 28 | 29 | read -rp "请输入配置文件地址(回车使用默认值可留空): " TEMPLATE_URL 30 | if [ -z "$TEMPLATE_URL" ]; then 31 | if [ "$MODE" = "TProxy" ]; then 32 | TEMPLATE_URL=$(grep TPROXY_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 33 | echo -e "${CYAN}使用默认 TProxy 配置文件地址: $TEMPLATE_URL${NC}" 34 | elif [ "$MODE" = "TUN" ]; then 35 | TEMPLATE_URL=$(grep TUN_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 36 | echo -e "${CYAN}使用默认 TUN 配置文件地址: $TEMPLATE_URL${NC}" 37 | else 38 | echo -e "${RED}未知的模式: $MODE${NC}" 39 | exit 1 40 | fi 41 | fi 42 | } 43 | 44 | while true; do 45 | prompt_user_input 46 | 47 | # 显示用户输入的配置信息 48 | echo -e "${CYAN}你输入的配置信息如下:${NC}" 49 | echo "后端地址: $BACKEND_URL" 50 | echo "订阅地址: $SUBSCRIPTION_URL" 51 | echo "配置文件地址: $TEMPLATE_URL" 52 | 53 | read -rp "确认输入的配置信息?(y/n): " confirm_choice 54 | if [[ "$confirm_choice" =~ ^[Yy]$ ]]; then 55 | # 更新手动输入的配置文件 56 | cat > "$MANUAL_FILE" < /etc/sing-box/update-singbox.sh </dev/null | grep -v '/etc/sing-box/update-singbox.sh' | crontab - 68 | echo "已删除旧的自动更新任务。" 69 | else 70 | echo -e "${CYAN}保持已有的自动更新任务。返回菜单。${NC}" 71 | exit 0 72 | fi 73 | fi 74 | 75 | 76 | (crontab -l 2>/dev/null; echo "0 */$interval_choice * * * /etc/sing-box/update-singbox.sh") | crontab - 77 | /etc/init.d/cron restart 78 | 79 | echo "定时更新任务已设置,每 $interval_choice 小时执行一次" 80 | break 81 | 82 | elif [[ "$menu_choice" == "2" ]]; then 83 | # 取消自动更新任务 84 | if crontab -l 2>/dev/null | grep -q '/etc/sing-box/update-singbox.sh'; then 85 | crontab -l 2>/dev/null | grep -v '/etc/sing-box/update-singbox.sh' | crontab - 86 | /etc.init.d/cron restart 87 | echo -e "${CYAN}自动更新任务已取消。${NC}" 88 | else 89 | echo -e "${CYAN}没有找到自动更新任务。${NC}" 90 | fi 91 | break 92 | 93 | else 94 | echo -e "${RED}输入无效, 请输入1或2。${NC}" 95 | fi 96 | done 97 | -------------------------------------------------------------------------------- /debian/auto_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | # 手动输入的配置文件 9 | MANUAL_FILE="/etc/sing-box/manual.conf" 10 | 11 | # 创建定时更新脚本 12 | cat > /etc/sing-box/update-singbox.sh </dev/null | grep -v '/etc/sing-box/update-singbox.sh' | crontab - 69 | echo "已删除旧的自动更新任务。" 70 | else 71 | echo -e "${CYAN}保持已有的自动更新任务。返回菜单。${NC}" 72 | exit 0 73 | fi 74 | fi 75 | 76 | # 添加新的定时任务 77 | (crontab -l 2>/dev/null; echo "0 */$interval_choice * * * /etc/sing-box/update-singbox.sh") | crontab - 78 | systemctl restart cron 79 | 80 | echo "定时更新任务已设置,每 $interval_choice 小时执行一次" 81 | break 82 | 83 | elif [[ "$menu_choice" == "2" ]]; then 84 | # 取消自动更新任务 85 | if crontab -l 2>/dev/null | grep -q '/etc/sing-box/update-singbox.sh'; then 86 | crontab -l 2>/dev/null | grep -v '/etc/sing-box/update-singbox.sh' | crontab - 87 | systemctl restart cron 88 | echo -e "${CYAN}自动更新任务已取消。${NC}" 89 | else 90 | echo -e "${CYAN}没有找到自动更新任务。${NC}" 91 | fi 92 | break 93 | 94 | else 95 | echo -e "${RED}输入无效, 请输入1或2。${NC}" 96 | fi 97 | done 98 | -------------------------------------------------------------------------------- /debian/kernel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 本脚本用于添加 XanMod 内核仓库,获取必要的 GPG 密钥, 4 | # 检测 CPU 指令集,安装合适的 XanMod 内核版本,并重启系统。 5 | 6 | set -euo pipefail 7 | 8 | # 错误处理函数 9 | error() { 10 | echo "错误: $1" >&2 11 | exit 1 12 | } 13 | 14 | # 确保以 root 用户运行脚本 15 | if [ "$(id -u)" -ne 0 ]; then 16 | error "必须以 root 用户运行此脚本。" 17 | fi 18 | 19 | # 更新软件包列表 20 | echo "正在更新软件包列表..." 21 | apt update || error "更新软件包列表失败。" 22 | 23 | # 安装必要工具(gpg 和 curl) 24 | for cmd in gpg curl; do 25 | if ! command -v "$cmd" >/dev/null 2>&1; then 26 | echo "正在安装 $cmd..." 27 | apt install "$cmd" -y || error "安装 $cmd 失败。" 28 | fi 29 | done 30 | 31 | # 确保密钥环目录存在 32 | KEYRING_DIR="/etc/apt/keyrings" 33 | mkdir -p "$KEYRING_DIR" 34 | 35 | # 定义 XanMod 的 GPG 密钥 URL 和密钥环文件路径 36 | XANMOD_KEY_URL="https://dl.xanmod.org/archive.key" 37 | XANMOD_KEYRING="$KEYRING_DIR/xanmod-archive-keyring.gpg" 38 | 39 | # 方法一:使用 gpg 参数抑制提示 40 | echo "使用 gpg 参数添加 XanMod GPG 密钥..." 41 | if ! curl -fsSL "$XANMOD_KEY_URL" | gpg --batch --yes --dearmor -o "$XANMOD_KEYRING"; then 42 | echo "使用 gpg 参数添加 GPG 密钥失败,尝试方法二..." 43 | 44 | # 方法二:写入前先删除已有密钥环文件 45 | rm -f "$XANMOD_KEYRING" 46 | if ! curl -fsSL "$XANMOD_KEY_URL" | gpg --dearmor -o "$XANMOD_KEYRING"; then 47 | error "使用两种方法均无法从 $XANMOD_KEY_URL 添加 GPG 密钥。" 48 | fi 49 | fi 50 | 51 | # 定义仓库列表文件和仓库条目 52 | REPO_LIST="/etc/apt/sources.list.d/xanmod-release.list" 53 | REPO_ENTRY="deb [signed-by=$XANMOD_KEYRING] http://deb.xanmod.org releases main" 54 | 55 | # 检查仓库是否已添加 56 | if [ ! -f "$REPO_LIST" ] || ! grep -Fxq "$REPO_ENTRY" "$REPO_LIST"; then 57 | echo "正在添加 XanMod 仓库..." 58 | echo "$REPO_ENTRY" | tee "$REPO_LIST" >/dev/null 59 | else 60 | echo "XanMod 仓库已存在。" 61 | fi 62 | 63 | # 更新软件包列表以包含新仓库 64 | echo "正在更新软件包列表(包括 XanMod 仓库)..." 65 | apt update || error "添加仓库后更新软件包列表失败。" 66 | 67 | # 检测 CPU 指令集 68 | echo "正在检测 CPU 指令集..." 69 | cpu_flags=$(grep -o -w -E 'lm|cmov|cx8|fpu|fxsr|mmx|syscall|sse2|cx16|lahf|popcnt|sse4_1|sse4_2|ssse3|avx|avx2|bmi1|bmi2|f16c|fma|abm|movbe|xsave|avx512f|avx512bw|avx512cd|avx512dq|avx512vl' /proc/cpuinfo | sort -u | tr '\n' ' ') 70 | echo "检测到的 CPU 标志: $cpu_flags" 71 | 72 | # 检查是否包含所有所需指令集的函数 73 | has_flags() { 74 | local flags="$1" 75 | for flag in $flags; do 76 | [[ "$cpu_flags" =~ $flag ]] || return 1 77 | done 78 | return 0 79 | } 80 | 81 | # 根据指令集判断 CPU 级别 82 | if has_flags "avx512f avx512bw avx512cd avx512dq avx512vl"; then 83 | level=4 84 | elif has_flags "avx avx2 bmi1 bmi2 f16c fma abm movbe xsave"; then 85 | level=3 86 | elif has_flags "cx16 lahf popcnt sse4_1 sse4_2 ssse3"; then 87 | level=2 88 | elif has_flags "lm cmov cx8 fpu fxsr mmx syscall sse2"; then 89 | level=1 90 | else 91 | error "无法根据 CPU 指令集确定合适的 XanMod 内核版本。" 92 | fi 93 | 94 | echo "检测到的 CPU 级别: $level" 95 | 96 | # 根据 CPU 级别设置内核包名称 97 | case "$level" in 98 | 1) 99 | kernel_package="linux-xanmod-lts-x64v1" 100 | ;; 101 | 2) 102 | kernel_package="linux-xanmod-lts-x64v2" 103 | ;; 104 | 3) 105 | kernel_package="linux-xanmod-lts-x64v3" 106 | ;; 107 | 4) 108 | kernel_package="linux-xanmod-lts-x64v4" 109 | ;; 110 | *) 111 | error "无效的 CPU 级别: $level" 112 | ;; 113 | esac 114 | 115 | # 安装合适的 XanMod 内核 116 | echo "正在安装 $kernel_package..." 117 | apt install "$kernel_package" -y || error "安装 $kernel_package 失败。" 118 | 119 | # 提示系统重启 120 | echo "系统将在 10 秒后重启,按 Ctrl+C 可取消。" 121 | for i in {10..1}; do 122 | echo "$i..." 123 | sleep 1 124 | done 125 | echo "现在重启系统!" 126 | reboot -------------------------------------------------------------------------------- /debian/manage_autostart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | GREEN='\033[0;32m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | echo -e "${GREEN}设置开机自启动...${NC}" 9 | echo "请选择操作(1: 启用自启动, 2: 禁用自启动)" 10 | read -rp "(1/2): " autostart_choice 11 | 12 | apply_firewall() { 13 | MODE=$(grep -oP '(?<=^MODE=).*' /etc/sing-box/mode.conf) 14 | if [ "$MODE" = "TProxy" ]; then 15 | echo "应用 TProxy 模式下的防火墙规则..." 16 | bash /etc/sing-box/scripts/configure_tproxy.sh 17 | elif [ "$MODE" = "TUN" ]; then 18 | echo "应用 TUN 模式下的防火墙规则..." 19 | bash /etc/sing-box/scripts/configure_tun.sh 20 | else 21 | echo "无效的模式,跳过防火墙规则应用。" 22 | exit 1 23 | fi 24 | } 25 | 26 | case $autostart_choice in 27 | 1) 28 | # 检查自启动是否已经开启 29 | if systemctl is-enabled sing-box.service >/dev/null 2>&1 && systemctl is-enabled nftables-singbox.service >/dev/null 2>&1; then 30 | echo -e "${GREEN}自启动已经开启,无需操作。${NC}" 31 | exit 0 # 返回主菜单 32 | fi 33 | 34 | echo -e "${GREEN}启用自启动...${NC}" 35 | 36 | # 删除旧的配置文件以避免重复配置 37 | sudo rm -f /etc/systemd/system/nftables-singbox.service 38 | 39 | # 创建 nftables-singbox.service 文件 40 | sudo bash -c 'cat > /etc/systemd/system/nftables-singbox.service </dev/null 2>&1 && ! systemctl is-enabled nftables-singbox.service >/dev/null 2>&1; then 78 | echo -e "${GREEN}自启动已经禁用,无需操作。${NC}" 79 | exit 0 # 返回主菜单 80 | fi 81 | 82 | echo -e "${RED}禁用自启动...${NC}" 83 | 84 | # 禁用并停止服务 85 | sudo systemctl disable sing-box.service 86 | sudo systemctl disable nftables-singbox.service 87 | sudo systemctl stop sing-box.service 88 | sudo systemctl stop nftables-singbox.service 89 | 90 | # 删除 nftables-singbox.service 文件 91 | sudo rm -f /etc/systemd/system/nftables-singbox.service 92 | 93 | # 还原 sing-box.service 文件 94 | sudo bash -c "sed -i '/After=nftables-singbox.service/d' /usr/lib/systemd/system/sing-box.service" 95 | sudo bash -c "sed -i '/Requires=nftables-singbox.service/d' /usr/lib/systemd/system/sing-box.service" 96 | 97 | # 重新加载 systemd 98 | sudo systemctl daemon-reload 99 | cmd_status=$? 100 | 101 | if [ "$cmd_status" -eq 0 ]; then 102 | echo -e "${GREEN}自启动已成功禁用。${NC}" 103 | else 104 | echo -e "${RED}禁用自启动失败。${NC}" 105 | fi 106 | ;; 107 | *) 108 | echo -e "${RED}无效的选择${NC}" 109 | ;; 110 | esac 111 | 112 | # 调用应用防火墙规则的函数 113 | if [ "$1" = "apply_firewall" ]; then 114 | apply_firewall 115 | fi 116 | -------------------------------------------------------------------------------- /config_template/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": { 3 | "servers": [ 4 | { 5 | "tag": "google", 6 | "type": "udp", 7 | "server": "8.8.8.8" 8 | }, 9 | { 10 | "tag": "cloudflare", 11 | "type": "udp", 12 | "server": "1.1.1.1" 13 | } 14 | ], 15 | "rules": [ 16 | { 17 | "query_type": "HTTPS", 18 | "action": "reject" 19 | }, 20 | { 21 | "query_type": [ 22 | "A", 23 | "AAAA" 24 | ], 25 | "server": "cloudflare" 26 | } 27 | ], 28 | "final": "cloudflare", 29 | "strategy": "ipv4_only" 30 | }, 31 | "inbounds": [ 32 | { 33 | "tag":"SS", 34 | "type": "shadowsocks", 35 | "listen": "::", 36 | "listen_port": 80, 37 | "method": "2022-blake3-aes-128-gcm", 38 | "password": "hztQCU1ZB8CAuPMVFJiCJw==", 39 | "multiplex": { 40 | "enabled": true 41 | } 42 | }, 43 | { 44 | "tag":"VLESS-Vision-Reality", 45 | "type":"vless", 46 | "listen":"::", 47 | "listen_port":443, 48 | "users":[ 49 | { 50 | "uuid":"625a08bb-d372-4f7c-a2d4-6a50ca3393ce", 51 | "flow":"xtls-rprx-vision" 52 | } 53 | ], 54 | "tls":{ 55 | "enabled":true, 56 | "server_name":"updates.cdn-apple.com", 57 | "reality":{ 58 | "enabled":true, 59 | "handshake":{ 60 | "server":"updates.cdn-apple.com", 61 | "server_port":443 62 | }, 63 | "private_key":"mAQVEs96AtDg1V_b2POFVP8n-Uu6hBe0_1Zt-DtRzGE", 64 | "short_id":[ 65 | "a118b9425a7e2dc5" 66 | ] 67 | } 68 | } 69 | }, 70 | { 71 | "tag": "HYSTERIA2", 72 | "type": "hysteria2", 73 | "listen": "::", 74 | "listen_port": 52021, 75 | "users": [ 76 | { 77 | "password": "c36d52aa-12b0-420c-a409-02f0410f6ac4" 78 | } 79 | ], 80 | "tls": { 81 | "enabled": true, 82 | "alpn": [ 83 | "h3" 84 | ], 85 | "certificate_path": "/etc/ssl/yu.ykszckj.com/yu.ykszckj.com.crt", 86 | "key_path": "/etc/ssl/yu.ykszckj.com/yu.ykszckj.com.key" 87 | } 88 | } 89 | ], 90 | "outbounds": [ 91 | { 92 | "tag": "代理出站", 93 | "type": "selector", 94 | "outbounds": [ 95 | "直接出站" 96 | ] 97 | }, 98 | { 99 | "tag": "直接出站", 100 | "type": "direct" 101 | } 102 | ], 103 | "route": { 104 | "rules": [ 105 | { 106 | "action": "sniff", 107 | "sniffer": [ 108 | "http", 109 | "tls", 110 | "quic", 111 | "dns" 112 | ] 113 | }, 114 | { 115 | "type": "logical", 116 | "mode": "or", 117 | "rules": [ 118 | { 119 | "port": 53 120 | }, 121 | { 122 | "protocol": "dns" 123 | } 124 | ], 125 | "action": "hijack-dns" 126 | }, 127 | { 128 | "ip_is_private": true, 129 | "outbound": "直接出站" 130 | }, 131 | { 132 | "rule_set": "geosite-ai", 133 | "outbound": "代理出站" 134 | } 135 | ], 136 | "rule_set": [ 137 | { 138 | "tag": "geosite-ai", 139 | "type": "remote", 140 | "format": "binary", 141 | "url": "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ai-!cn.srs", 142 | "download_detour": "直接出站" 143 | } 144 | ], 145 | "final": "直接出站", 146 | "auto_detect_interface": true, 147 | "default_domain_resolver": { 148 | "server": "cloudflare" 149 | } 150 | }, 151 | "experimental": { 152 | "cache_file": { 153 | "enabled": true, 154 | "path": "/etc/sing-box/cache.db" 155 | } 156 | }, 157 | "log": { 158 | "disabled": false, 159 | "level": "info", 160 | "timestamp": true 161 | } 162 | } -------------------------------------------------------------------------------- /sbshall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 定义主脚本的下载URL 3 | DEBIAN_MAIN_SCRIPT_URL="https://ghfast.top/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/debian/menu.sh" 4 | OPENWRT_MAIN_SCRIPT_URL="https://gh-proxy.com/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/openwrt/menu.sh" 5 | 6 | # 脚本下载目录 7 | SCRIPT_DIR="/etc/sing-box/scripts" 8 | 9 | # 定义颜色 10 | GREEN='\033[0;32m' 11 | YELLOW='\033[1;33m' 12 | RED='\033[0;31m' 13 | NC='\033[0m' # 无颜色 14 | 15 | # 检查系统是否支持 16 | if [[ "$(uname -s)" != "Linux" ]]; then 17 | echo -e "${RED}当前系统不支持运行此脚本。${NC}" 18 | exit 1 19 | fi 20 | 21 | # 检查发行版并下载相应的主脚本 22 | if grep -qi 'debian\|ubuntu\|armbian' /etc/os-release; then 23 | echo -e "${GREEN}系统为Debian/Ubuntu/Armbian,支持运行此脚本。${NC}" 24 | MAIN_SCRIPT_URL="$DEBIAN_MAIN_SCRIPT_URL" 25 | DEPENDENCIES=("wget" "nftables") 26 | 27 | # 检查 sudo 是否安装 28 | if ! command -v sudo &> /dev/null; then 29 | echo -e "${RED}sudo 未安装。${NC}" 30 | read -rp "是否安装 sudo?(y/n): " install_sudo 31 | if [[ "$install_sudo" =~ ^[Yy]$ ]]; then 32 | apt-get update 33 | apt-get install -y sudo 34 | if ! command -v sudo &> /dev/null; then 35 | echo -e "${RED}安装 sudo 失败,请手动安装 sudo 并重新运行此脚本。${NC}" 36 | exit 1 37 | fi 38 | echo -e "${GREEN}sudo 安装成功。${NC}" 39 | else 40 | echo -e "${RED}由于未安装 sudo,脚本无法继续运行。${NC}" 41 | exit 1 42 | fi 43 | fi 44 | 45 | # 检查并安装缺失的依赖项 46 | for DEP in "${DEPENDENCIES[@]}"; do 47 | if [ "$DEP" == "nftables" ]; then 48 | CHECK_CMD="nft --version" 49 | else 50 | CHECK_CMD="wget --version" 51 | fi 52 | 53 | if ! $CHECK_CMD &> /dev/null; then 54 | echo -e "${RED}$DEP 未安装。${NC}" 55 | read -rp "是否安装 $DEP?(y/n): " install_dep 56 | if [[ "$install_dep" =~ ^[Yy]$ ]]; then 57 | sudo apt-get update 58 | sudo apt-get install -y "$DEP" 59 | if ! $CHECK_CMD &> /dev/null; then 60 | echo -e "${RED}安装 $DEP 失败,请手动安装 $DEP 并重新运行此脚本。${NC}" 61 | exit 1 62 | fi 63 | echo -e "${GREEN}$DEP 安装成功。${NC}" 64 | else 65 | echo -e "${RED}由于未安装 $DEP,脚本无法继续运行。${NC}" 66 | exit 1 67 | fi 68 | fi 69 | done 70 | elif grep -qi 'openwrt' /etc/os-release; then 71 | echo -e "${GREEN}系统为OpenWRT,支持运行此脚本。${NC}" 72 | MAIN_SCRIPT_URL="$OPENWRT_MAIN_SCRIPT_URL" 73 | DEPENDENCIES=("nftables") 74 | 75 | # 检查并安装缺失的依赖项 76 | for DEP in "${DEPENDENCIES[@]}"; do 77 | if [ "$DEP" == "nftables" ]; then 78 | CHECK_CMD="nft --version" 79 | fi 80 | 81 | if ! $CHECK_CMD &> /dev/null; then 82 | echo -e "${RED}$DEP 未安装。${NC}" 83 | read -rp "是否安装 $DEP?(y/n): " install_dep 84 | if [[ "$install_dep" =~ ^[Yy]$ ]]; then 85 | opkg update 86 | opkg install "$DEP" 87 | if ! $CHECK_CMD &> /dev/null; then 88 | echo -e "${RED}安装 $DEP 失败,请手动安装 $DEP 并重新运行此脚本。${NC}" 89 | exit 1 90 | fi 91 | echo -e "${GREEN}$DEP 安装成功。${NC}" 92 | else 93 | echo -e "${RED}由于未安装 $DEP,脚本无法继续运行。${NC}" 94 | exit 1 95 | fi 96 | fi 97 | done 98 | else 99 | echo -e "${RED}当前系统不是Debian/Ubuntu/Armbian/OpenWRT,不支持运行此脚本。${NC}" 100 | exit 1 101 | fi 102 | 103 | # 确保脚本目录存在并设置权限 104 | if grep -qi 'openwrt' /etc/os-release; then 105 | mkdir -p "$SCRIPT_DIR" 106 | else 107 | sudo mkdir -p "$SCRIPT_DIR" 108 | sudo chown "$(whoami)":"$(whoami)" "$SCRIPT_DIR" 109 | fi 110 | 111 | # 下载并执行主脚本 112 | if grep -qi 'openwrt' /etc/os-release; then 113 | curl -s -o "$SCRIPT_DIR/menu.sh" "$MAIN_SCRIPT_URL" 114 | else 115 | wget -q -O "$SCRIPT_DIR/menu.sh" "$MAIN_SCRIPT_URL" 116 | fi 117 | 118 | echo -e "${GREEN}脚本下载中,请耐心等待...${NC}" 119 | echo -e "${YELLOW}注意:安装更新singbox尽量使用代理环境,运行singbox切记关闭代理!${NC}" 120 | 121 | if ! [ -f "$SCRIPT_DIR/menu.sh" ]; then 122 | echo -e "${RED}下载主脚本失败,请检查网络连接。${NC}" 123 | exit 1 124 | fi 125 | 126 | chmod +x "$SCRIPT_DIR/menu.sh" 127 | bash "$SCRIPT_DIR/menu.sh" 128 | -------------------------------------------------------------------------------- /debian/configure_tproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 配置参数 4 | TPROXY_PORT=7895 # 与 sing-box 中定义的一致 5 | ROUTING_MARK=666 # 与 sing-box 中定义的一致 6 | PROXY_FWMARK=1 7 | PROXY_ROUTE_TABLE=100 8 | INTERFACE=$(ip route show default | awk '/default/ {print $5; exit}') 9 | 10 | # 保留 IP 地址集合 11 | ReservedIP4='{ 127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 192.88.99.0/24, 192.168.0.0/16, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32 }' 12 | CustomBypassIP='{ 192.168.0.0/16, 10.0.0.0/8 }' # 自定义绕过的 IP 地址集合 13 | 14 | # 读取当前模式 15 | MODE=$(grep -oP '(?<=^MODE=).*' /etc/sing-box/mode.conf) 16 | 17 | # 检查指定路由表是否存在 18 | check_route_exists() { 19 | ip route show table "$1" >/dev/null 2>&1 20 | return $? 21 | } 22 | 23 | # 创建路由表,如果不存在的话 24 | create_route_table_if_not_exists() { 25 | if ! check_route_exists "$PROXY_ROUTE_TABLE"; then 26 | echo "路由表不存在,正在创建..." 27 | ip route add local default dev "$INTERFACE" table "$PROXY_ROUTE_TABLE" || { echo "创建路由表失败"; exit 1; } 28 | fi 29 | } 30 | 31 | # 等待 FIB 表加载完成 32 | wait_for_fib_table() { 33 | i=1 34 | while [ $i -le 10 ]; do 35 | if ip route show table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1; then 36 | return 0 37 | fi 38 | echo "等待 FIB 表加载中,等待 $i 秒..." 39 | i=$((i + 1)) 40 | done 41 | echo "FIB 表加载失败,超出最大重试次数" 42 | return 1 43 | } 44 | 45 | # 清理现有 sing-box 防火墙规则 46 | clearSingboxRules() { 47 | nft list table inet sing-box >/dev/null 2>&1 && nft delete table inet sing-box 48 | ip rule del fwmark $PROXY_FWMARK lookup $PROXY_ROUTE_TABLE 2>/dev/null 49 | ip route del local default dev "${INTERFACE}" table $PROXY_ROUTE_TABLE 2>/dev/null 50 | echo "清理 sing-box 相关的防火墙规则" 51 | } 52 | 53 | # 仅在 TProxy 模式下应用防火墙规则 54 | if [ "$MODE" = "TProxy" ]; then 55 | echo "应用 TProxy 模式下的防火墙规则..." 56 | 57 | # 创建并确保路由表存在 58 | create_route_table_if_not_exists 59 | 60 | # 等待 FIB 表加载完成 61 | if ! wait_for_fib_table; then 62 | echo "FIB 表准备失败,退出脚本。" 63 | exit 1 64 | fi 65 | 66 | # 清理现有规则 67 | clearSingboxRules 68 | 69 | # 设置 IP 规则和路由 70 | ip -f inet rule add fwmark $PROXY_FWMARK lookup $PROXY_ROUTE_TABLE 71 | ip -f inet route add local default dev "${INTERFACE}" table $PROXY_ROUTE_TABLE 72 | sysctl -w net.ipv4.ip_forward=1 > /dev/null 73 | 74 | # 确保目录存在 75 | sudo mkdir -p /etc/sing-box/nft 76 | 77 | # 设置 TProxy 模式下的 nftables 规则 78 | cat > /etc/sing-box/nft/nftables.conf < /etc/nftables.conf 147 | 148 | echo "TProxy 模式的防火墙规则已应用。" 149 | else 150 | echo "当前模式为 TUN 模式,不需要应用防火墙规则。" >/dev/null 2>&1 151 | fi 152 | -------------------------------------------------------------------------------- /openwrt/configure_tproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 配置参数 4 | TPROXY_PORT=7895 # 与 sing-box 中定义的一致 5 | ROUTING_MARK=666 # 与 sing-box 中定义的一致 6 | PROXY_FWMARK=1 7 | PROXY_ROUTE_TABLE=100 8 | INTERFACE=$(ip route show default | awk '/default/ {print $5; exit}') 9 | 10 | # 保留 IP 地址集合 11 | ReservedIP4='{ 127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 192.88.99.0/24, 192.168.0.0/16, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32 }' 12 | CustomBypassIP='{ 192.168.0.0/16, 10.0.0.0/8 }' # 自定义绕过的 IP 地址集合 13 | 14 | # 读取当前模式 15 | MODE=$(grep -E '^MODE=' /etc/sing-box/mode.conf | sed 's/^MODE=//') 16 | 17 | # 检查指定路由表是否存在 18 | check_route_exists() { 19 | ip route show table "$1" >/dev/null 2>&1 20 | return $? 21 | } 22 | 23 | # 创建路由表,如果不存在的话 24 | create_route_table_if_not_exists() { 25 | if ! check_route_exists "$PROXY_ROUTE_TABLE"; then 26 | echo "路由表不存在,正在创建..." 27 | ip route add local default dev "$INTERFACE" table "$PROXY_ROUTE_TABLE" || { echo "创建路由表失败"; exit 1; } 28 | fi 29 | } 30 | 31 | # 等待 FIB 表加载完成 32 | wait_for_fib_table() { 33 | i=1 34 | while [ $i -le 10 ]; do 35 | if ip route show table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1; then 36 | return 0 37 | fi 38 | echo "等待 FIB 表加载中,等待 $i 秒..." 39 | i=$((i + 1)) 40 | done 41 | echo "FIB 表加载失败,超出最大重试次数" 42 | return 1 43 | } 44 | 45 | # 清理现有 sing-box 防火墙规则 46 | clearSingboxRules() { 47 | nft list table inet sing-box >/dev/null 2>&1 && nft delete table inet sing-box 48 | ip rule del fwmark $PROXY_FWMARK lookup $PROXY_ROUTE_TABLE 2>/dev/null 49 | ip route del local default dev "${INTERFACE}" table $PROXY_ROUTE_TABLE 2>/dev/null 50 | echo "清理 sing-box 相关的防火墙规则" 51 | } 52 | 53 | # 仅在 TProxy 模式下应用防火墙规则 54 | if [ "$MODE" = "TProxy" ]; then 55 | echo "应用 TProxy 模式下的防火墙规则..." 56 | 57 | # 创建并确保路由表存在 58 | create_route_table_if_not_exists 59 | 60 | # 等待 FIB 表加载完成 61 | if ! wait_for_fib_table; then 62 | echo "FIB 表准备失败,退出脚本。" 63 | exit 1 64 | fi 65 | 66 | # 清理现有规则 67 | clearSingboxRules 68 | 69 | # 设置 IP 规则和路由 70 | ip rule add fwmark $PROXY_FWMARK table $PROXY_ROUTE_TABLE 71 | ip route add local default dev "$INTERFACE" table $PROXY_ROUTE_TABLE 72 | sysctl -w net.ipv4.ip_forward=1 > /dev/null 73 | 74 | # 确保目录存在 75 | mkdir -p /etc/sing-box/nft 76 | 77 | # 手动创建 inet 表 78 | nft add table inet sing-box 79 | 80 | # 设置 TProxy 模式下的 nftables 规则 81 | cat > /etc/sing-box/nft/nftables.conf < /etc/nftables.conf 157 | 158 | echo "TProxy 模式的防火墙规则已应用。" 159 | else 160 | echo "当前模式为 TUN 模式,不需要应用防火墙规则。" >/dev/null 2>&1 161 | fi 162 | -------------------------------------------------------------------------------- /debian/manual_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | RED='\033[0;31m' 7 | NC='\033[0m' # 无颜色 8 | 9 | # 手动输入的配置文件 10 | MANUAL_FILE="/etc/sing-box/manual.conf" 11 | DEFAULTS_FILE="/etc/sing-box/defaults.conf" 12 | 13 | # 获取当前模式 14 | MODE=$(grep -oP '(?<=^MODE=).*' /etc/sing-box/mode.conf) 15 | 16 | 17 | prompt_user_input() { 18 | while true; do 19 | read -rp "请输入后端地址(不填使用默认值): " BACKEND_URL 20 | if [ -z "$BACKEND_URL" ]; then 21 | BACKEND_URL=$(grep BACKEND_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 22 | if [ -z "$BACKEND_URL" ]; then 23 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 24 | continue 25 | fi 26 | echo -e "${CYAN}使用默认后端地址: $BACKEND_URL${NC}" 27 | fi 28 | break 29 | done 30 | 31 | while true; do 32 | read -rp "请输入订阅地址(不填使用默认值): " SUBSCRIPTION_URL 33 | if [ -z "$SUBSCRIPTION_URL" ]; then 34 | SUBSCRIPTION_URL=$(grep SUBSCRIPTION_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 35 | if [ -z "$SUBSCRIPTION_URL" ]; then 36 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 37 | continue 38 | fi 39 | echo -e "${CYAN}使用默认订阅地址: $SUBSCRIPTION_URL${NC}" 40 | fi 41 | break 42 | done 43 | 44 | while true; do 45 | read -rp "请输入配置文件地址(不填使用默认值): " TEMPLATE_URL 46 | if [ -z "$TEMPLATE_URL" ]; then 47 | if [ "$MODE" = "TProxy" ]; then 48 | TEMPLATE_URL=$(grep TPROXY_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 49 | if [ -z "$TEMPLATE_URL" ]; then 50 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 51 | continue 52 | fi 53 | echo -e "${CYAN}使用默认 TProxy 配置文件地址: $TEMPLATE_URL${NC}" 54 | elif [ "$MODE" = "TUN" ]; then 55 | TEMPLATE_URL=$(grep TUN_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 56 | if [ -z "$TEMPLATE_URL" ]; then 57 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 58 | continue 59 | fi 60 | echo -e "${CYAN}使用默认 TUN 配置文件地址: $TEMPLATE_URL${NC}" 61 | else 62 | echo -e "${RED}未知的模式: $MODE${NC}" 63 | exit 1 64 | fi 65 | fi 66 | break 67 | done 68 | } 69 | 70 | 71 | read -rp "是否更换订阅地址?(y/n): " change_subscription 72 | if [[ "$change_subscription" =~ ^[Yy]$ ]]; then 73 | # 执行手动输入相关内容 74 | while true; do 75 | prompt_user_input 76 | 77 | echo -e "${CYAN}你输入的配置信息如下:${NC}" 78 | echo "后端地址: $BACKEND_URL" 79 | echo "订阅地址: $SUBSCRIPTION_URL" 80 | echo "配置文件地址: $TEMPLATE_URL" 81 | 82 | read -rp "确认输入的配置信息?(y/n): " confirm_choice 83 | if [[ "$confirm_choice" =~ ^[Yy]$ ]]; then 84 | 85 | cat > "$MANUAL_FILE" </dev/null | cut -d'=' -f2-) 105 | SUBSCRIPTION_URL=$(grep SUBSCRIPTION_URL "$MANUAL_FILE" 2>/dev/null | cut -d'=' -f2-) 106 | TEMPLATE_URL=$(grep TEMPLATE_URL "$MANUAL_FILE" 2>/dev/null | cut -d'=' -f2-) 107 | 108 | if [ -z "$BACKEND_URL" ] || [ -z "$SUBSCRIPTION_URL" ] || [ -z "$TEMPLATE_URL" ]; then 109 | echo -e "${RED}订阅地址为空,请设置!${NC}" 110 | exit 1 111 | fi 112 | 113 | echo -e "${CYAN}当前配置如下:${NC}" 114 | echo "后端地址: $BACKEND_URL" 115 | echo "订阅地址: $SUBSCRIPTION_URL" 116 | echo "配置文件地址: $TEMPLATE_URL" 117 | fi 118 | 119 | # 构建完整的配置文件URL 120 | FULL_URL="${BACKEND_URL}/config/${SUBSCRIPTION_URL}&file=${TEMPLATE_URL}" 121 | echo "生成完整订阅链接: $FULL_URL" 122 | 123 | # 备份现有配置文件 124 | [ -f "/etc/sing-box/config.json" ] && cp /etc/sing-box/config.json /etc/sing-box/config.json.backup 125 | 126 | if curl -L --connect-timeout 10 --max-time 30 "$FULL_URL" -o /etc/sing-box/config.json; then 127 | echo -e "${GREEN}配置文件更新成功!${NC}" 128 | if ! sing-box check -c /etc/sing-box/config.json; then 129 | echo -e "${RED}配置文件验证失败,恢复备份...${NC}" 130 | [ -f "/etc/sing-box/config.json.backup" ] && cp /etc/sing-box/config.json.backup /etc/sing-box/config.json 131 | fi 132 | else 133 | echo -e "${RED}配置文件下载失败,恢复备份...${NC}" 134 | [ -f "/etc/sing-box/config.json.backup" ] && cp /etc/sing-box/config.json.backup /etc/sing-box/config.json 135 | fi 136 | 137 | # 重启sing-box并检查启动状态 138 | sudo systemctl restart sing-box 139 | 140 | if systemctl is-active --quiet sing-box; then 141 | echo -e "${GREEN}sing-box 启动成功${NC}" 142 | else 143 | echo -e "${RED}sing-box 启动失败${NC}" 144 | fi 145 | -------------------------------------------------------------------------------- /openwrt/update_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | RED='\033[0;31m' 7 | NC='\033[0m' # 无颜色 8 | 9 | # 脚本下载目录 10 | SCRIPT_DIR="/etc/sing-box/scripts" 11 | TEMP_DIR="/tmp/sing-box" 12 | 13 | # 脚本的URL基础路径 14 | BASE_URL="https://ghfast.top/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/openwrt" 15 | 16 | # 初始下载菜单脚本的URL 17 | MENU_SCRIPT_URL="$BASE_URL/menu.sh" 18 | 19 | # 提示用户正在检测版本 20 | echo -e "${CYAN}正在检测版本,请耐心等待...${NC}" 21 | 22 | # 确保脚本目录和临时目录存在并设置权限 23 | mkdir -p "$SCRIPT_DIR" 24 | mkdir -p "$TEMP_DIR" 25 | chown "$(id -u)":"$(id -g)" "$SCRIPT_DIR" 26 | chown "$(id -u)":"$(id -g)" "$TEMP_DIR" 27 | 28 | # 下载远程脚本到临时目录 29 | wget -q -O "$TEMP_DIR/menu.sh" "$MENU_SCRIPT_URL" 30 | 31 | # 检查下载是否成功 32 | if ! [ -f "$TEMP_DIR/menu.sh" ]; then 33 | echo -e "${RED}下载远程脚本失败,请检查网络连接。${NC}" 34 | exit 1 35 | fi 36 | 37 | # 获取本地和远程脚本版本 38 | LOCAL_VERSION=$(grep '^# 版本:' "$SCRIPT_DIR/menu.sh" | awk '{print $3}') 39 | REMOTE_VERSION=$(grep '^# 版本:' "$TEMP_DIR/menu.sh" | awk '{print $3}') 40 | 41 | # 检查远程版本是否为空 42 | if [ -z "$REMOTE_VERSION" ]; then 43 | echo -e "${RED}远程版本获取失败,请检查网络连接。${NC}" 44 | read -rp "是否重试?(y/n): " retry_choice 45 | if [[ "$retry_choice" =~ ^[Yy]$ ]]; then 46 | wget -q -O "$TEMP_DIR/menu.sh" "$MENU_SCRIPT_URL" 47 | REMOTE_VERSION=$(grep '^# 版本:' "$TEMP_DIR/menu.sh" | awk '{print $3}') 48 | if [ -z "$REMOTE_VERSION" ]; then 49 | echo -e "${RED}远程版本获取失败,请检查网络连接后再试。返回菜单。${NC}" 50 | rm -rf "$TEMP_DIR" 51 | exit 1 52 | fi 53 | else 54 | echo -e "${RED}请检查网络连接后再试。返回菜单。${NC}" 55 | rm -rf "$TEMP_DIR" 56 | exit 1 57 | fi 58 | fi 59 | 60 | # 输出检测到的版本 61 | echo -e "${CYAN}检测到的版本:本地版本 $LOCAL_VERSION, 远程版本 $REMOTE_VERSION${NC}" 62 | 63 | # 比较版本号 64 | if [ "$LOCAL_VERSION" == "$REMOTE_VERSION" ]; then 65 | echo -e "${GREEN}脚本版本为最新,无需升级。${NC}" 66 | read -rp "是否强制更新?(y/n): " force_update 67 | if [[ "$force_update" =~ ^[Yy]$ ]]; then 68 | echo -e "${CYAN}正在强制更新...${NC}" 69 | else 70 | echo -e "${CYAN}返回菜单。${NC}" 71 | rm -rf "$TEMP_DIR" 72 | exit 0 73 | fi 74 | else 75 | echo -e "${RED}检测到新版本,准备升级。${NC}" 76 | fi 77 | 78 | # 脚本列表 79 | SCRIPTS=( 80 | "check_environment.sh" 81 | "install_singbox.sh" 82 | "manual_input.sh" 83 | "manual_update.sh" 84 | "auto_update.sh" 85 | "configure_tproxy.sh" 86 | "configure_tun.sh" 87 | "start_singbox.sh" 88 | "stop_singbox.sh" 89 | "clean_nft.sh" 90 | "set_defaults.sh" 91 | "commands.sh" 92 | "switch_mode.sh" 93 | "manage_autostart.sh" 94 | "check_config.sh" 95 | "update_scripts.sh" 96 | "update_ui.sh" 97 | "menu.sh" 98 | ) 99 | 100 | # 下载并设置单个脚本,带重试逻辑 101 | download_script() { 102 | local SCRIPT="$1" 103 | local RETRIES=3 104 | local RETRY_DELAY=5 105 | 106 | for ((i=1; i<=RETRIES; i++)); do 107 | if wget -q -O "$SCRIPT_DIR/$SCRIPT" "$BASE_URL/$SCRIPT"; then 108 | chmod +x "$SCRIPT_DIR/$SCRIPT" 109 | return 0 110 | else 111 | sleep "$RETRY_DELAY" 112 | fi 113 | done 114 | 115 | echo -e "${RED}下载 $SCRIPT 失败,请检查网络连接。${NC}" 116 | return 1 117 | } 118 | 119 | # 并行下载脚本 120 | parallel_download_scripts() { 121 | local pids=() 122 | for SCRIPT in "${SCRIPTS[@]}"; do 123 | download_script "$SCRIPT" & 124 | pids+=("$!") 125 | done 126 | 127 | for pid in "${pids[@]}"; do 128 | wait "$pid" 129 | done 130 | } 131 | 132 | # 常规更新 133 | function regular_update() { 134 | echo -e "${CYAN}正在清理缓存,请耐心等待...${NC}" 135 | rm -f "$SCRIPT_DIR"/*.sh 136 | echo -e "${CYAN}正在进行常规更新,请耐心等待...${NC}" 137 | parallel_download_scripts 138 | echo -e "${CYAN}脚本常规更新完成。${NC}" 139 | } 140 | 141 | # 重置更新 142 | function reset_update() { 143 | echo -e "${RED}即将停止 sing-box 并重置所有内容,请稍候...${NC}" 144 | bash "$SCRIPT_DIR/clean_nft.sh" 145 | rm -rf /etc/sing-box 146 | echo -e "${CYAN}sing-box 文件夹已删除。${NC}" 147 | echo -e "${CYAN}正在重新拉取脚本,请耐心等待...${NC}" 148 | bash <(curl -s "$MENU_SCRIPT_URL") 149 | } 150 | 151 | # 提示用户并确认选择 152 | echo -e "${CYAN}请选择更新方式:${NC}" 153 | echo -e "${GREEN}1. 常规更新${NC}" 154 | echo -e "${GREEN}2. 重置更新${NC}" 155 | read -rp "请选择操作: " update_choice 156 | 157 | case $update_choice in 158 | 1) 159 | echo -e "${RED}常规更新只更新脚本内容, 再次执行菜单内容才会执行新脚本。${NC}" 160 | read -rp "是否继续常规更新?(y/n): " confirm 161 | if [[ "$confirm" =~ ^[Yy]$ ]]; then 162 | regular_update 163 | else 164 | echo -e "${CYAN}常规更新已取消。${NC}" 165 | fi 166 | ;; 167 | 2) 168 | echo -e "${RED}即将停止 sing-box 并重置所有内容, 并初始化引导设置。${NC}" 169 | read -rp "是否继续重置更新?(y/n): " confirm 170 | if [[ "$confirm" =~ ^[Yy]$ ]]; then 171 | reset_update 172 | else 173 | echo -e "${CYAN}重置更新已取消。${NC}" 174 | fi 175 | ;; 176 | *) 177 | echo -e "${RED}无效的选择。${NC}" 178 | ;; 179 | esac 180 | 181 | # 清理临时目录 182 | rm -rf "$TEMP_DIR" 183 | -------------------------------------------------------------------------------- /openwrt/manual_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | RED='\033[0;31m' 7 | NC='\033[0m' # 无颜色 8 | 9 | # 手动输入的配置文件 10 | MANUAL_FILE="/etc/sing-box/manual.conf" 11 | DEFAULTS_FILE="/etc/sing-box/defaults.conf" 12 | 13 | # 获取当前模式 14 | MODE=$(grep '^MODE=' /etc/sing-box/mode.conf | sed 's/^MODE=//') 15 | 16 | # 提示用户是否更换订阅的函数 17 | prompt_user_input() { 18 | while true; do 19 | read -rp "请输入后端地址(不填使用默认值): " BACKEND_URL 20 | if [ -z "$BACKEND_URL" ]; then 21 | BACKEND_URL=$(grep BACKEND_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 22 | if [ -z "$BACKEND_URL" ]; then 23 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 24 | continue 25 | fi 26 | echo -e "${CYAN}使用默认后端地址: $BACKEND_URL${NC}" 27 | fi 28 | break 29 | done 30 | 31 | while true; do 32 | read -rp "请输入订阅地址(不填使用默认值): " SUBSCRIPTION_URL 33 | if [ -z "$SUBSCRIPTION_URL" ]; then 34 | SUBSCRIPTION_URL=$(grep SUBSCRIPTION_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 35 | if [ -z "$SUBSCRIPTION_URL" ]; then 36 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 37 | continue 38 | fi 39 | echo -e "${CYAN}使用默认订阅地址: $SUBSCRIPTION_URL${NC}" 40 | fi 41 | break 42 | done 43 | 44 | while true; do 45 | read -rp "请输入配置文件地址(不填使用默认值): " TEMPLATE_URL 46 | if [ -z "$TEMPLATE_URL" ]; then 47 | if [ "$MODE" = "TProxy" ]; then 48 | TEMPLATE_URL=$(grep TPROXY_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 49 | if [ -z "$TEMPLATE_URL" ]; then 50 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 51 | continue 52 | fi 53 | echo -e "${CYAN}使用默认 TProxy 配置文件地址: $TEMPLATE_URL${NC}" 54 | elif [ "$MODE" = "TUN" ]; then 55 | TEMPLATE_URL=$(grep TUN_TEMPLATE_URL "$DEFAULTS_FILE" 2>/dev/null | cut -d'=' -f2-) 56 | if [ -z "$TEMPLATE_URL" ]; then 57 | echo -e "${RED}未设置默认值,请在菜单中设置!${NC}" 58 | continue 59 | fi 60 | echo -e "${CYAN}使用默认 TUN 配置文件地址: $TEMPLATE_URL${NC}" 61 | else 62 | echo -e "${RED}未知的模式: $MODE${NC}" 63 | exit 1 64 | fi 65 | fi 66 | break 67 | done 68 | } 69 | 70 | read -rp "是否更换订阅地址?(y/n): " change_subscription 71 | if [[ "$change_subscription" =~ ^[Yy]$ ]]; then 72 | # 执行手动输入相关内容 73 | while true; do 74 | prompt_user_input 75 | 76 | echo -e "${CYAN}你输入的配置信息如下:${NC}" 77 | echo "后端地址: $BACKEND_URL" 78 | echo "订阅地址: $SUBSCRIPTION_URL" 79 | echo "配置文件地址: $TEMPLATE_URL" 80 | 81 | read -rp "确认输入的配置信息?(y/n): " confirm_choice 82 | if [[ "$confirm_choice" =~ ^[Yy]$ ]]; then 83 | # 更新手动输入的配置文件 84 | cat > "$MANUAL_FILE" </dev/null | cut -d'=' -f2-) 104 | SUBSCRIPTION_URL=$(grep SUBSCRIPTION_URL "$MANUAL_FILE" 2>/dev/null | cut -d'=' -f2-) 105 | TEMPLATE_URL=$(grep TEMPLATE_URL "$MANUAL_FILE" 2>/dev/null | cut -d'=' -f2-) 106 | 107 | if [ -z "$BACKEND_URL" ] || [ -z "$SUBSCRIPTION_URL" ] || [ -z "$TEMPLATE_URL" ]; then 108 | echo -e "${RED}订阅地址为空,请设置!${NC}" 109 | exit 1 110 | fi 111 | 112 | echo -e "${CYAN}当前配置如下:${NC}" 113 | echo "后端地址: $BACKEND_URL" 114 | echo "订阅地址: $SUBSCRIPTION_URL" 115 | echo "配置文件地址: $TEMPLATE_URL" 116 | fi 117 | 118 | # 构建完整的配置文件URL 119 | FULL_URL="${BACKEND_URL}/config/${SUBSCRIPTION_URL}&file=${TEMPLATE_URL}" 120 | echo "生成完整订阅链接: $FULL_URL" 121 | 122 | # 备份现有配置文件 123 | [ -f "/etc/sing-box/config.json" ] && cp /etc/sing-box/config.json /etc/sing-box/config.json.backup 124 | 125 | if curl -L --connect-timeout 10 --max-time 30 "$FULL_URL" -o /etc/sing-box/config.json; then 126 | echo -e "${GREEN}配置文件更新成功!${NC}" 127 | if ! sing-box check -c /etc/sing-box/config.json; then 128 | echo -e "${RED}配置文件验证失败,恢复备份...${NC}" 129 | [ -f "/etc/sing-box/config.json.backup" ] && cp /etc/sing-box/config.json.backup /etc/sing-box/config.json 130 | fi 131 | else 132 | echo -e "${RED}配置文件下载失败,恢复备份...${NC}" 133 | [ -f "/etc/sing-box/config.json.backup" ] && cp /etc/sing-box/config.json.backup /etc/sing-box/config.json 134 | fi 135 | 136 | # 重启sing-box并检查启动状态 137 | /etc/init.d/sing-box start 138 | 139 | if /etc/init.d/sing-box status | grep -q "running"; then 140 | echo -e "${GREEN}sing-box 启动成功${NC}" 141 | else 142 | echo -e "${RED}sing-box 启动失败${NC}" 143 | fi 144 | -------------------------------------------------------------------------------- /debian/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | MAGENTA='\033[0;35m' 6 | YELLOW='\033[1;33m' 7 | RED='\033[0;31m' 8 | NC='\033[0m' # 无颜色 9 | 10 | 11 | function view_firewall_rules() { 12 | echo -e "${YELLOW}查看防火墙规则...${NC}" 13 | sudo nft list ruleset 14 | read -rp "按回车键返回二级菜单..." 15 | } 16 | 17 | function view_logs() { 18 | echo -e "${YELLOW}显示日志...${NC}" 19 | sudo journalctl -u sing-box --output cat -e 20 | read -rp "按回车键返回二级菜单..." 21 | } 22 | 23 | function live_logs() { 24 | echo -e "${YELLOW}实时日志...${NC}" 25 | sudo journalctl -u sing-box -f --output=cat 26 | read -rp "按回车键返回二级菜单..." 27 | } 28 | 29 | function check_config() { 30 | echo -e "${YELLOW}检查配置文件...${NC}" 31 | bash /etc/sing-box/scripts/check_config.sh 32 | read -rp "按回车键返回二级菜单..." 33 | } 34 | 35 | function delaytest() { 36 | echo -e "${YELLOW}正在测试网络延迟...${NC}" 37 | bash /etc/sing-box/scripts/delaytest.sh 38 | read -rp "按回车键返回二级菜单..." 39 | } 40 | 41 | function setup_singbox_permissions() { 42 | echo -e "${YELLOW}正在设置 sing-box 权限与服务...${NC}" 43 | 44 | if ! id sing-box &>/dev/null; then 45 | echo "正在创建 sing-box 系统用户" 46 | sudo useradd --system --no-create-home --shell /usr/sbin/nologin sing-box 47 | fi 48 | 49 | echo "正在设置 sing-box 权限..." 50 | sudo mkdir -p /var/lib/sing-box 51 | sudo chown -R sing-box:sing-box /var/lib/sing-box 52 | sudo chown -R sing-box:sing-box /etc/sing-box 53 | sudo chmod 770 /etc/sing-box 54 | 55 | version_output=$(sing-box version 2>/dev/null) 56 | version=$(echo "$version_output" | grep -oE '1\.11\.[0-9]+') 57 | 58 | if [[ -n "$version" ]]; then 59 | echo "检测到 sing-box 版本为 $version" 60 | service_file="/lib/systemd/system/sing-box.service" 61 | 62 | if [[ -f "$service_file" ]]; then 63 | echo "已找到服务文件" 64 | has_user=$(grep -E '^\s*User=sing-box' "$service_file") 65 | has_state=$(grep -E '^\s*StateDirectory=sing-box' "$service_file") 66 | 67 | if [[ -n "$has_user" && -n "$has_state" ]]; then 68 | echo -e "${RED}服务已有无需设置${NC}" 69 | else 70 | echo "准备插入缺失配置..." 71 | awk -v add_user="$([[ -z "$has_user" ]] && echo 1 || echo 0)" \ 72 | -v add_state="$([[ -z "$has_state" ]] && echo 1 || echo 0)" ' 73 | BEGIN { in_service=0 } 74 | { 75 | print 76 | if ($0 ~ /^\[Service\]/) { 77 | in_service = 1 78 | next 79 | } 80 | 81 | if (in_service == 1) { 82 | if (add_user == 1) { 83 | print "User=sing-box" 84 | if (add_state == 1) { 85 | print "StateDirectory=sing-box" 86 | add_state = 0 87 | } 88 | add_user = 0 89 | } else if (add_state == 1 && $0 ~ /^User=sing-box/) { 90 | print 91 | print "StateDirectory=sing-box" 92 | add_state = 0 93 | next 94 | } 95 | } 96 | } 97 | ' "$service_file" > "${service_file}.tmp" && sudo mv "${service_file}.tmp" "$service_file" 98 | 99 | echo "修改完成,执行 systemctl daemon-reexec" 100 | sudo systemctl daemon-reexec 101 | fi 102 | else 103 | echo "未找到服务文件:$service_file" 104 | fi 105 | else 106 | echo "当前 sing-box 版本非 1.11.x,跳过处理。" 107 | fi 108 | 109 | read -rp "按回车键返回二级菜单..." 110 | } 111 | 112 | 113 | function show_submenu() { 114 | echo -e "${CYAN}=========== 二级菜单选项 ===========${NC}" 115 | echo -e "${MAGENTA}1. 查看防火墙规则${NC}" 116 | echo -e "${MAGENTA}2. 显示日志${NC}" 117 | echo -e "${MAGENTA}3. 实时日志${NC}" 118 | echo -e "${MAGENTA}4. 检查配置文件${NC}" 119 | echo -e "${MAGENTA}5. 外网真实延迟测试${NC}" 120 | echo -e "${MAGENTA}6. 设置 sing-box 权限与服务(执行前查阅wiki)${NC}" 121 | echo -e "${MAGENTA}0. 返回主菜单${NC}" 122 | echo -e "${CYAN}===================================${NC}" 123 | } 124 | 125 | function handle_submenu_choice() { 126 | while true; do 127 | read -rp "请选择操作: " choice 128 | case $choice in 129 | 1) view_firewall_rules ;; 130 | 2) view_logs ;; 131 | 3) live_logs ;; 132 | 4) check_config ;; 133 | 5) delaytest ;; 134 | 6) setup_singbox_permissions ;; 135 | 0) return 0 ;; 136 | *) echo -e "${RED}无效的选择${NC}" ;; 137 | esac 138 | show_submenu 139 | done 140 | return 0 # 确保函数结束时返回 0 141 | } 142 | 143 | menu_active=true 144 | while $menu_active; do 145 | show_submenu 146 | handle_submenu_choice 147 | choice_returned=$? # 捕获函数返回值 148 | if [[ $choice_returned -eq 0 ]]; then 149 | menu_active=false 150 | fi 151 | done -------------------------------------------------------------------------------- /debian/update_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | GREEN='\033[0;32m' 6 | RED='\033[0;31m' 7 | NC='\033[0m' # 无颜色 8 | 9 | # 脚本下载目录 10 | SCRIPT_DIR="/etc/sing-box/scripts" 11 | TEMP_DIR="/tmp/sing-box" 12 | 13 | # 脚本的URL基础路径 14 | BASE_URL="https://ghfast.top/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/debian" 15 | # 初始下载菜单脚本的URL 16 | MENU_SCRIPT_URL="$BASE_URL/menu.sh" 17 | 18 | # 提示用户正在检测版本 19 | echo -e "${CYAN}正在检测版本,请耐心等待...${NC}" 20 | 21 | # 确保脚本目录和临时目录存在并设置权限 22 | sudo mkdir -p "$SCRIPT_DIR" 23 | sudo mkdir -p "$TEMP_DIR" 24 | sudo chown "$(whoami)":"$(whoami)" "$SCRIPT_DIR" 25 | sudo chown "$(whoami)":"$(whoami)" "$TEMP_DIR" 26 | 27 | # 下载远程脚本到临时目录 28 | wget -q -O "$TEMP_DIR/menu.sh" "$MENU_SCRIPT_URL" 29 | 30 | # 检查下载是否成功 31 | if ! [ -f "$TEMP_DIR/menu.sh" ]; then 32 | echo -e "${RED}下载远程脚本失败,请检查网络连接。${NC}" 33 | exit 1 34 | fi 35 | 36 | # 获取本地和远程脚本版本 37 | LOCAL_VERSION=$(grep '^# 版本:' "$SCRIPT_DIR/menu.sh" | awk '{print $3}') 38 | REMOTE_VERSION=$(grep '^# 版本:' "$TEMP_DIR/menu.sh" | awk '{print $3}') 39 | 40 | # 检查远程版本是否为空 41 | if [ -z "$REMOTE_VERSION" ]; then 42 | echo -e "${RED}远程版本获取失败,请检查网络连接。${NC}" 43 | read -rp "是否重试?(y/n): " retry_choice 44 | if [[ "$retry_choice" =~ ^[Yy]$ ]]; then 45 | wget -q -O "$TEMP_DIR/menu.sh" "$MENU_SCRIPT_URL" 46 | REMOTE_VERSION=$(grep '^# 版本:' "$TEMP_DIR/menu.sh" | awk '{print $3}') 47 | if [ -z "$REMOTE_VERSION" ]; then 48 | echo -e "${RED}远程版本获取失败,请检查网络连接后再试。返回菜单。${NC}" 49 | rm -rf "$TEMP_DIR" 50 | exit 1 51 | fi 52 | else 53 | echo -e "${RED}请检查网络连接后再试。返回菜单。${NC}" 54 | rm -rf "$TEMP_DIR" 55 | exit 1 56 | fi 57 | fi 58 | 59 | # 输出检测到的版本 60 | echo -e "${CYAN}检测到的版本:本地版本 $LOCAL_VERSION,远程版本 $REMOTE_VERSION${NC}" 61 | 62 | # 比较版本号 63 | if [ "$LOCAL_VERSION" == "$REMOTE_VERSION" ]; then 64 | echo -e "${GREEN}脚本版本为最新,无需升级。${NC}" 65 | read -rp "是否强制更新?(y/n): " force_update 66 | if [[ "$force_update" =~ ^[Yy]$ ]]; then 67 | echo -e "${CYAN}正在强制更新...${NC}" 68 | else 69 | echo -e "${CYAN}返回菜单。${NC}" 70 | rm -rf "$TEMP_DIR" 71 | exit 0 72 | fi 73 | else 74 | echo -e "${RED}检测到新版本,准备升级。${NC}" 75 | fi 76 | 77 | # 脚本列表 78 | SCRIPTS=( 79 | "check_environment.sh" 80 | "set_network.sh" 81 | "check_update.sh" 82 | "install_singbox.sh" 83 | "manual_input.sh" 84 | "manual_update.sh" 85 | "auto_update.sh" 86 | "configure_tproxy.sh" 87 | "configure_tun.sh" 88 | "start_singbox.sh" 89 | "stop_singbox.sh" 90 | "clean_nft.sh" 91 | "set_defaults.sh" 92 | "commands.sh" 93 | "switch_mode.sh" 94 | "manage_autostart.sh" 95 | "check_config.sh" 96 | "update_scripts.sh" 97 | "update_ui.sh" 98 | "delaytest.sh" 99 | "update_config.sh" 100 | "setup.sh" 101 | "ufw.sh" 102 | "kernel.sh" 103 | "optimize.sh" 104 | "menu.sh" 105 | ) 106 | 107 | # 下载并设置单个脚本,带重试逻辑 108 | download_script() { 109 | local SCRIPT="$1" 110 | local RETRIES=3 111 | local RETRY_DELAY=5 112 | 113 | for ((i=1; i<=RETRIES; i++)); do 114 | if wget -q -O "$SCRIPT_DIR/$SCRIPT" "$BASE_URL/$SCRIPT"; then 115 | chmod +x "$SCRIPT_DIR/$SCRIPT" 116 | return 0 117 | else 118 | sleep "$RETRY_DELAY" 119 | fi 120 | done 121 | 122 | echo -e "${RED}下载 $SCRIPT 失败,请检查网络连接。${NC}" 123 | return 1 124 | } 125 | 126 | # 并行下载脚本 127 | parallel_download_scripts() { 128 | local pids=() 129 | for SCRIPT in "${SCRIPTS[@]}"; do 130 | download_script "$SCRIPT" & 131 | pids+=("$!") 132 | done 133 | 134 | for pid in "${pids[@]}"; do 135 | wait "$pid" 136 | done 137 | } 138 | 139 | # 常规更新 140 | function regular_update() { 141 | echo -e "${CYAN}正在清理缓存,请耐心等待...${NC}" 142 | rm -f "$SCRIPT_DIR"/*.sh 143 | echo -e "${CYAN}正在进行常规更新,请耐心等待...${NC}" 144 | parallel_download_scripts 145 | echo -e "${CYAN}脚本常规更新完成。${NC}" 146 | } 147 | 148 | # 重置更新 149 | function reset_update() { 150 | echo -e "${RED}即将停止 sing-box 并重置所有内容,请稍候...${NC}" 151 | sudo bash "$SCRIPT_DIR/clean_nft.sh" 152 | sudo rm -rf /etc/sing-box 153 | echo -e "${CYAN}sing-box 文件夹已删除。${NC}" 154 | echo -e "${CYAN}正在重新拉取脚本,请耐心等待...${NC}" 155 | bash <(curl -s "$MENU_SCRIPT_URL") 156 | } 157 | 158 | # 提示用户并确认选择 159 | echo -e "${CYAN}请选择更新方式:${NC}" 160 | echo -e "${GREEN}1. 常规更新${NC}" 161 | echo -e "${GREEN}2. 重置更新${NC}" 162 | read -rp "请选择操作: " update_choice 163 | 164 | case $update_choice in 165 | 1) 166 | echo -e "${RED}常规更新只更新脚本内容,再次执行菜单内容才会执行新脚本。${NC}" 167 | read -rp "是否继续常规更新?(y/n): " confirm 168 | if [[ "$confirm" =~ ^[Yy]$ ]]; then 169 | regular_update 170 | else 171 | echo -e "${CYAN}常规更新已取消。${NC}" 172 | fi 173 | ;; 174 | 2) 175 | echo -e "${RED}即将停止 sing-box 并重置所有内容,并初始化引导设置。${NC}" 176 | read -rp "是否继续重置更新?(y/n): " confirm 177 | if [[ "$confirm" =~ ^[Yy]$ ]]; then 178 | reset_update 179 | else 180 | echo -e "${CYAN}重置更新已取消。${NC}" 181 | fi 182 | ;; 183 | *) 184 | echo -e "${RED}无效的选择。${NC}" 185 | ;; 186 | esac 187 | 188 | # 清理临时目录 189 | rm -rf "$TEMP_DIR" 190 | -------------------------------------------------------------------------------- /debian/install_singbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义颜色 4 | CYAN='\033[0;36m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' # 无颜色 7 | 8 | # 检查 sing-box 是否已安装 9 | if command -v sing-box &> /dev/null; then 10 | echo -e "${CYAN}sing-box 已安装,跳过安装步骤${NC}" 11 | else 12 | # 添加官方 GPG 密钥和仓库 13 | sudo mkdir -p /etc/apt/keyrings 14 | sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc 15 | sudo chmod a+r /etc/apt/keyrings/sagernet.asc 16 | echo "Types: deb 17 | URIs: https://deb.sagernet.org/ 18 | Suites: * 19 | Components: * 20 | Enabled: yes 21 | Signed-By: /etc/apt/keyrings/sagernet.asc 22 | " | sudo tee /etc/apt/sources.list.d/sagernet.sources > /dev/null 23 | 24 | # 始终更新包列表 25 | echo "正在更新包列表,请稍候..." 26 | sudo apt-get update -qq > /dev/null 2>&1 27 | 28 | # 选择安装稳定版或测试版 29 | while true; do 30 | read -rp "请选择安装版本(1: 稳定版, 2: 测试版): " version_choice 31 | case $version_choice in 32 | 1) 33 | echo "安装稳定版..." 34 | sudo apt-get install sing-box -yq > /dev/null 2>&1 35 | echo "安装已完成" 36 | break 37 | ;; 38 | 2) 39 | echo "安装测试版..." 40 | sudo apt-get install sing-box-beta -yq > /dev/null 2>&1 41 | echo "安装已完成" 42 | break 43 | ;; 44 | *) 45 | echo -e "${RED}无效的选择,请输入 1 或 2。${NC}" 46 | ;; 47 | esac 48 | done 49 | 50 | if command -v sing-box &> /dev/null; then 51 | sing_box_version=$(sing-box version | grep 'sing-box version' | awk '{print $3}') 52 | echo -e "${CYAN}sing-box 安装成功,版本:${NC} $sing_box_version" 53 | 54 | if ! id sing-box &>/dev/null; then 55 | echo "正在创建 sing-box 系统用户" 56 | sudo useradd --system --no-create-home --shell /usr/sbin/nologin sing-box 57 | fi 58 | echo "正在设置sing-box权限..." 59 | sudo mkdir -p /var/lib/sing-box 60 | sudo chown -R sing-box:sing-box /var/lib/sing-box 61 | sudo chown -R sing-box:sing-box /etc/sing-box 62 | sudo chmod 770 /etc/sing-box 63 | 64 | #if [ -f /etc/sing-box/cache.db ]; then 65 | # sudo chown sing-box:sing-box /etc/sing-box/cache.db 66 | # sudo chmod 660 /etc/sing-box/cache.db 67 | #else 68 | # sudo -u sing-box touch /etc/sing-box/cache.db 69 | # sudo chown sing-box:sing-box /etc/sing-box/cache.db 70 | # sudo chmod 660 /etc/sing-box/cache.db 71 | #fi 72 | # 获取 sing-box 的版本号 73 | version_output=$(sing-box version 2>/dev/null) 74 | version=$(echo "$version_output" | grep -oE '1\.11\.[0-9]+') 75 | 76 | # 检查是否为 1.11.x 版本 77 | if [[ -n "$version" ]]; then 78 | echo "检测到 sing-box 版本为 $version" 79 | 80 | service_file="/lib/systemd/system/sing-box.service" 81 | 82 | if [[ -f "$service_file" ]]; then 83 | echo "已找到服务文件" 84 | 85 | has_user=$(grep -E '^\s*User=sing-box' "$service_file") 86 | has_state=$(grep -E '^\s*StateDirectory=sing-box' "$service_file") 87 | 88 | if [[ -n "$has_user" && -n "$has_state" ]]; then 89 | echo -e "${RED}服务已有无需设置${NC}" 90 | else 91 | echo "准备插入缺失配置..." 92 | 93 | awk -v add_user="$([[ -z "$has_user" ]] && echo 1 || echo 0)" \ 94 | -v add_state="$([[ -z "$has_state" ]] && echo 1 || echo 0)" ' 95 | BEGIN { in_service=0 } 96 | { 97 | print 98 | if ($0 ~ /^\[Service\]/) { 99 | in_service = 1 100 | next 101 | } 102 | 103 | if (in_service == 1) { 104 | if (add_user == 1) { 105 | print "User=sing-box" 106 | if (add_state == 1) { 107 | print "StateDirectory=sing-box" 108 | add_state = 0 109 | } 110 | add_user = 0 111 | } else if (add_state == 1 && $0 ~ /^User=sing-box/) { 112 | print 113 | print "StateDirectory=sing-box" 114 | add_state = 0 115 | next 116 | } 117 | } 118 | } 119 | ' "$service_file" > "${service_file}.tmp" && mv "${service_file}.tmp" "$service_file" 120 | 121 | echo "修改完成,执行 systemctl daemon-reexec" 122 | systemctl daemon-reexec 123 | fi 124 | else 125 | echo "未找到服务文件:$service_file" 126 | fi 127 | else 128 | echo "当前 sing-box 版本非 1.11.x,跳过处理。" 129 | fi 130 | # 重启 sing-box 服务 131 | sudo systemctl daemon-reload 132 | sudo systemctl restart sing-box 133 | 134 | echo -e "${CYAN}sing-box 服务已重启${NC}" 135 | else 136 | echo -e "${RED}sing-box 安装失败,请检查日志或网络配置${NC}" 137 | fi 138 | fi 139 | -------------------------------------------------------------------------------- /openwrt/menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################# 4 | # 描述: OpenWRT 官方sing-box 全自动脚本 5 | # 版本: 2.1.0 6 | ################################################# 7 | 8 | # 定义颜色 9 | CYAN='\033[0;36m' 10 | GREEN='\033[0;32m' 11 | YELLOW='\033[1;33m' 12 | RED='\033[0;31m' 13 | NC='\033[0m' # 无颜色 14 | 15 | # 脚本下载目录和初始化标志文件 16 | SCRIPT_DIR="/etc/sing-box/scripts" 17 | INITIALIZED_FILE="$SCRIPT_DIR/.initialized" 18 | 19 | mkdir -p "$SCRIPT_DIR" 20 | if ! grep -qi 'openwrt' /etc/os-release; then 21 | chown "$(whoami)":"$(whoami)" "$SCRIPT_DIR" 22 | fi 23 | 24 | # 脚本的URL基础路径 25 | BASE_URL="https://ghfast.top/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/openwrt" 26 | 27 | # 脚本列表 28 | SCRIPTS=( 29 | "check_environment.sh" # 检查系统环境 30 | "install_singbox.sh" # 安装 Sing-box 31 | "manual_input.sh" # 手动输入配置 32 | "manual_update.sh" # 手动更新配置 33 | "auto_update.sh" # 自动更新配置 34 | "configure_tproxy.sh" # 配置 TProxy 模式 35 | "configure_tun.sh" # 配置 TUN 模式 36 | "start_singbox.sh" # 手动启动 Sing-box 37 | "stop_singbox.sh" # 手动停止 Sing-box 38 | "clean_nft.sh" # 清理 nftables 规则 39 | "set_defaults.sh" # 设置默认配置 40 | "commands.sh" # 常用命令 41 | "switch_mode.sh" # 切换代理模式 42 | "manage_autostart.sh" # 设置自启动 43 | "check_config.sh" # 检查配置文件 44 | "update_scripts.sh" # 更新脚本 45 | "update_ui.sh" # 控制面板安装/更新/检查 46 | "menu.sh" # 主菜单 47 | ) 48 | 49 | # 下载并设置单个脚本,带重试和日志记录逻辑 50 | download_script() { 51 | local SCRIPT="$1" 52 | local RETRIES=5 # 增加重试次数 53 | local RETRY_DELAY=5 54 | 55 | for ((i=1; i<=RETRIES; i++)); do 56 | if curl -s -o "$SCRIPT_DIR/$SCRIPT" "$BASE_URL/$SCRIPT"; then 57 | chmod +x "$SCRIPT_DIR/$SCRIPT" 58 | return 0 59 | else 60 | echo -e "${YELLOW}下载 $SCRIPT 失败,重试 $i/${RETRIES}...${NC}" 61 | sleep "$RETRY_DELAY" 62 | fi 63 | done 64 | 65 | echo -e "${RED}下载 $SCRIPT 失败,请检查网络连接。${NC}" 66 | return 1 67 | } 68 | 69 | # 并行下载脚本 70 | parallel_download_scripts() { 71 | local pids=() 72 | for SCRIPT in "${SCRIPTS[@]}"; do 73 | download_script "$SCRIPT" & 74 | pids+=("$!") 75 | done 76 | 77 | for pid in "${pids[@]}"; do 78 | wait "$pid" 79 | done 80 | } 81 | 82 | check_and_download_scripts() { 83 | local missing_scripts=() 84 | for SCRIPT in "${SCRIPTS[@]}"; do 85 | if [ ! -f "$SCRIPT_DIR/$SCRIPT" ]; then 86 | missing_scripts+=("$SCRIPT") 87 | fi 88 | done 89 | 90 | if [ ${#missing_scripts[@]} -ne 0 ]; then 91 | echo -e "${CYAN}正在下载脚本,请耐心等待...${NC}" 92 | for SCRIPT in "${missing_scripts[@]}"; do 93 | download_script "$SCRIPT" || { 94 | echo -e "${RED}下载 $SCRIPT 失败,是否重试?(y/n): ${NC}" 95 | read -r retry_choice 96 | if [[ "$retry_choice" =~ ^[Yy]$ ]]; then 97 | download_script "$SCRIPT" 98 | else 99 | echo -e "${RED}跳过 $SCRIPT 下载。${NC}" 100 | fi 101 | } 102 | done 103 | fi 104 | } 105 | 106 | # 初始化操作 107 | initialize() { 108 | # 检查是否存在旧脚本 109 | if ls "$SCRIPT_DIR"/*.sh 1> /dev/null 2>&1; then 110 | find "$SCRIPT_DIR" -type f -name "*.sh" ! -name "menu.sh" -exec rm -f {} \; 111 | rm -f "$INITIALIZED_FILE" 112 | fi 113 | 114 | # 重新下载脚本 115 | parallel_download_scripts 116 | # 进行首次运行的其他初始化操作 117 | auto_setup 118 | touch "$INITIALIZED_FILE" 119 | } 120 | 121 | # 自动引导设置 122 | auto_setup() { 123 | if [ -f /etc/init.d/sing-box ]; then 124 | /etc/init.d/sing-box stop 125 | fi 126 | mkdir -p /etc/sing-box/ 127 | [ -f /etc/sing-box/mode.conf ] || touch /etc/sing-box/mode.conf 128 | chmod 777 /etc/sing-box/mode.conf 129 | bash "$SCRIPT_DIR/check_environment.sh" 130 | command -v sing-box &> /dev/null || bash "$SCRIPT_DIR/install_singbox.sh" || bash "$SCRIPT_DIR/check_update.sh" 131 | bash "$SCRIPT_DIR/switch_mode.sh" 132 | bash "$SCRIPT_DIR/manual_input.sh" 133 | bash "$SCRIPT_DIR/start_singbox.sh" 134 | } 135 | 136 | # 检查是否需要初始化 137 | if [ ! -f "$INITIALIZED_FILE" ]; then 138 | echo -e "${CYAN}回车进入初始化引导设置,输入skip跳过引导${NC}" 139 | read -r init_choice 140 | if [[ "$init_choice" =~ ^[Ss]kip$ ]]; then 141 | echo -e "${CYAN}跳过初始化引导,直接进入菜单...${NC}" 142 | else 143 | initialize 144 | fi 145 | fi 146 | 147 | # 添加别名 148 | [ -f ~/.bashrc ] || touch ~/.bashrc 149 | if ! grep -q "alias sb=" ~/.bashrc || true; then 150 | echo "alias sb='bash $SCRIPT_DIR/menu.sh menu'" >> ~/.bashrc 151 | fi 152 | 153 | # 创建快捷脚本 154 | if [ ! -f /usr/bin/sb ]; then 155 | echo -e '#!/bin/bash\nbash /etc/sing-box/scripts/menu.sh menu' | tee /usr/bin/sb >/dev/null 156 | chmod +x /usr/bin/sb 157 | fi 158 | 159 | show_menu() { 160 | echo -e "${CYAN}=========== Sbshell 管理菜单 ===========${NC}" 161 | echo -e "${GREEN}1. Tproxy/Tun模式切换${NC}" 162 | echo -e "${GREEN}2. 手动更新配置文件${NC}" 163 | echo -e "${GREEN}3. 自动更新配置文件${NC}" 164 | echo -e "${GREEN}4. 手动启动 sing-box${NC}" 165 | echo -e "${GREEN}5. 手动停止 sing-box${NC}" 166 | echo -e "${GREEN}6. 默认参数设置${NC}" 167 | echo -e "${GREEN}7. 设置自启动${NC}" 168 | echo -e "${GREEN}8. 常用命令${NC}" 169 | echo -e "${GREEN}9. 更新脚本${NC}" 170 | echo -e "${GREEN}10. 更新控制面板${NC}" 171 | echo -e "${GREEN}0. 退出${NC}" 172 | echo -e "${CYAN}=======================================${NC}" 173 | } 174 | 175 | handle_choice() { 176 | read -rp "请选择操作: " choice 177 | case $choice in 178 | 1) 179 | bash "$SCRIPT_DIR/switch_mode.sh" 180 | bash "$SCRIPT_DIR/manual_input.sh" 181 | bash "$SCRIPT_DIR/start_singbox.sh" 182 | ;; 183 | 2) 184 | bash "$SCRIPT_DIR/manual_update.sh" 185 | ;; 186 | 3) 187 | bash "$SCRIPT_DIR/auto_update.sh" 188 | ;; 189 | 4) 190 | bash "$SCRIPT_DIR/start_singbox.sh" 191 | ;; 192 | 5) 193 | bash "$SCRIPT_DIR/stop_singbox.sh" 194 | ;; 195 | 6) 196 | bash "$SCRIPT_DIR/set_defaults.sh" 197 | ;; 198 | 7) 199 | bash "$SCRIPT_DIR/manage_autostart.sh" 200 | ;; 201 | 8) 202 | bash "$SCRIPT_DIR/commands.sh" 203 | ;; 204 | 9) 205 | bash "$SCRIPT_DIR/update_scripts.sh" 206 | ;; 207 | 10) 208 | bash "$SCRIPT_DIR/update_ui.sh" 209 | ;; 210 | 0) 211 | exit 0 212 | ;; 213 | *) 214 | echo -e "${RED}无效的选择${NC}" 215 | ;; 216 | esac 217 | } 218 | 219 | # 主循环 220 | while true; do 221 | show_menu 222 | handle_choice 223 | done 224 | -------------------------------------------------------------------------------- /debian/update_ui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | UI_DIR="/etc/sing-box/ui" 4 | BACKUP_DIR="/tmp/sing-box/ui_backup" 5 | TEMP_DIR="/tmp/sing-box-ui" 6 | 7 | ZASHBOARD_URL="https://ghfast.top/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip" 8 | METACUBEXD_URL="https://ghfast.top/https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip" 9 | YACD_URL="https://ghfast.top/https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip" 10 | 11 | # 创建备份目录 12 | mkdir -p "$BACKUP_DIR" 13 | mkdir -p "$TEMP_DIR" 14 | 15 | # 检查依赖并安装 16 | check_and_install_dependencies() { 17 | if ! command -v busybox &> /dev/null; then 18 | echo -e "\e[31mbusybox 未安装,正在安装...\e[0m" 19 | sudo apt-get update 20 | sudo apt-get install -y busybox 21 | export PATH=$PATH:/bin/busybox 22 | sudo chmod +x /bin/busybox 23 | fi 24 | } 25 | 26 | unzip_with_busybox() { 27 | busybox unzip "$1" -d "$2" > /dev/null 2>&1 28 | } 29 | 30 | get_download_url() { 31 | CONFIG_FILE="/etc/sing-box/config.json" 32 | DEFAULT_URL="https://ghfast.top/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip" 33 | 34 | if [ -f "$CONFIG_FILE" ]; then 35 | URL=$(grep -oP '(?<="external_ui_download_url": ")[^"]*' "$CONFIG_FILE") 36 | echo "${URL:-$DEFAULT_URL}" 37 | else 38 | echo "$DEFAULT_URL" 39 | fi 40 | } 41 | 42 | backup_and_remove_ui() { 43 | if [ -d "$UI_DIR" ]; then 44 | echo -e "备份当前ui文件夹..." 45 | mv "$UI_DIR" "$BACKUP_DIR/$(date +%Y%m%d%H%M%S)_ui" 46 | echo -e "已备份至 $BACKUP_DIR" 47 | fi 48 | } 49 | 50 | download_and_process_ui() { 51 | local url="$1" 52 | local temp_file="$TEMP_DIR/ui.zip" 53 | 54 | # 清理临时目录 55 | rm -rf "${TEMP_DIR:?}"/* 56 | 57 | echo "正在下载面板..." 58 | curl -L "$url" -o "$temp_file" 59 | if [ $? -ne 0 ]; then 60 | echo -e "\e[31m下载失败,正在还原备份...\e[0m" 61 | [ -d "$BACKUP_DIR" ] && mv "$BACKUP_DIR/"* "$UI_DIR" 2>/dev/null 62 | return 1 63 | fi 64 | 65 | # 解压文件 66 | echo "解压中..." 67 | if unzip_with_busybox "$temp_file" "$TEMP_DIR"; then 68 | # 确保目标目录存在 69 | mkdir -p "$UI_DIR" 70 | rm -rf "${UI_DIR:?}"/* 71 | mv "$TEMP_DIR"/*/* "$UI_DIR" 72 | echo -e "\e[32m面板安装完成\e[0m" 73 | return 0 74 | else 75 | echo -e "\e[31m解压失败,正在还原备份...\e[0m" 76 | [ -d "$BACKUP_DIR" ] && mv "$BACKUP_DIR/"* "$UI_DIR" 2>/dev/null 77 | return 1 78 | fi 79 | } 80 | 81 | install_default_ui() { 82 | echo "正在安装默认ui面板..." 83 | DOWNLOAD_URL=$(get_download_url) 84 | backup_and_remove_ui 85 | download_and_process_ui "$DOWNLOAD_URL" 86 | } 87 | 88 | install_selected_ui() { 89 | local url="$1" 90 | backup_and_remove_ui 91 | download_and_process_ui "$url" 92 | } 93 | 94 | check_ui() { 95 | if [ -d "$UI_DIR" ] && [ "$(ls -A "$UI_DIR")" ]; then 96 | echo -e "\e[32mui面板已安装\e[0m" 97 | else 98 | echo -e "\e[31mui面板未安装或为空\e[0m" 99 | fi 100 | } 101 | 102 | setup_auto_update_ui() { 103 | local schedule_choice 104 | while true; do 105 | echo "请选择自动更新频率:" 106 | echo "1. 每周一" 107 | echo "2. 每月1号" 108 | read -rp "请输入选项(1/2, 默认为1): " schedule_choice 109 | schedule_choice=${schedule_choice:-1} 110 | 111 | if [[ "$schedule_choice" =~ ^[12]$ ]]; then 112 | break 113 | else 114 | echo -e "\e[31m输入无效,请输入1或2。\e[0m" 115 | fi 116 | done 117 | 118 | if crontab -l 2>/dev/null | grep -q '/etc/sing-box/update-ui.sh'; then 119 | echo -e "\e[31m检测到已有自动更新任务。\e[0m" 120 | read -rp "是否重新设置自动更新任务?(y/n): " confirm_reset 121 | if [[ "$confirm_reset" =~ ^[Yy]$ ]]; then 122 | crontab -l 2>/dev/null | grep -v '/etc/sing-box/update-ui.sh' | crontab - 123 | echo "已删除旧的自动更新任务。" 124 | else 125 | echo -e "\e[36m保持已有的自动更新任务。返回菜单。\e[0m" 126 | return 127 | fi 128 | fi 129 | 130 | # 创建自动更新脚本 131 | cat > /etc/sing-box/update-ui.sh </dev/null 161 | fi 162 | 163 | EOF 164 | 165 | chmod a+x /etc/sing-box/update-ui.sh 166 | 167 | if [ "$schedule_choice" -eq 1 ]; then 168 | (crontab -l 2>/dev/null; echo "0 0 * * 1 /etc/sing-box/update-ui.sh") | crontab - 169 | echo -e "\e[32m定时更新任务已设置,每周一执行一次\e[0m" 170 | else 171 | (crontab -l 2>/dev/null; echo "0 0 1 * * /etc/sing-box/update-ui.sh") | crontab - 172 | echo -e "\e[32m定时更新任务已设置,每月1号执行一次\e[0m" 173 | fi 174 | 175 | systemctl restart cron 176 | } 177 | 178 | update_ui() { 179 | check_and_install_dependencies # 检查并安装依赖 180 | while true; do 181 | echo "请选择功能:" 182 | echo "1. 默认ui(依据配置文件)" 183 | echo "2. 安装/更新自选ui" 184 | echo "3. 检查是否存在ui面板" 185 | echo "4. 设置定时自动更新面板" 186 | read -r -p "请输入选项(1/2/3/4)或按回车键退出: " choice 187 | 188 | if [ -z "$choice" ]; then 189 | echo "退出程序。" 190 | exit 0 191 | fi 192 | 193 | case "$choice" in 194 | 1) 195 | install_default_ui 196 | exit 0 # 更新结束后退出菜单 197 | ;; 198 | 2) 199 | echo "请选择面板安装:" 200 | echo "1. zashboard面板" 201 | echo "2. metacubexd面板" 202 | echo "3. yacd面板" 203 | read -r -p "请输入选项(1/2/3): " ui_choice 204 | 205 | case "$ui_choice" in 206 | 1) 207 | install_selected_ui "$ZASHBOARD_URL" 208 | ;; 209 | 2) 210 | install_selected_ui "$METACUBEXD_URL" 211 | ;; 212 | 3) 213 | install_selected_ui "$YACD_URL" 214 | ;; 215 | *) 216 | echo -e "\e[31m无效选项,返回上级菜单。\e[0m" 217 | ;; 218 | esac 219 | exit 0 # 更新结束后退出菜单 220 | ;; 221 | 3) 222 | check_ui 223 | ;; 224 | 4) 225 | setup_auto_update_ui 226 | ;; 227 | *) 228 | echo -e "\e[31m无效选项,返回主菜单\e[0m" 229 | ;; 230 | esac 231 | done 232 | } 233 | 234 | update_ui -------------------------------------------------------------------------------- /openwrt/update_ui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | UI_DIR="/etc/sing-box/ui" 4 | BACKUP_DIR="/tmp/sing-box/ui_backup" 5 | TEMP_DIR="/tmp/sing-box-ui" 6 | 7 | ZASHBOARD_URL="https://ghfast.top/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip" 8 | METACUBEXD_URL="https://ghfast.top/https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip" 9 | YACD_URL="https://ghfast.top/https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip" 10 | 11 | # 定义颜色 12 | CYAN='\033[0;36m' 13 | GREEN='\033[0;32m' 14 | RED='\033[0;31m' 15 | NC='\033[0m' # 无颜色 16 | 17 | 18 | # 创建备份目录 19 | mkdir -p "$BACKUP_DIR" 20 | mkdir -p "$TEMP_DIR" 21 | 22 | # 检查依赖并安装 23 | check_and_install_dependencies() { 24 | if ! command -v unzip &> /dev/null; then 25 | echo -e "${RED}unzip 未安装,正在安装...${NC}" 26 | opkg update > /dev/null 2>&1 27 | opkg install unzip > /dev/null 2>&1 28 | fi 29 | } 30 | 31 | get_download_url() { 32 | CONFIG_FILE="/etc/sing-box/config.json" 33 | DEFAULT_URL="https://ghfast.top/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip" 34 | 35 | if [ -f "$CONFIG_FILE" ]; then 36 | URL=$(grep -o '"external_ui_download_url": "[^"]*' "$CONFIG_FILE" | sed 's/"external_ui_download_url": "//') 37 | echo "${URL:-$DEFAULT_URL}" 38 | else 39 | echo "$DEFAULT_URL" 40 | fi 41 | } 42 | 43 | backup_and_remove_ui() { 44 | if [ -d "$UI_DIR" ]; then 45 | echo -e "${CYAN}备份当前ui文件夹...${NC}" 46 | mv "$UI_DIR" "$BACKUP_DIR/$(date +%Y%m%d%H%M%S)_ui" 47 | echo -e "${GREEN}已备份至 $BACKUP_DIR${NC}" 48 | fi 49 | } 50 | 51 | download_and_process_ui() { 52 | local url="$1" 53 | local temp_file="$TEMP_DIR/ui.zip" 54 | 55 | # 清理临时目录 56 | rm -rf "${TEMP_DIR:?}"/* 57 | 58 | echo -e "${CYAN}正在下载面板...${NC}" 59 | curl -L "$url" -o "$temp_file" > /dev/null 2>&1 60 | if [ $? -ne 0 ]; then 61 | echo -e "${RED}下载失败,正在还原备份...${NC}" 62 | [ -d "$BACKUP_DIR" ] && mv "$BACKUP_DIR/"* "$UI_DIR" 2>/dev/null 63 | return 1 64 | fi 65 | 66 | # 解压文件 67 | echo -e "${CYAN}解压中...${NC}" 68 | if unzip "$temp_file" -d "$TEMP_DIR" > /dev/null 2>&1; then 69 | # 确保目标目录存在 70 | mkdir -p "$UI_DIR" 71 | rm -rf "${UI_DIR:?}"/* 72 | mv "$TEMP_DIR"/*/* "$UI_DIR" 73 | echo -e "${GREEN}面板安装完成${NC}" 74 | return 0 75 | else 76 | echo -e "${RED}解压失败,正在还原备份...${NC}" 77 | [ -d "$BACKUP_DIR" ] && mv "$BACKUP_DIR/"* "$UI_DIR" 2>/dev/null 78 | return 1 79 | fi 80 | } 81 | 82 | install_default_ui() { 83 | echo -e "${CYAN}正在安装默认ui面板...${NC}" 84 | DOWNLOAD_URL=$(get_download_url) 85 | backup_and_remove_ui 86 | download_and_process_ui "$DOWNLOAD_URL" 87 | } 88 | 89 | install_selected_ui() { 90 | local url="$1" 91 | backup_and_remove_ui 92 | download_and_process_ui "$url" 93 | } 94 | 95 | check_ui() { 96 | if [ -d "$UI_DIR" ] && [ "$(ls -A "$UI_DIR")" ]; then 97 | echo -e "${GREEN}ui面板已安装${NC}" 98 | else 99 | echo -e "${RED}ui面板未安装或为空${NC}" 100 | fi 101 | } 102 | 103 | setup_auto_update_ui() { 104 | local schedule_choice 105 | while true; do 106 | echo -e "${CYAN}请选择自动更新频率:${NC}" 107 | echo "1. 每周一" 108 | echo "2. 每月1号" 109 | read -rp "请输入选项(1/2, 默认为1): " schedule_choice 110 | schedule_choice=${schedule_choice:-1} 111 | 112 | if [[ "$schedule_choice" =~ ^[12]$ ]]; then 113 | break 114 | else 115 | echo -e "${RED}输入无效,请输入1或2。${NC}" 116 | fi 117 | done 118 | 119 | if crontab -l 2>/dev/null | grep -q '/etc/sing-box/update-ui.sh'; then 120 | echo -e "${RED}检测到已有自动更新任务。${NC}" 121 | read -rp "是否重新设置自动更新任务?(y/n): " confirm_reset 122 | if [[ "$confirm_reset" =~ ^[Yy]$ ]]; then 123 | crontab -l 2>/dev/null | grep -v '/etc/sing-box/update-ui.sh' | crontab - 124 | echo "已删除旧的自动更新任务。" 125 | else 126 | echo -e "${CYAN}保持已有的自动更新任务。返回菜单。${NC}" 127 | return 128 | fi 129 | fi 130 | 131 | # 创建自动更新脚本 132 | cat > /etc/sing-box/update-ui.sh < /dev/null 2>&1; then 156 | mkdir -p "\$UI_DIR" 157 | rm -rf "\${UI_DIR:?}"/* 158 | mv "\$TEMP_DIR"/*/* "\$UI_DIR" 159 | else 160 | echo "解压失败,正在还原备份..." 161 | [ -d "\$BACKUP_DIR" ] && mv "\$BACKUP_DIR/"* "\$UI_DIR" 2>/dev/null 162 | fi 163 | 164 | EOF 165 | 166 | chmod a+x /etc/sing-box/update-ui.sh 167 | 168 | if [ "$schedule_choice" -eq 1 ]; then 169 | (crontab -l 2>/dev/null; echo "0 0 * * 1 /etc/sing-box/update-ui.sh") | crontab - 170 | echo -e "${GREEN}定时更新任务已设置,每周一执行一次${NC}" 171 | else 172 | (crontab -l 2>/dev/null; echo "0 0 1 * * /etc/sing-box/update-ui.sh") | crontab - 173 | echo -e "${GREEN}定时更新任务已设置,每月1号执行一次${NC}" 174 | fi 175 | 176 | systemctl restart cron 177 | } 178 | 179 | update_ui() { 180 | check_and_install_dependencies # 检查并安装依赖 181 | while true; do 182 | echo -e "${CYAN}请选择功能:${NC}" 183 | echo "1. 默认ui(依据配置文件)" 184 | echo "2. 安装/更新自选ui" 185 | echo "3. 检查是否存在ui面板" 186 | echo "4. 设置定时自动更新面板" 187 | read -r -p "请输入选项(1/2/3/4)或按回车键退出: " choice 188 | 189 | if [ -z "$choice" ]; then 190 | echo "退出程序。" 191 | exit 0 192 | fi 193 | 194 | case "$choice" in 195 | 1) 196 | install_default_ui 197 | exit 0 # 更新结束后退出菜单 198 | ;; 199 | 2) 200 | echo -e "${CYAN}请选择面板安装:${NC}" 201 | echo "1. zashboard面板" 202 | echo "2. metacubexd面板" 203 | echo "3. yacd面板" 204 | read -r -p "请输入选项(1/2/3): " ui_choice 205 | 206 | case "$ui_choice" in 207 | 1) 208 | install_selected_ui "$ZASHBOARD_URL" 209 | ;; 210 | 2) 211 | install_selected_ui "$METACUBEXD_URL" 212 | ;; 213 | 3) 214 | install_selected_ui "$YACD_URL" 215 | ;; 216 | *) 217 | echo -e "${RED}无效选项,返回上级菜单。${NC}" 218 | ;; 219 | esac 220 | exit 0 # 更新结束后退出菜单 221 | ;; 222 | 3) 223 | check_ui 224 | ;; 225 | 4) 226 | setup_auto_update_ui 227 | ;; 228 | *) 229 | echo -e "${RED}无效选项,返回主菜单${NC}" 230 | ;; 231 | esac 232 | done 233 | } 234 | 235 | update_ui -------------------------------------------------------------------------------- /debian/delaytest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ============================================================================== 4 | # 外网真实延迟测试脚本 5 | # ============================================================================== 6 | 7 | # --- 配置 --- 8 | NUM_TESTS=5 9 | LOG_FILE="latency_log.txt" 10 | CONNECT_TIMEOUT="10" 11 | PREDEFINED_TARGETS=( 12 | "www.google.com" 13 | "www.youtube.com" 14 | "www.cloudflare.com" 15 | "www.github.com" 16 | "www.baidu.com" 17 | ) 18 | 19 | # --- 颜色定义 20 | COLOR_GREEN=$'\033[0;32m' 21 | COLOR_RED=$'\033[0;31m' 22 | COLOR_YELLOW=$'\033[0;33m' 23 | COLOR_BLUE=$'\033[0;34m' 24 | COLOR_PURPLE=$'\033[0;35m' 25 | COLOR_CYAN=$'\033[0;36m' 26 | COLOR_BOLD=$'\033[1m' 27 | COLOR_RESET=$'\033[0m' 28 | 29 | # --- 函数:执行核心测试逻辑 --- 30 | run_test() { 31 | local TARGET_URL="$1" 32 | local output="" 33 | local avg_time_ms=0 34 | 35 | case "$TARGET_URL" in 36 | http://* | https://*) ;; 37 | *) TARGET_URL="https://$TARGET_URL" ;; 38 | esac 39 | 40 | output=$( { 41 | printf "============================================================\n" 42 | printf " %s正在测试: %s%s%s\n" "${COLOR_BLUE}" "${COLOR_BOLD}" "${TARGET_URL}" "${COLOR_RESET}" 43 | printf "============================================================\n" 44 | 45 | local total_duration_ms=0 46 | local min_time_ms="999999" 47 | local max_time_ms="0" 48 | local successful_runs=0 49 | 50 | for i in $(seq 1 $NUM_TESTS); do 51 | local CACHE_BUST_URL 52 | CACHE_BUST_URL="${TARGET_URL}?_t=$(date +%s%N)" 53 | 54 | local CURL_FORMAT="%{time_connect},%{time_pretransfer},%{time_total}" 55 | 56 | local response 57 | response=$(curl -s \ 58 | -H "Cache-Control: no-cache" \ 59 | -H "Pragma: no-cache" \ 60 | --connect-timeout "$CONNECT_TIMEOUT" \ 61 | -o /dev/null \ 62 | -w "$CURL_FORMAT" \ 63 | "$CACHE_BUST_URL") 64 | 65 | if [ $? -ne 0 ] || [ -z "$response" ]; then 66 | printf " 第 %d/%d 次: %s❌ 测试失败 (无法连接或超时)%s\n" "$i" "$NUM_TESTS" "${COLOR_RED}" "${COLOR_RESET}" 67 | continue 68 | fi 69 | 70 | successful_runs=$((successful_runs + 1)) 71 | 72 | IFS=',' read -r connect_time_s tls_time_s run_time_s <<< "$response" 73 | 74 | local connect_time_ms tls_time_ms run_time_ms 75 | connect_time_ms=$(awk -v time="$connect_time_s" 'BEGIN { printf "%.0f", time * 1000 }') 76 | tls_time_ms=$(awk -v time="$tls_time_s" 'BEGIN { printf "%.0f", time * 1000 }') 77 | run_time_ms=$(awk -v time="$run_time_s" 'BEGIN { printf "%.0f", time * 1000 }') 78 | 79 | printf " 第 %d/%d 次: 总延迟 = %s%s ms%s (连接: %s ms, TLS: %s ms)\n" "$i" "$NUM_TESTS" "${COLOR_BOLD}" "$run_time_ms" "${COLOR_RESET}" "$connect_time_ms" "$tls_time_ms" 80 | 81 | echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ"),${TARGET_URL},${i},${connect_time_s},${tls_time_s},${run_time_s}" >> "$LOG_FILE" 82 | 83 | total_duration_ms=$((total_duration_ms + run_time_ms)) 84 | if [ "$run_time_ms" -lt "$min_time_ms" ]; then min_time_ms=$run_time_ms; fi 85 | if [ "$run_time_ms" -gt "$max_time_ms" ]; then max_time_ms=$run_time_ms; fi 86 | done 87 | 88 | printf -- "------------------------------------------------------------\n" 89 | if [ "$successful_runs" -gt 0 ]; then 90 | avg_time_ms=$(awk -v total="$total_duration_ms" -v runs="$successful_runs" 'BEGIN { printf "%.2f", total / runs }') 91 | printf " 📊 %s统计结果 (基于 %d 次成功测试):%s\n" "${COLOR_BOLD}" "$successful_runs" "${COLOR_RESET}" 92 | printf " - 最快 (Min): \t%s%s ms%s\n" "${COLOR_GREEN}" "${min_time_ms}" "${COLOR_RESET}" 93 | printf " - 最慢 (Max): \t%s%s ms%s\n" "${COLOR_RED}" "${max_time_ms}" "${COLOR_RESET}" 94 | printf " - 平均 (Avg): \t%s%s ms%s\n" "${COLOR_YELLOW}" "${avg_time_ms}" "${COLOR_RESET}" 95 | else 96 | printf " 📊 %s所有测试均失败,无法生成统计数据。%s\n" "${COLOR_RED}" "${COLOR_RESET}" 97 | avg_time_ms="0" 98 | fi 99 | printf "============================================================\n" 100 | 101 | echo "$avg_time_ms" 102 | } | tee /dev/tty ) 103 | 104 | echo "$output" | tail -n 1 105 | } 106 | 107 | # --- 函数:批量测试多个地址 --- 108 | run_batch_test() { 109 | local targets=("$@") 110 | local results=() 111 | local target_names=() 112 | 113 | printf "%s%s🚀 开始批量测试多个目标 🚀%s\n" "${COLOR_PURPLE}" "${COLOR_BOLD}" "${COLOR_RESET}" 114 | printf -- "----------------------------------\n" 115 | 116 | for target in "${targets[@]}"; do 117 | printf "\n%s开始测试目标: %s%s\n" "${COLOR_BLUE}" "${target}" "${COLOR_RESET}" 118 | sleep 1 119 | 120 | result=$(run_test "$target" | tail -n 1) 121 | 122 | if [[ "$result" =~ ^[0-9]+([.][0-9]+)?$ ]] && (( $(echo "$result > 0" | bc -l) )); then 123 | results+=("$result") 124 | target_names+=("$target") 125 | else 126 | printf "⚠️ 忽略 %s,无效延迟值 '%s'\n" "$target" "$result" 127 | fi 128 | done 129 | 130 | if [ ${#results[@]} -gt 0 ]; then 131 | show_batch_results "${target_names[@]}" "${results[@]}" 132 | else 133 | printf "%s没有有效的测试结果可显示。%s\n" "${COLOR_RED}" "${COLOR_RESET}" 134 | fi 135 | } 136 | 137 | # --- 函数:显示批量测试结果比较 --- 138 | show_batch_results() { 139 | local -a names=("${@:1:$#/2}") 140 | local -a times=("${@:$#/2+1}") 141 | 142 | printf "%s%s📊 批量测试结果汇总 📊%s\n" "${COLOR_PURPLE}" "${COLOR_BOLD}" "${COLOR_RESET}" 143 | printf -- "----------------------------------\n" 144 | printf "%-20s %-15s %-10s\n" "目标域名" "平均延迟(ms)" "排名" 145 | printf -- "----------------------------------\n" 146 | 147 | declare -A time_map 148 | for i in "${!names[@]}"; do 149 | local name="${names[$i]}" 150 | local time="${times[$i]}" 151 | 152 | if [[ "$time" =~ ^[0-9]+([.][0-9]+)?$ ]]; then 153 | time_map["$name"]="$time" 154 | fi 155 | done 156 | 157 | mapfile -t sorted < <(printf "%s\n" "${times[@]}" | sort -n) 158 | 159 | rank=1 160 | for time in "${sorted[@]}"; do 161 | for name in "${!time_map[@]}"; do 162 | if [ "${time_map[$name]}" = "$time" ]; then 163 | if (( $(echo "$time < 200" | bc -l) )); then 164 | color="${COLOR_GREEN}" 165 | elif (( $(echo "$time < 500" | bc -l) )); then 166 | color="${COLOR_YELLOW}" 167 | else 168 | color="${COLOR_RED}" 169 | fi 170 | 171 | printf "%-20s ${color}%-15s${COLOR_RESET} %-10s\n" "$name" "$time" "$rank" 172 | unset "time_map[$name]" 173 | rank=$((rank + 1)) 174 | fi 175 | done 176 | done 177 | 178 | printf -- "----------------------------------\n" 179 | printf "%s延迟越低表示连接速度越快%s\n" "${COLOR_CYAN}" "${COLOR_RESET}" 180 | } 181 | 182 | # --- 函数:显示主菜单 --- 183 | show_menu() { 184 | clear 185 | printf "%s%s🚀 外网真实延迟测试脚本 🚀%s\n" "${COLOR_PURPLE}" "${COLOR_BOLD}" "${COLOR_RESET}" 186 | printf -- "----------------------------------\n" 187 | printf "%s请选择一个要测试的目标:%s\n" "${COLOR_CYAN}" "${COLOR_RESET}" 188 | 189 | for i in "${!PREDEFINED_TARGETS[@]}"; do 190 | printf " %s%2d)%s %s\n" "${COLOR_YELLOW}" $((i+1)) "${COLOR_RESET}" "${PREDEFINED_TARGETS[$i]}" 191 | done 192 | 193 | printf -- "----------------------------------\n" 194 | printf " %sb)%s 测试谷歌、百度、github、youtube\n" "${COLOR_YELLOW}" "${COLOR_RESET}" 195 | printf " %sm)%s 手动输入域名 (Manual Input)\n" "${COLOR_YELLOW}" "${COLOR_RESET}" 196 | printf " %sq)%s 退出 (Quit)\n" "${COLOR_YELLOW}" "${COLOR_RESET}" 197 | printf -- "----------------------------------\n" 198 | } 199 | 200 | # --- 主循环 --- 201 | if [ ! -f "$LOG_FILE" ]; then 202 | echo "Timestamp,Target,Run,Connect_Time_s,TLS_Time_s,Total_Time_s" > "$LOG_FILE" 203 | fi 204 | 205 | while true; do 206 | show_menu 207 | read -rp "请输入您的选择 [1-$((${#PREDEFINED_TARGETS[@]})), b, m, q]: " choice 208 | 209 | case "$choice" in 210 | [qQ]) 211 | printf "\n%s感谢使用,再见!%s\n" "${COLOR_GREEN}" "${COLOR_RESET}" 212 | exit 0 213 | ;; 214 | [bB]) 215 | run_batch_test "www.google.com" "www.baidu.com" "www.github.com" "www.youtube.com" 216 | ;; 217 | [mM]) 218 | read -rp "请输入您想测试的域名: " MANUAL_URL 219 | if [ -n "$MANUAL_URL" ]; then 220 | run_test "$MANUAL_URL" 221 | else 222 | printf "%s输入不能为空,请重试。%s\n" "${COLOR_RED}" "${COLOR_RESET}"; sleep 2 223 | fi 224 | ;; 225 | *) 226 | if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#PREDEFINED_TARGETS[@]}" ]; then 227 | SELECTED_TARGET="${PREDEFINED_TARGETS[$((choice-1))]}" 228 | run_test "$SELECTED_TARGET" 229 | else 230 | printf "%s无效的选择 '%s',请重试。%s\n" "${COLOR_RED}" "${choice}" "${COLOR_RESET}"; sleep 2 231 | fi 232 | ;; 233 | esac 234 | 235 | read -n 1 -s -r -p $'\n按任意键返回主菜单...' 236 | done -------------------------------------------------------------------------------- /config_template/config_tproxy.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": 3 | { 4 | "servers": [ 5 | {"tag": "local", "type": "udp", "server": "114.114.114.114"}, 6 | {"tag": "public", "type": "udp", "server": "223.5.5.5"}, 7 | {"tag": "foreign", "type": "udp", "server": "8.8.8.8"} 8 | ], 9 | "rules": [ 10 | {"clash_mode": "direct", "server": "local"}, 11 | {"clash_mode": "global", "server": "foreign"}, 12 | {"domain_suffix": ["services.googleapis.cn", "googleapis.cn", "xn--ngstr-lra8j.com"], "server": "foreign"}, 13 | {"rule_set": ["geosite-cn", "geosite-direct", "geosite-steamcn", "geosite-apple"], "server": "local"} 14 | ], 15 | "final": "foreign", 16 | "strategy": "ipv4_only", 17 | "independent_cache": true 18 | }, 19 | 20 | "inbounds": [ 21 | { 22 | "type": "tproxy", 23 | "tag": "tproxy-in", 24 | "listen": "0.0.0.0", 25 | "listen_port": 7895 26 | } 27 | ], 28 | 29 | "outbounds": [ 30 | { "tag": "🚀 节点选择", "type": "selector", "outbounds": ["🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换", "♻️ 自动选择", "➡️ 直连"] }, 31 | { "tag": "📹 YouTube", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 32 | { "tag": "🤖 OpenAI", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 33 | { "tag": "🍀 Google", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 34 | { "tag": "👨‍💻 Github", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 35 | { "tag": "🪟 Microsoft", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "➡️ 直连"] }, 36 | { "tag": "🐬 OneDrive", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 37 | { "tag": "🎵 TikTok", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 38 | { "tag": "🎥 Netflix", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 39 | { "tag": "📲 Telegram", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 40 | { "tag": "🍏 Apple", "type": "selector", "outbounds": ["➡️ 直连", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点"] }, 41 | { "tag": "🐠 兜底策略", "type": "selector", "outbounds": ["🚀 节点选择","➡️ 直连"] }, 42 | { "tag": "🐸 手动切换", "type": "selector", "outbounds": ["{all}"]}, 43 | { "tag": "🇭🇰 香港节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }] }, 44 | { "tag": "🇯🇵 日本节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇯🇵|JP|jp|日本|日|Japan"] }] }, 45 | { "tag": "🇺🇲 美国节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇺🇸|US|us|美国|美|United States"] }, { "action": "exclude", "keywords": ["香港|港|HK|hk|HongKong"] }] }, 46 | { "tag": "🔯 香港自动", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 47 | { "tag": "♻️ 自动选择", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "exclude", "keywords": ["网站|地址|剩余|过期|时间|有效"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 48 | { "tag": "GLOBAL", "type": "selector", "outbounds": ["{all}"]}, 49 | { "tag": "➡️ 直连", "type": "direct" } 50 | ], 51 | 52 | "route": 53 | { 54 | "rules": 55 | [ 56 | {"action": "sniff", "sniffer": ["http", "tls", "quic", "dns"]}, 57 | {"type": "logical", "mode": "or", "rules": [{"port": 53}, {"protocol": "dns"}], "action": "hijack-dns"}, 58 | {"ip_is_private": true, "outbound": "🎯 全球直连"}, 59 | {"clash_mode": "direct", "outbound": "➡️ 直连"}, 60 | {"clash_mode": "global", "outbound": "GLOBAL"}, 61 | {"domain": ["clash.razord.top", "yacd.metacubex.one", "yacd.haishan.me", "d.metacubex.one"], "outbound": "➡️ 直连"}, 62 | {"rule_set": "geosite-private", "outbound": "➡️ 直连"}, 63 | {"rule_set": "geosite-chat", "outbound": "🤖 OpenAI"}, 64 | {"rule_set": "geosite-youtube", "outbound": "📹 YouTube"}, 65 | {"rule_set": "geosite-github", "outbound": "👨‍💻 Github"}, 66 | {"rule_set": ["geosite-google", "geoip-google"], "outbound": "🍀 Google"}, 67 | {"rule_set": ["geosite-telegram", "geoip-telegram"], "outbound": "📲 Telegram"}, 68 | {"rule_set": "geosite-tiktok", "outbound": "🎵 TikTok"}, 69 | {"rule_set": ["geosite-netflix", "geoip-netflix"], "outbound": "🎥 Netflix"}, 70 | {"rule_set": ["geosite-apple", "geoip-apple"], "outbound": "🍏 Apple"}, 71 | {"rule_set": "geosite-onedrive", "outbound": "🐬 OneDrive"}, 72 | {"rule_set": "geosite-microsoft", "outbound": "🪟 Microsoft"}, 73 | {"rule_set": "geosite-geolocation-!cn", "outbound": "🚀 节点选择"}, 74 | {"rule_set": ["geoip-cn", "geosite-cn"], "outbound": "➡️ 直连"} 75 | ], 76 | 77 | "rule_set": [ 78 | { "tag": "geosite-chat", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ai-!cn.srs", "download_detour": "➡️ 直连" }, 79 | { "tag": "geosite-youtube", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/youtube.srs", "download_detour": "➡️ 直连" }, 80 | { "tag": "geosite-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/google.srs", "download_detour": "➡️ 直连" }, 81 | { "tag": "geosite-github", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs", "download_detour": "➡️ 直连" }, 82 | { "tag": "geosite-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/telegram.srs", "download_detour": "➡️ 直连" }, 83 | { "tag": "geosite-tiktok", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/tiktok.srs", "download_detour": "➡️ 直连" }, 84 | { "tag": "geosite-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/netflix.srs", "download_detour": "➡️ 直连" }, 85 | { "tag": "geosite-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/apple.srs", "download_detour": "➡️ 直连" }, 86 | { "tag": "geosite-microsoft", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/microsoft.srs", "download_detour": "➡️ 直连" }, 87 | { "tag": "geosite-onedrive", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/onedrive.srs", "download_detour": "➡️ 直连" }, 88 | { "tag": "geosite-geolocation-!cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/geolocation-!cn.srs", "download_detour": "➡️ 直连" }, 89 | { "tag": "geosite-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/cn.srs", "download_detour": "➡️ 直连" }, 90 | { "tag": "geosite-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/private.srs", "download_detour": "➡️ 直连" }, 91 | 92 | { "tag": "geoip-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/google.srs", "download_detour": "➡️ 直连" }, 93 | { "tag": "geoip-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/telegram.srs", "download_detour": "➡️ 直连" }, 94 | { "tag": "geoip-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/netflix.srs", "download_detour": "➡️ 直连" }, 95 | { "tag": "geoip-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo-lite/geoip/apple.srs", "download_detour": "➡️ 直连" }, 96 | { "tag": "geoip-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/cn.srs", "download_detour": "➡️ 直连" }, 97 | { "tag": "geoip-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/private.srs", "download_detour": "➡️ 直连" } 98 | ], 99 | "final": "🐠 兜底策略", 100 | "auto_detect_interface": true, 101 | "default_mark": 666, 102 | "default_domain_resolver": {"server": "public"} 103 | }, 104 | "log": { 105 | "disabled": false, 106 | "level": "info", 107 | "timestamp": true 108 | }, 109 | 110 | "experimental": { 111 | "clash_api": { 112 | "external_controller": "0.0.0.0:9095", 113 | "external_ui": "/etc/sing-box/ui", 114 | "secret": "", 115 | "external_ui_download_url": "https://gh-proxy.com/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip", 116 | "external_ui_download_detour": "➡️ 直连", 117 | "default_mode": "rule" 118 | }, 119 | "cache_file": { 120 | "enabled": true, 121 | "path": "/etc/sing-box/cache.db", 122 | "store_fakeip": false 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /config_template/config_tun.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "disabled": false, 4 | "level": "info", 5 | "timestamp": true 6 | }, 7 | 8 | "experimental": { 9 | "clash_api": { 10 | "external_controller": "0.0.0.0:9095", 11 | "external_ui": "/etc/sing-box/ui", 12 | "secret": "", 13 | "external_ui_download_url": "https://gh-proxy.com/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip", 14 | "external_ui_download_detour": "➡️ 直连", 15 | "default_mode": "rule" 16 | }, 17 | "cache_file": { 18 | "enabled": true, 19 | "path": "/etc/sing-box/cache.db", 20 | "store_fakeip": false 21 | } 22 | }, 23 | 24 | "dns": 25 | { 26 | "servers": 27 | [ 28 | {"tag": "dns_direct", "address": "223.5.5.5", "address_strategy": "ipv4_only", "strategy": "ipv4_only", "detour": "➡️ 直连"}, 29 | {"tag": "dns_proxy", "address": "tls://8.8.8.8", "address_strategy": "ipv4_only", "strategy": "ipv4_only", "detour": "🚀 节点选择"} 30 | ], 31 | "rules": 32 | [ 33 | {"outbound": "any", "server": "dns_direct", "disable_cache": true}, 34 | {"clash_mode": "Direct", "server": "dns_direct"}, 35 | {"clash_mode": "Global", "server": "dns_proxy"}, 36 | {"rule_set": "geosite-cn", "action": "route","server": "dns_direct"}, 37 | {"rule_set": "geosite-geolocation-!cn", "server": "dns_proxy"} 38 | ], 39 | "final": "dns_proxy", 40 | "strategy": "ipv4_only" 41 | }, 42 | 43 | "inbounds": [ 44 | { 45 | "tag": "tun-in", 46 | "type": "tun", 47 | "address": [ 48 | "172.19.0.1/30", 49 | "fdfe:dcba:9876::1/126" 50 | ], 51 | "mtu": 9000, 52 | "auto_route": true, 53 | "auto_redirect": true 54 | }, 55 | { 56 | "tag": "mixed-in", 57 | "type": "mixed", 58 | "listen": "0.0.0.0", 59 | "listen_port": 7893 60 | } 61 | ], 62 | 63 | "outbounds": [ 64 | { "tag": "🚀 节点选择", "type": "selector", "outbounds": ["🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换", "♻️ 自动选择", "➡️ 直连"] }, 65 | { "tag": "📹 YouTube", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 66 | { "tag": "🤖 OpenAI", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 67 | { "tag": "🍀 Google", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 68 | { "tag": "👨‍💻 Github", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 69 | { "tag": "🪟 Microsoft", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "➡️ 直连"] }, 70 | { "tag": "🐬 OneDrive", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 71 | { "tag": "🎵 TikTok", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 72 | { "tag": "🎥 Netflix", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 73 | { "tag": "📲 Telegram", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 74 | { "tag": "🍏 Apple", "type": "selector", "outbounds": ["➡️ 直连", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点"] }, 75 | { "tag": "🐠 兜底策略", "type": "selector", "outbounds": ["🚀 节点选择","➡️ 直连"] }, 76 | { "tag": "🐸 手动切换", "type": "selector", "outbounds": ["{all}"]}, 77 | { "tag": "🇭🇰 香港节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }] }, 78 | { "tag": "🇯🇵 日本节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇯🇵|JP|jp|日本|日|Japan"] }] }, 79 | { "tag": "🇺🇲 美国节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇺🇸|US|us|美国|美|United States"] }, { "action": "exclude", "keywords": ["香港|港|HK|hk|HongKong"] }] }, 80 | { "tag": "🔯 香港自动", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 81 | { "tag": "♻️ 自动选择", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "exclude", "keywords": ["网站|地址|剩余|过期|时间|有效"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 82 | { "tag": "GLOBAL", "type": "selector", "outbounds": ["{all}"]}, 83 | { "tag": "➡️ 直连", "type": "direct" } 84 | ], 85 | 86 | "route": 87 | { 88 | "auto_detect_interface": true, 89 | "final": "🐠 兜底策略", 90 | "rules": 91 | [ 92 | {"action": "sniff"}, 93 | {"protocol": "dns", "action": "hijack-dns"}, 94 | {"clash_mode": "direct", "outbound": "➡️ 直连"}, 95 | {"clash_mode": "global", "outbound": "GLOBAL"}, 96 | {"domain": ["clash.razord.top", "yacd.metacubex.one", "yacd.haishan.me", "d.metacubex.one"], "outbound": "➡️ 直连"}, 97 | {"rule_set": "geosite-private", "outbound": "➡️ 直连"}, 98 | {"rule_set": "geosite-chat", "outbound": "🤖 OpenAI"}, 99 | {"rule_set": "geosite-youtube", "outbound": "📹 YouTube"}, 100 | {"rule_set": "geosite-github", "outbound": "👨‍💻 Github"}, 101 | {"rule_set": ["geosite-google", "geoip-google"], "outbound": "🍀 Google"}, 102 | {"rule_set": ["geosite-telegram", "geoip-telegram"], "outbound": "📲 Telegram"}, 103 | {"rule_set": "geosite-tiktok", "outbound": "🎵 TikTok"}, 104 | {"rule_set": ["geosite-netflix", "geoip-netflix"], "outbound": "🎥 Netflix"}, 105 | {"rule_set": ["geosite-apple", "geoip-apple"], "outbound": "🍏 Apple"}, 106 | {"rule_set": "geosite-onedrive", "outbound": "🐬 OneDrive"}, 107 | {"rule_set": "geosite-microsoft", "outbound": "🪟 Microsoft"}, 108 | {"rule_set": "geosite-geolocation-!cn", "outbound": "🚀 节点选择"}, 109 | {"rule_set": ["geoip-cn", "geosite-cn"], "outbound": "➡️ 直连"} 110 | ], 111 | 112 | "rule_set": [ 113 | { "tag": "geosite-chat", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ai-!cn.srs", "download_detour": "➡️ 直连" }, 114 | { "tag": "geosite-youtube", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/youtube.srs", "download_detour": "➡️ 直连" }, 115 | { "tag": "geosite-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/google.srs", "download_detour": "➡️ 直连" }, 116 | { "tag": "geosite-github", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs", "download_detour": "➡️ 直连" }, 117 | { "tag": "geosite-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/telegram.srs", "download_detour": "➡️ 直连" }, 118 | { "tag": "geosite-tiktok", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/tiktok.srs", "download_detour": "➡️ 直连" }, 119 | { "tag": "geosite-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/netflix.srs", "download_detour": "➡️ 直连" }, 120 | { "tag": "geosite-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/apple.srs", "download_detour": "➡️ 直连" }, 121 | { "tag": "geosite-microsoft", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/microsoft.srs", "download_detour": "➡️ 直连" }, 122 | { "tag": "geosite-onedrive", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/onedrive.srs", "download_detour": "➡️ 直连" }, 123 | { "tag": "geosite-geolocation-!cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/geolocation-!cn.srs", "download_detour": "➡️ 直连" }, 124 | { "tag": "geosite-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/cn.srs", "download_detour": "➡️ 直连" }, 125 | { "tag": "geosite-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/private.srs", "download_detour": "➡️ 直连" }, 126 | 127 | { "tag": "geoip-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/google.srs", "download_detour": "➡️ 直连" }, 128 | { "tag": "geoip-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/telegram.srs", "download_detour": "➡️ 直连" }, 129 | { "tag": "geoip-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/netflix.srs", "download_detour": "➡️ 直连" }, 130 | { "tag": "geoip-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo-lite/geoip/apple.srs", "download_detour": "➡️ 直连" }, 131 | { "tag": "geoip-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/cn.srs", "download_detour": "➡️ 直连" }, 132 | { "tag": "geoip-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/private.srs", "download_detour": "➡️ 直连" } 133 | ] 134 | } 135 | } -------------------------------------------------------------------------------- /config_template/config_trpoxy12.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": { 3 | "servers": [ 4 | { "tag": "local", "type": "udp", "server": "223.5.5.5" }, 5 | { "tag": "public", "type": "https", "server": "dns.alidns.com", "domain_resolver": "local" }, 6 | { "tag": "foreign", "type": "https", "server": "1.1.1.1", "detour": "🚀 节点选择" } 7 | ], 8 | "rules": [ 9 | {"clash_mode": "direct", "server": "local"}, 10 | {"clash_mode": "global", "server": "foreign"}, 11 | {"domain_suffix": ["services.googleapis.cn", "googleapis.cn", "xn--ngstr-lra8j.com"], "server": "foreign"}, 12 | {"rule_set": "geosite-google", "server": "foreign"}, 13 | {"rule_set": ["geosite-cn", "geosite-apple", "geosite-private"], "server": "local"} 14 | ], 15 | "final": "foreign", 16 | "strategy": "ipv4_only", 17 | "independent_cache": true 18 | }, 19 | 20 | "inbounds": [ 21 | { 22 | "type": "tproxy", 23 | "tag": "tproxy-in", 24 | "listen": "0.0.0.0", 25 | "listen_port": 7895 26 | } 27 | ], 28 | 29 | "outbounds": [ 30 | { "tag": "🚀 节点选择", "type": "selector", "outbounds": ["🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换", "♻️ 自动选择", "➡️ 直连"] }, 31 | { "tag": "📹 YouTube", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 32 | { "tag": "🤖 OpenAI", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 33 | { "tag": "🍀 Google", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 34 | { "tag": "👨‍💻 Github", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 35 | { "tag": "🪟 Microsoft", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "➡️ 直连"] }, 36 | { "tag": "🐬 OneDrive", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 37 | { "tag": "🎵 TikTok", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 38 | { "tag": "🎥 Netflix", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 39 | { "tag": "📲 Telegram", "type": "selector", "outbounds": ["🚀 节点选择", "♻️ 自动选择", "🔯 香港自动", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点", "🐸 手动切换"] }, 40 | { "tag": "🍏 Apple", "type": "selector", "outbounds": ["➡️ 直连", "🇭🇰 香港节点", "🇯🇵 日本节点", "🇺🇲 美国节点"] }, 41 | { "tag": "🕸️ 兜底策略", "type": "selector", "outbounds": ["🚀 节点选择","➡️ 直连"] }, 42 | { "tag": "🐸 手动切换", "type": "selector", "outbounds": ["{all}"]}, 43 | { "tag": "🇭🇰 香港节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }] }, 44 | { "tag": "🇯🇵 日本节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇯🇵|JP|jp|日本|日|Japan"] }] }, 45 | { "tag": "🇺🇲 美国节点", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇺🇸|US|us|美国|美|United States"] }, { "action": "exclude", "keywords": ["香港|港|HK|hk|HongKong"] }] }, 46 | { "tag": "🔯 香港自动", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 47 | { "tag": "♻️ 自动选择", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "exclude", "keywords": ["网站|地址|剩余|过期|时间|有效"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 48 | { "tag": "GLOBAL", "type": "selector", "outbounds": ["{all}"]}, 49 | { "tag": "➡️ 直连", "type": "direct" } 50 | ], 51 | 52 | "route": 53 | { 54 | "rules": 55 | [ 56 | {"action": "sniff", "sniffer": ["http", "tls", "quic", "dns"]}, 57 | {"type": "logical", "mode": "or", "rules": [{"port": 53}, {"protocol": "dns"}], "action": "hijack-dns"}, 58 | {"ip_is_private": true, "outbound": "➡️ 直连"}, 59 | {"clash_mode": "direct", "outbound": "➡️ 直连"}, 60 | {"clash_mode": "global", "outbound": "GLOBAL"}, 61 | {"domain": ["clash.razord.top", "yacd.metacubex.one", "yacd.haishan.me", "d.metacubex.one"], "outbound": "➡️ 直连"}, 62 | {"rule_set": "geosite-private", "outbound": "➡️ 直连"}, 63 | {"rule_set": "geosite-chat", "outbound": "🤖 OpenAI"}, 64 | {"rule_set": "geosite-youtube", "outbound": "📹 YouTube"}, 65 | {"rule_set": "geosite-github", "outbound": "👨‍💻 Github"}, 66 | {"rule_set": ["geosite-google", "geoip-google"], "outbound": "🍀 Google"}, 67 | {"rule_set": ["geosite-telegram", "geoip-telegram"], "outbound": "📲 Telegram"}, 68 | {"rule_set": "geosite-tiktok", "outbound": "🎵 TikTok"}, 69 | {"rule_set": ["geosite-netflix", "geoip-netflix"], "outbound": "🎥 Netflix"}, 70 | {"rule_set": ["geosite-apple", "geoip-apple"], "outbound": "🍏 Apple"}, 71 | {"rule_set": "geosite-onedrive", "outbound": "🐬 OneDrive"}, 72 | {"rule_set": "geosite-microsoft", "outbound": "🪟 Microsoft"}, 73 | {"rule_set": "geosite-geolocation-!cn", "outbound": "🚀 节点选择"}, 74 | {"rule_set": ["geoip-cn", "geosite-cn"], "outbound": "➡️ 直连"} 75 | ], 76 | 77 | "rule_set": [ 78 | { "tag": "geosite-chat", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ai-!cn.srs", "download_detour": "➡️ 直连" }, 79 | { "tag": "geosite-youtube", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/youtube.srs", "download_detour": "➡️ 直连" }, 80 | { "tag": "geosite-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/google.srs", "download_detour": "➡️ 直连" }, 81 | { "tag": "geosite-github", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs", "download_detour": "➡️ 直连" }, 82 | { "tag": "geosite-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/telegram.srs", "download_detour": "➡️ 直连" }, 83 | { "tag": "geosite-tiktok", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/tiktok.srs", "download_detour": "➡️ 直连" }, 84 | { "tag": "geosite-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/netflix.srs", "download_detour": "➡️ 直连" }, 85 | { "tag": "geosite-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/apple.srs", "download_detour": "➡️ 直连" }, 86 | { "tag": "geosite-microsoft", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/microsoft.srs", "download_detour": "➡️ 直连" }, 87 | { "tag": "geosite-onedrive", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/onedrive.srs", "download_detour": "➡️ 直连" }, 88 | { "tag": "geosite-geolocation-!cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/geolocation-!cn.srs", "download_detour": "➡️ 直连" }, 89 | { "tag": "geosite-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/cn.srs", "download_detour": "➡️ 直连" }, 90 | { "tag": "geosite-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/private.srs", "download_detour": "➡️ 直连" }, 91 | 92 | { "tag": "geoip-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/google.srs", "download_detour": "➡️ 直连" }, 93 | { "tag": "geoip-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/telegram.srs", "download_detour": "➡️ 直连" }, 94 | { "tag": "geoip-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/netflix.srs", "download_detour": "➡️ 直连" }, 95 | { "tag": "geoip-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo-lite/geoip/apple.srs", "download_detour": "➡️ 直连" }, 96 | { "tag": "geoip-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/cn.srs", "download_detour": "➡️ 直连" }, 97 | { "tag": "geoip-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/private.srs", "download_detour": "➡️ 直连" } 98 | ], 99 | "final": "🕸️ 兜底策略", 100 | "auto_detect_interface": true, 101 | "default_mark": 666, 102 | "default_domain_resolver": {"server": "public"} 103 | }, 104 | "log": { 105 | "disabled": false, 106 | "level": "info", 107 | "timestamp": true 108 | }, 109 | 110 | "experimental": { 111 | "clash_api": { 112 | "external_controller": "0.0.0.0:9095", 113 | "external_ui": "/etc/sing-box/ui", 114 | "secret": "", 115 | "external_ui_download_url": "https://gh-proxy.com/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip", 116 | "external_ui_download_detour": "➡️ 直连", 117 | "default_mode": "rule" 118 | }, 119 | "cache_file": { 120 | "enabled": true, 121 | "path": "/etc/sing-box/cache.db", 122 | "store_fakeip": false 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /debian/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # 一键申请 SSL 证书脚本 (默认使用 Let's Encrypt) 4 | # 5 | 6 | # --- 脚本设置与错误处理 --- 7 | set -eEuo pipefail 8 | # 在发生错误时,将错误信息输出到 stderr 并退出 9 | # `$BASH_SOURCE` 和 `$LINENO` 用于指示错误发生的脚本文件和行号 10 | trap 'echo -e "\033[31m❌ 脚本在 [\033[1m\$BASH_SOURCE:\$LINENO\033[0m\033[31m] 行发生错误\033[0m" >&2; exit 1' ERR 11 | 12 | # --- ANSI 颜色代码 --- 13 | RED='\033[31m' 14 | GREEN='\033[32m' 15 | YELLOW='\033[33m' 16 | BOLD='\033[1m' 17 | RESET='\033[0m' 18 | 19 | # --- 全局变量 --- 20 | DOMAIN="" 21 | EMAIL="" 22 | CA_SERVER="letsencrypt" 23 | OS_TYPE="" 24 | PKG_MANAGER="" 25 | ACME_INSTALL_PATH="$HOME/.acme.sh" 26 | CERT_KEY_DIR="" # 动态设置为 /etc/ssl/您的域名/ 27 | ACME_CMD="" # 动态查找的 acme.sh 命令路径 28 | 29 | # --- 函数定义 --- 30 | 31 | # 检查并确保以 root 权限运行 32 | check_root() { 33 | if [ "$EUID" -ne 0 ]; then 34 | echo -e "${RED}❌ 错误:请使用 root 权限运行此脚本。${RESET}" >&2 35 | exit 1 36 | fi 37 | echo -e "${GREEN}✅ Root 权限检查通过。${RESET}" 38 | } 39 | 40 | # 获取用户输入并校验格式 41 | get_user_input() { 42 | read -r -p "请输入域名: " DOMAIN 43 | if ! [[ "$DOMAIN" =~ ^[a-zA-Z0-9.-]+$ ]]; then 44 | echo -e "${RED}❌ 错误:域名格式不正确!${RESET}" >&2; exit 1; 45 | fi 46 | 47 | read -r -p "请输入电子邮件地址: " EMAIL 48 | if ! [[ "$EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then 49 | echo -e "${RED}❌ 错误:电子邮件格式不正确!${RESET}" >&2; exit 1; 50 | fi 51 | 52 | echo -e "${GREEN}✅ 用户信息收集完成 (默认使用 Let's Encrypt)。${RESET}" 53 | } 54 | 55 | # 检测操作系统并设置相关变量 56 | detect_os() { 57 | if grep -qi "ubuntu" /etc/os-release; then 58 | OS_TYPE="ubuntu"; PKG_MANAGER="apt" 59 | elif grep -qi "debian" /etc/os-release; then 60 | OS_TYPE="debian"; PKG_MANAGER="apt" 61 | elif grep -qi "centos" /etc/os-release; then 62 | OS_TYPE="centos"; PKG_MANAGER="yum" 63 | elif grep -qi "rhel" /etc/os-release; then 64 | OS_TYPE="rhel"; PKG_MANAGER="yum" 65 | else 66 | echo -e "${RED}❌ 错误:不支持的操作系统!${RESET}" >&2; exit 1 67 | fi 68 | echo -e "${GREEN}✅ 检测到操作系统: $OS_TYPE ($PKG_MANAGER)。${RESET}" 69 | } 70 | 71 | # 安装依赖 72 | install_dependencies() { 73 | local dependencies=() 74 | 75 | if [[ "$OS_TYPE" == "ubuntu" || "$OS_TYPE" == "debian" ]]; then 76 | dependencies=("curl" "socat" "cron" "ufw") 77 | elif [[ "$OS_TYPE" == "centos" || "$OS_TYPE" == "rhel" ]]; then 78 | dependencies=("curl" "socat" "cronie" "firewalld") 79 | else 80 | echo -e "${RED}❌ 错误:不支持的操作系统!${RESET}" >&2 81 | exit 1 82 | fi 83 | 84 | for pkg in "${dependencies[@]}"; do 85 | if [[ "$PKG_MANAGER" == "apt" ]]; then 86 | if ! dpkg -s "$pkg" &>/dev/null; then 87 | echo -e "${YELLOW}安装依赖: $pkg...${RESET}" 88 | sudo apt install -y "$pkg" >/dev/null 2>&1 || { echo -e "${RED}❌ 错误:安装 $pkg 失败${RESET}" >&2; exit 1; } 89 | fi 90 | elif [[ "$PKG_MANAGER" == "yum" ]]; then 91 | if ! rpm -q "$pkg" &>/dev/null; then 92 | echo -e "${YELLOW}安装依赖: $pkg...${RESET}" 93 | sudo yum install -y "$pkg" >/dev/null 2>&1 || { echo -e "${RED}❌ 错误:安装 $pkg 失败${RESET}" >&2; exit 1; } 94 | fi 95 | fi 96 | done 97 | echo -e "${GREEN}✅ 依赖安装完成。${RESET}" 98 | } 99 | 100 | 101 | configure_firewall() { 102 | local firewall_cmd="" 103 | local firewall_service_name="" 104 | local ssh_port="" 105 | 106 | # 提示用户输入 SSH 端口 107 | read -r -p "请输入需要开放的 SSH 端口,否则可能导致SSH无法连接(默认 22): " ssh_port 108 | ssh_port=${ssh_port:-22} # 如果用户未输入,默认使用 22 端口 109 | 110 | if [[ "$OS_TYPE" == "ubuntu" || "$OS_TYPE" == "debian" ]]; then 111 | firewall_cmd="ufw" 112 | firewall_service_name="ufw" 113 | if sudo "$firewall_cmd" status | grep -q "inactive"; then 114 | echo "y" | sudo "$firewall_cmd" enable >/dev/null 2>&1 || { echo -e "${RED}❌ 错误:UFW 启用失败${RESET}" >&2; exit 1; } 115 | fi 116 | # 检查并开放用户指定的 SSH 端口 117 | if ! sudo "$firewall_cmd" status | grep -q "$ssh_port/tcp"; then 118 | sudo "$firewall_cmd" allow "$ssh_port"/tcp comment 'Allow SSH' >/dev/null || echo -e "${YELLOW}警告: 无法添加 UFW $ssh_port/tcp 规则。${RESET}" >&2 119 | fi 120 | # 检查并开放 HTTP 和 HTTPS 端口 121 | if ! sudo "$firewall_cmd" status | grep -q "80/tcp"; then 122 | sudo "$firewall_cmd" allow 80/tcp comment 'Allow HTTP' >/dev/null || echo -e "${YELLOW}警告: 无法添加 UFW 80/tcp 规则。${RESET}" >&2 123 | fi 124 | if ! sudo "$firewall_cmd" status | grep -q "443/tcp"; then 125 | sudo "$firewall_cmd" allow 443/tcp comment 'Allow HTTPS' >/dev/null || echo -e "${YELLOW}警告: 无法添加 UFW 443/tcp 规则。${RESET}" >&2 126 | fi 127 | echo -e "${GREEN}✅ UFW 已配置开放 $ssh_port, 80 和 443 端口。${RESET}" 128 | 129 | elif [[ "$OS_TYPE" == "centos" || "$OS_TYPE" == "rhel" ]]; then 130 | firewall_cmd="firewall-cmd" 131 | firewall_service_name="firewalld" 132 | sudo systemctl is-active --quiet "$firewall_service_name" || { echo " 启动 Firewalld..."; sudo systemctl start "$firewall_service_name" >/dev/null 2>&1 || { echo -e "${RED}❌ 错误:Firewalld 启动失败${RESET}" >&2; exit 1; }; } 133 | # 检查并开放用户指定的 SSH 端口 134 | if ! sudo "$firewall_cmd" --query-port="$ssh_port"/tcp >/dev/null 2>&1; then 135 | sudo "$firewall_cmd" --zone=public --add-port="$ssh_port"/tcp --permanent >/dev/null || echo -e "${YELLOW}警告: 无法添加 Firewalld $ssh_port/tcp 规则。${RESET}" >&2 136 | fi 137 | # 检查并开放 HTTP 和 HTTPS 端口 138 | if ! sudo "$firewall_cmd" --query-port=80/tcp >/dev/null 2>&1; then 139 | sudo "$firewall_cmd" --zone=public --add-port=80/tcp --permanent >/dev/null || echo -e "${YELLOW}警告: 无法添加 Firewalld 80/tcp 规则。${RESET}" >&2 140 | fi 141 | if ! sudo "$firewall_cmd" --query-port=443/tcp >/dev/null 2>&1; then 142 | sudo "$firewall_cmd" --zone=public --add-port=443/tcp --permanent >/dev/null || echo -e "${YELLOW}警告: 无法添加 Firewalld 443/tcp 规则。${RESET}" >&2 143 | fi 144 | sudo "$firewall_cmd" --reload >/dev/null || echo -e "${YELLOW}警告: Firewalld 配置重载失败。${RESET}" >&2 145 | echo -e "${GREEN}✅ Firewalld 已配置开放 $ssh_port, 80 和 443 端口。${RESET}" 146 | 147 | else 148 | echo -e "${YELLOW}警告: 未识别的防火墙服务,请手动开放端口 $ssh_port, 80 和 443。${RESET}" >&2 149 | fi 150 | } 151 | 152 | # 下载安装 acme.sh 153 | download_acme() { 154 | if [ ! -d "$ACME_INSTALL_PATH" ]; then 155 | curl -fsSL https://get.acme.sh | sh -s -- home "$ACME_INSTALL_PATH" >/dev/null 2>&1 || { echo -e "${RED}❌ 错误:下载 acme.sh 失败,请检查网络连接${RESET}" >&2; exit 1; } 156 | echo -e "${GREEN}✅ acme.sh 下载完成。${RESET}" 157 | else 158 | true 159 | fi 160 | } 161 | 162 | # 查找 acme.sh 命令路径 163 | find_acme_cmd() { 164 | export PATH="$ACME_INSTALL_PATH:$PATH" 165 | ACME_CMD=$(command -v acme.sh) 166 | if [ -z "$ACME_CMD" ]; then 167 | echo -e "${RED}❌ 错误:找不到 acme.sh 命令。请检查安装或 PATH。${RESET}" >&2 168 | exit 1 169 | fi 170 | echo -e "${GREEN}✅ 找到 acme.sh 可执行文件。${RESET}" 171 | } 172 | 173 | # 更新 acme.sh 174 | update_acme() { 175 | "$ACME_CMD" --upgrade >/dev/null 2>&1 || echo -e "${YELLOW}警告:acme.sh 更新失败${RESET}" >&2 176 | "$ACME_CMD" --update-account --days 60 >/dev/null 2>&1 || echo -e "${YELLOW}警告:acme.sh 账户信息更新失败${RESET}" >/dev/null 177 | echo -e "${GREEN}✅ acme.sh 更新完成。${RESET}" 178 | } 179 | 180 | # 申请 SSL 证书 181 | issue_cert() { 182 | # !!! 请注意: --pre-hook 和 --post-hook 适用于常见的 Web 服务器 (nginx, apache2)。 183 | # !!! 如果您使用其他 Web 服务器或不需要停止/启动,请根据实际情况修改或移除这些 hook。 184 | # !!! Standalone 模式需要确保 80 端口在验证时可用。 185 | # !!! 添加 --force 参数以强制覆盖可能已存在的域密钥 186 | if ! "$ACME_CMD" --issue --standalone -d "$DOMAIN" --server "$CA_SERVER" --force \ 187 | --pre-hook "systemctl stop nginx 2>/dev/null || systemctl stop apache2 2>/dev/null || true" \ 188 | --post-hook "systemctl start nginx 2>/dev/null || systemctl start apache2 2>/dev/null || true" >/dev/null 2>&1; then 189 | echo -e "${RED}❌ 错误:证书申请失败。${RESET}" >&2 190 | echo " 正在进行清理..." >&2 191 | "$ACME_CMD" --revoke -d "$DOMAIN" --server "$CA_SERVER" >/dev/null 2>&1 || true 192 | "$ACME_CMD" --remove -d "$DOMAIN" --server "$CA_SERVER" >/dev/null 2>&1 || true 193 | exit 1 194 | fi 195 | echo -e "${GREEN}✅ 证书申请成功!${RESET}" 196 | } 197 | 198 | # 安装证书 199 | install_cert() { 200 | # 设置统一的证书安装目录 201 | CERT_KEY_DIR="/etc/ssl/$DOMAIN" 202 | sudo mkdir -p "$CERT_KEY_DIR" >/dev/null 2>&1 || { echo -e "${RED}❌ 错误:创建证书目录失败${RESET}" >&2; exit 1; } 203 | 204 | # 使用动态找到的 acme.sh 命令进行安装到统一目录 205 | # !!! 注意 reloadcmd 需要根据 Web 服务器修改 206 | if sudo "$ACME_CMD" --installcert -d "$DOMAIN" \ 207 | --key-file "${CERT_KEY_DIR}/${DOMAIN}.key" \ 208 | --fullchain-file "${CERT_KEY_DIR}/${DOMAIN}.crt" \ 209 | --reloadcmd "systemctl reload nginx 2>/dev/null || systemctl reload apache2 2>/dev/null || true" >/dev/null 2>&1; then 210 | 211 | sudo chmod 600 "${CERT_KEY_DIR}/${DOMAIN}.key" >/dev/null 2>&1 || echo -e "${YELLOW}警告:设置私钥文件权限失败。${RESET}" >&2 212 | sudo chown root:root "${CERT_KEY_DIR}/${DOMAIN}.key" >/dev/null 2>&1 || echo -e "${YELLOW}警告:设置私钥文件所有者失败。${RESET}" >&2 213 | echo -e "${GREEN}✅ 证书安装完成。${RESET}" 214 | else 215 | echo -e "${RED}❌ 错误:证书安装失败!${RESET}" >&2 216 | exit 1 217 | fi 218 | } 219 | 220 | # --- 主体逻辑 --- 221 | 222 | check_root 223 | get_user_input 224 | detect_os 225 | 226 | echo "➡️ 依赖安装中..." >&2 227 | install_dependencies 228 | configure_firewall # 配置防火墙开放端口 229 | 230 | download_acme 231 | find_acme_cmd # 在调用 acme.sh 之前查找命令 232 | 233 | update_acme # 更新 acme.sh 234 | 235 | echo "➡️ 证书申请中..." >&2 236 | issue_cert # 申请证书 237 | install_cert # 安装证书并设置权限 238 | 239 | echo "➡️ 配置自动续期..." >&2 240 | # 调用 acme.sh 内置的安装 cronjob 功能,会自动设置定时任务 241 | sudo "$ACME_CMD" --install-cronjob >/dev/null 2>&1 || echo -e "${YELLOW}警告:配置 acme.sh 自动续期任务失败。请手动运行 'sudo \$HOME/.acme.sh/acme.sh --install-cronjob' 进行配置。${RESET}" >&2 242 | 243 | echo -e "${GREEN}✅ 自动续期已通过 acme.sh 内置功能配置。${RESET}" >&2 244 | 245 | 246 | echo "===============================================" 247 | echo -e "${GREEN}✅ 脚本执行完毕。${RESET}" 248 | echo "===============================================" 249 | echo -e "${GREEN}证书文件: ${BOLD}${CERT_KEY_DIR}/${DOMAIN}.crt${RESET}" 250 | echo -e "${GREEN}私钥文件: ${BOLD}${CERT_KEY_DIR}/${DOMAIN}.key${RESET}" 251 | echo -e "${GREEN}自动续期已通过 acme.sh 内置功能配置完成。" 252 | echo -e "${YELLOW}提示: 您可以通过 'sudo crontab -l'来检查任务是否成功设置。${RESET}" >&2 253 | 254 | echo "===============================================" 255 | 256 | exit 0 -------------------------------------------------------------------------------- /config_template/config_fakeiptun12.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": { 3 | "servers": [ 4 | {"tag": "local", "type": "udp", "server": "223.5.5.5"}, 5 | {"tag": "public", "type": "https", "server": "dns.alidns.com", "domain_resolver": "local"}, 6 | {"tag": "foreign", "type": "https", "server": "dns.google", "domain_resolver": "local"}, 7 | {"tag": "fakeip", "type": "fakeip", "inet4_range": "198.18.0.0/15", "inet6_range": "fc00::/18"} 8 | ], 9 | "rules": [ 10 | {"clash_mode": "direct", "server": "local"}, 11 | {"clash_mode": "global", "server": "foreign"}, 12 | {"rule_set": ["geosite-cn", "geosite-steamcn", "geosite-apple"], "server": "local"}, 13 | {"query_type": ["A", "AAAA"], "server": "fakeip", "rewrite_ttl": 1} 14 | ], 15 | "final": "foreign", 16 | "strategy": "ipv4_only", 17 | "independent_cache": true 18 | }, 19 | "outbounds": [ 20 | {"tag": "🚀 默认代理", "type": "selector", "outbounds": ["🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择", "♻️ 自动选择"]}, 21 | {"tag": "🧠 AI", "type": "selector", "outbounds": ["🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动"]}, 22 | {"tag": "📹 YouTube", "type": "selector", "outbounds": ["🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 23 | {"tag": "🍀 Google", "type": "selector", "outbounds": ["🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 24 | {"tag": "👨‍💻 Github", "type": "selector", "outbounds": ["🇯🇵 日本手动", "🇭🇰 香港手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 25 | {"tag": "📲 Telegram", "type": "selector", "outbounds": ["🇸🇬 狮城手动", "🇭🇰 香港手动", "🇯🇵 日本手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 26 | {"tag": "🎵 TikTok", "type": "selector", "outbounds": ["🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 27 | {"tag": "🎥 Netflix", "type": "selector", "outbounds": ["🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 28 | {"tag": "💶 PayPal", "type": "selector", "outbounds": ["🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 29 | {"tag": "🎮 Steam", "type": "selector", "outbounds": ["🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 30 | {"tag": "🪟 Microsoft", "type": "selector", "outbounds": ["🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 31 | {"tag": "🐬 OneDrive", "type": "selector", "outbounds": ["🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择"]}, 32 | {"tag": "🍏 Apple", "type": "selector", "outbounds": ["➡️ 直连", "🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动"]}, 33 | {"tag": "🐠 漏网之鱼", "type": "selector", "outbounds": ["🚀 默认代理", "➡️ 直连"]}, 34 | {"tag": "🇭🇰 香港手动", "type": "selector", "outbounds": ["{all}"], "filter": [{"action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"]}, {"action": "exclude", "keywords": ["免费"]}]}, 35 | {"tag": "🇯🇵 日本手动", "type": "selector", "outbounds": ["{all}"], "filter": [{"action": "include", "keywords": ["🇯🇵|JP|jp|日本|日|Japan"]}, {"action": "exclude", "keywords": ["免费"]}]}, 36 | {"tag": "🇸🇬 狮城手动", "type": "selector", "outbounds": ["{all}"], "filter": [{"action": "include", "keywords": ["新加坡|坡|狮城|SG|Singapore"]}, {"action": "exclude", "keywords": ["免费"]}]}, 37 | {"tag": "🇺🇲 美国手动", "type": "selector", "outbounds": ["{all}"], "filter": [{"action": "include", "keywords": ["🇺🇸|US|us|美国|美|United States"]}, {"action": "exclude", "keywords": ["AUS|RUS|免费"]}]}, 38 | {"tag": "🐸 手动选择", "type": "selector", "outbounds": ["{all}"], "filter": [{"action": "exclude", "keywords": ["网站|流量|地址|剩余|过期|免费|时间|有效|Traffic|ExpireDate|GB|Expire Date"]}]}, 39 | {"tag": "♻️ 自动选择", "type": "urltest", "outbounds": ["{all}"], "filter": [{"action": "exclude", "keywords": ["官网|到期时间|剩余|流量|套餐|免费|订阅|全球直连|GB|Expire Date|Traffic|ExpireDate"]}], "interval": "10m", "tolerance": 100}, 40 | {"tag": "🍃 延迟辅助", "type": "urltest", "outbounds": ["🚀 默认代理", "➡️ 直连"]}, 41 | {"tag": "GLOBAL", "type": "selector", "outbounds": ["🚀 默认代理", "🧠 AI", "📹 YouTube", "🍀 Google", "👨‍💻 Github", "📲 Telegram", "🎵 TikTok", "🎥 Netflix", "💶 PayPal", "🎮 Steam", "🪟 Microsoft", "🐬 OneDrive", "🍏 Apple", "🐠 漏网之鱼", "🇭🇰 香港手动", "🇯🇵 日本手动", "🇸🇬 狮城手动", "🇺🇲 美国手动", "🐸 手动选择", "♻️ 自动选择", "🍃 延迟辅助", "➡️ 直连"]}, 42 | {"tag": "➡️ 直连", "type": "direct"} 43 | ], 44 | "route": { 45 | "rules": [ 46 | {"action": "sniff", "sniffer": ["http", "tls", "quic", "dns"]}, 47 | {"type": "logical", "mode": "or", "rules": [{"port": 53}, {"protocol": "dns"}], "action": "hijack-dns"}, 48 | {"ip_is_private": true, "outbound": "➡️ 直连"}, 49 | {"clash_mode": "direct", "outbound": "➡️ 直连"}, 50 | {"clash_mode": "global", "outbound": "GLOBAL"}, 51 | {"rule_set": "geosite-ai", "outbound": "🧠 AI"}, 52 | {"rule_set": "geosite-youtube", "outbound": "📹 YouTube"}, 53 | {"rule_set": "geosite-google", "outbound": "🍀 Google"}, 54 | {"rule_set": "geosite-github", "outbound": "👨‍💻 Github"}, 55 | {"rule_set": "geosite-onedrive", "outbound": "🐬 OneDrive"}, 56 | {"rule_set": "geosite-microsoft", "outbound": "🪟 Microsoft"}, 57 | {"rule_set": "geosite-apple", "outbound": "🍏 Apple"}, 58 | {"rule_set": "geosite-telegram", "outbound": "📲 Telegram"}, 59 | {"rule_set": "geosite-tiktok", "outbound": "🎵 TikTok"}, 60 | {"rule_set": "geosite-netflix", "outbound": "🎥 Netflix"}, 61 | {"rule_set": "geosite-paypal", "outbound": "💶 PayPal"}, 62 | {"rule_set": "geosite-steamcn", "outbound": "➡️ 直连"}, 63 | {"rule_set": "geosite-steam", "outbound": "🎮 Steam"}, 64 | {"rule_set": "geosite-!cn", "outbound": "🚀 默认代理"}, 65 | {"rule_set": "geosite-cn", "outbound": "➡️ 直连"}, 66 | {"rule_set": "geoip-google", "outbound": "🍀 Google"}, 67 | {"rule_set": "geoip-apple", "outbound": "🍏 Apple"}, 68 | {"rule_set": "geoip-telegram", "outbound": "📲 Telegram"}, 69 | {"rule_set": "geoip-netflix", "outbound": "🎥 Netflix"}, 70 | {"rule_set": "geoip-cn", "outbound": "➡️ 直连"} 71 | ], 72 | "rule_set": [ 73 | {"tag": "geosite-ai", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ai-!cn.srs", "download_detour": "➡️ 直连"}, 74 | {"tag": "geosite-youtube", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/youtube.srs", "download_detour": "➡️ 直连"}, 75 | {"tag": "geosite-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/google.srs", "download_detour": "➡️ 直连"}, 76 | {"tag": "geosite-github", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs", "download_detour": "➡️ 直连"}, 77 | {"tag": "geosite-onedrive", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/onedrive.srs", "download_detour": "➡️ 直连"}, 78 | {"tag": "geosite-microsoft", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/microsoft.srs", "download_detour": "➡️ 直连"}, 79 | {"tag": "geosite-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/apple.srs", "download_detour": "➡️ 直连"}, 80 | {"tag": "geosite-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/telegram.srs", "download_detour": "➡️ 直连"}, 81 | {"tag": "geosite-tiktok", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/tiktok.srs", "download_detour": "➡️ 直连"}, 82 | {"tag": "geosite-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/netflix.srs", "download_detour": "➡️ 直连"}, 83 | {"tag": "geosite-paypal", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/paypal.srs", "download_detour": "➡️ 直连"}, 84 | {"tag": "geosite-steamcn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/steam@cn.srs", "download_detour": "➡️ 直连"}, 85 | {"tag": "geosite-steam", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/steam.srs", "download_detour": "➡️ 直连"}, 86 | {"tag": "geosite-!cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/geolocation-!cn.srs", "download_detour": "➡️ 直连"}, 87 | {"tag": "geosite-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/cn.srs", "download_detour": "➡️ 直连"}, 88 | {"tag": "geoip-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/google.srs", "download_detour": "➡️ 直连"}, 89 | {"tag": "geoip-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo-lite/geoip/apple.srs", "download_detour": "➡️ 直连"}, 90 | {"tag": "geoip-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/telegram.srs", "download_detour": "➡️ 直连"}, 91 | {"tag": "geoip-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/netflix.srs", "download_detour": "➡️ 直连"}, 92 | {"tag": "geoip-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://github.com/qljsyph/ruleset-icon/raw/refs/heads/main/sing-box/geoip/China-ASN-combined-ip.srs", "download_detour": "➡️ 直连"} 93 | ], 94 | "final": "🐠 漏网之鱼", 95 | "auto_detect_interface": true, 96 | "default_domain_resolver": {"server": "public"} 97 | }, 98 | "inbounds": [ 99 | { 100 | "tag": "tun-in", 101 | "type": "tun", 102 | "address": [ 103 | "172.19.0.1/30", 104 | "fdfe:dcba:9876::1/126" 105 | ], 106 | "mtu": 9000, 107 | "auto_route": true, 108 | "auto_redirect": true, 109 | "strict_route": true 110 | } 111 | ], 112 | "experimental": { 113 | "cache_file": { 114 | "enabled": true, 115 | "path": "/etc/momo/run/cache.db", 116 | "store_fakeip": true 117 | }, 118 | "clash_api": { 119 | "external_controller": "0.0.0.0:9095", 120 | "external_ui": "/etc/sing-box/ui", 121 | "external_ui_download_url": "https://gh-proxy.com/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip", 122 | "external_ui_download_detour": "➡️ 直连", 123 | "secret": "", 124 | "default_mode": "rule" 125 | } 126 | }, 127 | "log": { 128 | "disabled": false, 129 | "level": "info", 130 | "timestamp": true 131 | } 132 | } -------------------------------------------------------------------------------- /debian/menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################# 4 | # 描述: Debian/Ubuntu/Armbian 官方sing-box 全自动脚本 5 | # 版本: 3.0.0 6 | # 说明: Sing-box 服务管理脚本,提供客户端和服务端模式。 7 | ################################################# 8 | 9 | # --- 1. 全局变量和颜色定义 --- 10 | CYAN='\033[0;36m' 11 | GREEN='\033[0;32m' 12 | YELLOW='\033[1;33m' 13 | RED='\033[0;31m' 14 | WHITE='\033[1;37m' 15 | BOLD='\033[1m' 16 | LIGHT_PURPLE='\033[1;35m' 17 | LIGHT_BLUE='\033[1;34m' 18 | NC='\033[0m' 19 | 20 | SCRIPT_DIR="/etc/sing-box/scripts" 21 | INITIALIZED_FILE="$SCRIPT_DIR/.initialized" 22 | ROLE_FILE="$SCRIPT_DIR/.role" 23 | BASE_URL="https://ghfast.top/https://raw.githubusercontent.com/qljsyph/sbshell/refs/heads/main/debian" 24 | ROLE="" # 运行角色: client 或 server 25 | 26 | # 脚本功能列表,按功能分组 27 | SCRIPTS=( 28 | # --- 核心与安装 --- 29 | "menu.sh" # 主菜单 30 | "install_singbox.sh" # 安装/更新 sing-box 31 | "check_update.sh" # 检查 sing-box 更新 32 | "update_scripts.sh" # 更新所有管理脚本 33 | "update_ui.sh" # 更新 Web 控制面板 (Yacd) 34 | 35 | # --- 客户端配置 --- 36 | "manual_input.sh" # 手动输入订阅链接 37 | "manual_update.sh" # 手动更新配置文件 38 | "auto_update.sh" # 配置订阅自动更新 39 | "switch_mode.sh" # 切换 TProxy / TUN 模式 40 | "configure_tproxy.sh" # 配置 TProxy 41 | "configure_tun.sh" # 配置 TUN 42 | 43 | # --- 服务端配置 --- 44 | "update_config.sh" # 更新服务端配置文件 45 | "setup.sh" # (服务端) 依赖安装和证书申请 46 | "ufw.sh" # (服务端) 防火墙配置 47 | 48 | # --- 服务管理 --- 49 | "start_singbox.sh" # 启动 sing-box 50 | "stop_singbox.sh" # 停止 sing-box 51 | "manage_autostart.sh" # 管理开机自启 52 | "check_config.sh" # 检查配置文件语法 53 | 54 | # --- 系统与网络 --- 55 | "check_environment.sh" # 检查系统环境 56 | "set_network.sh" # 配置网络接口 57 | "clean_nft.sh" # 清理 nftables 规则 58 | "kernel.sh" # 更换/管理系统内核 59 | "optimize.sh" # 网络性能优化 60 | "set_defaults.sh" # 设置脚本默认参数 61 | "delaytest.sh" # 外网延迟测试脚本 62 | "commands.sh" # 常用命令速查 63 | ) 64 | 65 | # --- 2. 辅助函数 --- 66 | 67 | # 带有状态提示的脚本执行器 68 | # 用法: run_script "提示信息" "脚本名" ["--quiet"] 69 | run_script() { 70 | local message="$1" 71 | local script_name="$2" 72 | local quiet_mode="$3" 73 | 74 | echo -e "${CYAN}${message}...${NC}" 75 | if [ "$quiet_mode" == "--quiet" ]; then 76 | bash "$SCRIPT_DIR/$script_name" >/dev/null 77 | else 78 | bash "$SCRIPT_DIR/$script_name" 79 | fi 80 | 81 | if [ $? -ne 0 ]; then 82 | echo -e "${RED}${message}失败!${NC}" 83 | return 1 84 | else 85 | # 对于非静默模式,成功信息由子脚本自己提供 86 | if [ "$quiet_mode" == "--quiet" ]; then 87 | echo -e "${GREEN}${message}成功。${NC}" 88 | fi 89 | return 0 90 | fi 91 | } 92 | 93 | # 带有状态提示的 systemctl 命令执行器 94 | # 用法: run_systemctl "提示信息" "操作" 95 | run_systemctl() { 96 | local message="$1" 97 | local action="$2" 98 | 99 | echo -e "${CYAN}${message}...${NC}" 100 | if sudo systemctl "$action" sing-box >/dev/null 2>&1; then 101 | echo -e "${GREEN}${message}成功。${NC}" 102 | return 0 103 | else 104 | echo -e "${RED}${message}失败!${NC}" 105 | return 1 106 | fi 107 | } 108 | 109 | # --- 3. 脚本下载与准备 --- 110 | 111 | # 下载单个脚本 112 | download_script() { 113 | local script="$1" 114 | local retries=3 115 | for ((i=1; i<=retries; i++)); do 116 | if wget -q -O "$SCRIPT_DIR/$script" "$BASE_URL/$script"; then 117 | chmod +x "$SCRIPT_DIR/$script" 118 | return 0 119 | fi 120 | sleep 2 121 | done 122 | echo -e "${YELLOW}下载 $script 失败 (尝试 $retries 次)。${NC}" 123 | return 1 124 | } 125 | 126 | # 并行下载所有脚本 127 | parallel_download_scripts() { 128 | echo -e "${CYAN}开始下载所有必需脚本...${NC}" 129 | local pids=() 130 | local failed_scripts=() 131 | for script in "${SCRIPTS[@]}"; do 132 | download_script "$script" & 133 | pids+=("$!") 134 | done 135 | for pid in "${pids[@]}"; do 136 | if ! wait "$pid"; then 137 | failed_scripts+=("1") 138 | fi 139 | done 140 | if [ ${#failed_scripts[@]} -ne 0 ]; then 141 | echo -e "${RED}一个或多个脚本下载失败,请检查网络并重试。${NC}" 142 | return 1 143 | fi 144 | echo -e "${GREEN}所有脚本下载完成。${NC}" 145 | return 0 146 | } 147 | 148 | # 检查并按需下载缺失的脚本 149 | check_and_download_scripts() { 150 | local missing_scripts=() 151 | for script in "${SCRIPTS[@]}"; do 152 | [ ! -f "$SCRIPT_DIR/$script" ] && missing_scripts+=("$script") 153 | done 154 | 155 | if [ ${#missing_scripts[@]} -ne 0 ]; then 156 | echo -e "${YELLOW}发现缺失脚本,正在尝试下载...${NC}" 157 | for script in "${missing_scripts[@]}"; do 158 | download_script "$script" 159 | done 160 | fi 161 | } 162 | 163 | # 清理旧脚本并下载最新版本 164 | prepare_scripts() { 165 | echo -e "${CYAN}正在清理旧脚本...${NC}" 166 | find "$SCRIPT_DIR" -type f -name "*.sh" ! -name "menu.sh" -exec rm -f {} \; 167 | rm -f "$INITIALIZED_FILE" 168 | parallel_download_scripts 169 | } 170 | 171 | # --- 4. 初始化流程 --- 172 | 173 | # 客户端初始化 174 | client_initialize() { 175 | echo -e "${CYAN}--- 开始客户端初始化 ---${NC}" 176 | prepare_scripts || exit 1 177 | run_script "检查系统环境" "check_environment.sh" --quiet 178 | run_script "安装/更新 sing-box" "install_singbox.sh" --quiet 179 | run_script "配置代理模式" "switch_mode.sh" 180 | run_script "配置订阅链接" "manual_input.sh" 181 | run_script "启动 sing-box" "start_singbox.sh" --quiet 182 | echo -e "${GREEN}--- 客户端初始化完成 ---${NC}" 183 | } 184 | 185 | # 服务端初始化 186 | server_initialize() { 187 | echo -e "${CYAN}--- 开始服务端初始化 ---${NC}" 188 | prepare_scripts || exit 1 189 | run_script "配置防火墙" "ufw.sh" "--auto" 190 | run_script "安装/更新 sing-box" "install_singbox.sh" --quiet 191 | run_script "更新服务端配置" "update_config.sh" 192 | run_systemctl "启动 sing-box 服务" "start" 193 | echo -e "${GREEN}--- 服务端初始化完成 ---${NC}" 194 | } 195 | 196 | # --- 5. 主逻辑 --- 197 | 198 | # 角色选择 199 | select_role() { 200 | echo -e "${CYAN}请选择运行角色: [1] 客户端 [2] 服务端${NC}" 201 | read -rp "输入数字选择: " role_choice 202 | case $role_choice in 203 | 1) ROLE="client" ;; 204 | 2) ROLE="server" ;; 205 | *) echo -e "${YELLOW}无效选择,默认为客户端。${NC}"; ROLE="client" ;; 206 | esac 207 | echo "$ROLE" > "$ROLE_FILE" 208 | } 209 | 210 | # 初始化检查与执行 211 | run_initialization() { 212 | # 首先选择角色 213 | select_role 214 | 215 | echo -e "${YELLOW}为 '$ROLE' 角色进行首次初始化。${NC}" 216 | echo "初始化将自动完成环境检查、sing-box安装、配置等步骤。" 217 | read -rp "按回车开始,或输入 'skip' 仅下载脚本进入菜单: " init_choice 218 | 219 | if [[ "$init_choice" =~ ^[Ss]kip$ ]]; then 220 | echo -e "${CYAN}跳过初始化,仅下载脚本...${NC}" 221 | parallel_download_scripts 222 | else 223 | if [ "$ROLE" = "server" ]; then 224 | server_initialize 225 | else 226 | client_initialize 227 | fi 228 | touch "$INITIALIZED_FILE" # 成功后创建标记 229 | fi 230 | } 231 | 232 | # 创建别名 233 | setup_alias() { 234 | if ! grep -q "alias sb=" ~/.bashrc; then 235 | echo -e "\n# sing-box 快捷方式\nalias sb='bash $SCRIPT_DIR/menu.sh'" >> ~/.bashrc 236 | echo -e "${GREEN}已添加 'sb' 快捷命令到 .bashrc,请运行 'source ~/.bashrc' 或重新登录生效。${NC}" 237 | fi 238 | if [ ! -f /usr/local/bin/sb ]; then 239 | echo -e '#!/bin/bash\nbash /etc/sing-box/scripts/menu.sh "$@"' | sudo tee /usr/local/bin/sb >/dev/null 240 | sudo chmod +x /usr/local/bin/sb 241 | fi 242 | } 243 | 244 | # --- 6. 菜单定义与处理 --- 245 | 246 | # 客户端菜单 247 | show_client_menu() { 248 | echo -e "\n${CYAN}================= sbshell客户端管理菜单 =================${NC}" 249 | echo -e "${BOLD}${LIGHT_BLUE}--- 配置管理 ---${NC}" 250 | echo -e "${LIGHT_BLUE} 1. 模式切换与配置${NC}" 251 | echo -e "${LIGHT_BLUE} 2. 手动更新配置${NC}" 252 | echo -e "${LIGHT_BLUE} 3. 自动更新配置${NC}" 253 | echo -e "${LIGHT_BLUE} 4. 设置默认参数${NC}" 254 | echo -e "${BOLD}${LIGHT_PURPLE}--- 服务控制 ---${NC}" 255 | echo -e "${LIGHT_PURPLE} 5. 启动sing-box${NC}" 256 | echo -e "${LIGHT_PURPLE} 6. 停止sing-box${NC}" 257 | echo -e "${LIGHT_PURPLE} 7. 管理自启动${NC}" 258 | echo -e "${BOLD}${YELLOW}--- 更新与维护 ---${NC}" 259 | echo -e "${YELLOW} 8. 更新sing-box${NC}" 260 | echo -e "${YELLOW} 9. 更新脚本${NC}" 261 | echo -e "${YELLOW}10. 更新面板${NC}" 262 | echo -e "${BOLD}${WHITE}--- 系统与网络 ---${NC}" 263 | echo -e "${WHITE}11. 网络设置${NC}" 264 | echo -e "${WHITE}12. 常用命令${NC}" 265 | echo -e "${WHITE}13. 更换XanMod内核${NC}" 266 | echo -e "${WHITE}14. 网络优化${NC}" 267 | echo -e "${CYAN}----------------------------------------------------${NC}" 268 | echo -e "${GREEN} 0. 退出${NC}" 269 | echo -e "${CYAN}====================================================${NC}" 270 | } 271 | 272 | handle_client_choice() { 273 | read -rp "请选择操作: " choice 274 | case $choice in 275 | 1) run_script "配置代理模式" "switch_mode.sh"; run_script "配置订阅链接" "manual_input.sh"; run_script "启动 sing-box" "start_singbox.sh" --quiet ;; 276 | 2) run_script "手动更新配置" "manual_update.sh" ;; 277 | 3) run_script "自动更新配置" "auto_update.sh" ;; 278 | 4) run_script "设置默认参数" "set_defaults.sh" ;; 279 | 5) run_script "启动sing-box" "start_singbox.sh" --quiet ;; 280 | 6) run_script "停止sing-box" "stop_singbox.sh" --quiet ;; 281 | 7) run_script "管理自启动" "manage_autostart.sh" ;; 282 | 8) if command -v sing-box &> /dev/null; then 283 | run_script "检查 sing-box 更新" "check_update.sh" 284 | else 285 | run_script "安装/更新 sing-box" "install_singbox.sh" 286 | fi 287 | ;; 288 | 9) run_script "更新所有脚本" "update_scripts.sh" ;; 289 | 10) run_script "更新控制面板" "update_ui.sh" ;; 290 | 11) run_script "网络设置" "set_network.sh" ;; 291 | 12) run_script "常用命令" "commands.sh" ;; 292 | 13) run_script "更换XanMod内核" "kernel.sh" ;; 293 | 14) run_script "网络优化" "optimize.sh" ;; 294 | 0) exit 0 ;; 295 | *) echo -e "${RED}无效的选择${NC}" ;; 296 | esac 297 | } 298 | 299 | # 服务端菜单 300 | show_server_menu() { 301 | echo -e "\n${CYAN}================= sbshell服务端管理菜单 =================${NC}" 302 | echo -e "${BOLD}${LIGHT_PURPLE}--- 服务控制 ---${NC}" 303 | echo -e "${LIGHT_PURPLE} 1. 启动sing-box${NC}" 304 | echo -e "${LIGHT_PURPLE} 2. 停止sing-box${NC}" 305 | echo -e "${LIGHT_PURPLE} 3. 重启sing-box${NC}" 306 | echo -e "${LIGHT_PURPLE} 4. 设为自启${NC}" 307 | echo -e "${LIGHT_PURPLE} 5. 查看日志${NC}" 308 | echo -e "${BOLD}${YELLOW}--- 配置与更新 ---${NC}" 309 | echo -e "${YELLOW} 6. 更新配置文件${NC}" 310 | echo -e "${YELLOW} 7. 更新sing-box${NC}" 311 | echo -e "${YELLOW} 8. 更新脚本${NC}" 312 | echo -e "${YELLOW} 9. 证书申请${NC}" 313 | echo -e "${BOLD}${WHITE}--- 系统与网络 ---${NC}" 314 | echo -e "${WHITE}10. 更换XanMod内核${NC}" 315 | echo -e "${WHITE}11. 网络优化${NC}" 316 | echo -e "${WHITE}12. 手动配置防火墙${NC}" 317 | echo -e "${CYAN}----------------------------------------------------${NC}" 318 | echo -e "${GREEN} 0. 退出${NC}" 319 | echo -e "${CYAN}====================================================${NC}" 320 | } 321 | 322 | handle_server_choice() { 323 | read -rp "请选择操作: " choice 324 | case $choice in 325 | 1) run_systemctl "启动sing-box" "start" ;; 326 | 2) run_systemctl "停止sing-box" "stop" ;; 327 | 3) run_systemctl "重启sing-box" "restart" ;; 328 | 4) run_systemctl "设置开机自启" "enable" ;; 329 | 5) sudo journalctl -u sing-box --output cat -f ;; 330 | 6) run_script "更新服务端配置文件" "update_config.sh" ;; 331 | 7) if command -v sing-box &> /dev/null; then 332 | run_script "检查 sing-box 更新" "check_update.sh" 333 | else 334 | run_script "安装/更新 sing-box" "install_singbox.sh" 335 | fi 336 | ;; 337 | 8) run_script "更新脚本" "update_scripts.sh" ;; 338 | 9) run_script "证书申请" "setup.sh" ;; 339 | 10) run_script "更换XanMod内核" "kernel.sh" ;; 340 | 11) run_script "网络优化" "optimize.sh" ;; 341 | 12) run_script "手动配置防火墙" "ufw.sh" ;; 342 | 0) exit 0 ;; 343 | *) echo -e "${RED}无效的选择${NC}" ;; 344 | esac 345 | } 346 | 347 | # --- 7. 脚本入口 --- 348 | 349 | main() { 350 | # 确保脚本目录存在 351 | sudo mkdir -p "$SCRIPT_DIR" 352 | sudo chown "$(whoami)":"$(whoami)" "$SCRIPT_DIR" 353 | cd "$SCRIPT_DIR" || exit 1 354 | 355 | # 如果通过快捷方式 sb 调用,则第一个参数可能是菜单选项 356 | if [ "$1" == "menu" ]; then 357 | shift 358 | fi 359 | 360 | # 检查是否已经初始化过 361 | if [ ! -f "$INITIALIZED_FILE" ]; then 362 | run_initialization 363 | else 364 | # 如果已经初始化,加载角色并检查脚本 365 | if [ -f "$ROLE_FILE" ]; then 366 | ROLE=$(cat "$ROLE_FILE") 367 | else 368 | # 兼容旧版本,如果 .initialized 存在但 .role 不存在 369 | echo -e "${YELLOW}角色文件丢失,引导重新初始化。${NC}" 370 | sudo rm -f "$INITIALIZED_FILE" 371 | run_initialization 372 | fi 373 | check_and_download_scripts 374 | fi 375 | 376 | # 如果初始化流程被跳过或失败,ROLE 可能为空 377 | if [ -z "$ROLE" ]; then 378 | # 尝试从文件再次加载角色,以防 'skip' 初始化后直接运行 379 | if [ -f "$ROLE_FILE" ]; then 380 | ROLE=$(cat "$ROLE_FILE") 381 | else 382 | echo -e "${RED}未设置角色,无法继续。请重新运行以完成初始化。${NC}" 383 | exit 1 384 | fi 385 | fi 386 | 387 | # 设置别名 388 | setup_alias 389 | 390 | # 进入主循环 391 | if [ "$ROLE" = "server" ]; then 392 | while true; do show_server_menu; handle_server_choice; done 393 | else 394 | while true; do show_client_menu; handle_client_choice; done 395 | fi 396 | } 397 | 398 | # 执行主函数 399 | main "$@" 400 | -------------------------------------------------------------------------------- /config_template/config_fakeiptrpoxy12.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": { 3 | "servers": [ 4 | {"tag": "local", "type": "udp", "server": "114.114.114.114"}, 5 | {"tag": "public", "type": "udp", "server": "223.5.5.5"}, 6 | {"tag": "foreign", "type": "udp", "server": "8.8.8.8"}, 7 | {"tag": "fakeip", "type": "fakeip", "inet4_range": "198.18.0.0/15", "inet6_range": "fc00::/18"} 8 | ], 9 | "rules": [ 10 | {"clash_mode": "direct", "server": "local"}, 11 | {"clash_mode": "global", "server": "fakeip"}, 12 | {"rule_set": ["geosite-cn", "geosite-private"], "server": "local"}, 13 | {"query_type": ["A", "AAAA"], "server": "fakeip", "rewrite_ttl": 1} 14 | ], 15 | "final": "foreign", 16 | "strategy": "ipv4_only", 17 | "independent_cache": true 18 | }, 19 | "outbounds": [ 20 | { "tag": "🚀 节点选择", "type": "selector", "outbounds": ["🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🔯 美国自动", "🍔 美国", "🍤 手动切换", "🍖 自动选择", "➡️ 直连"]}, 21 | { "tag": "📹 YouTube", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🔯 美国自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 22 | { "tag": "🤖 OpenAI", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🥘 新加坡", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 23 | { "tag": "🍀 Google", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 24 | { "tag": "👨‍💻 Github", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 25 | { "tag": "🪟 Microsoft", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "➡️ 直连"] }, 26 | { "tag": "🐬 OneDrive", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 27 | { "tag": "🎵 TikTok", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 28 | { "tag": "🎥 Netflix", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 29 | { "tag": "🎥 Disney+", "type": "selector", "outbounds": ["🚀 节点选择", "🍖 自动选择", "🔯 香港自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 30 | { "tag": "🍄 Game", "type": "selector", "outbounds": ["🚀 节点选择", "➡️ 直连", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 31 | { "tag": "📲 Telegram", "type": "selector", "outbounds": ["🚀 节点选择", "🔯 香港自动", "🔯 美国自动", "🍨 香港", "🥘 新加坡", "🇨🇳 台湾", "🍣 日本", "🍔 美国", "🍤 手动切换"] }, 32 | { "tag": "🍏 Apple", "type": "selector", "outbounds": ["➡️ 直连", "🍨 香港", "🇨🇳 台湾", "🍣 日本", "🍔 美国"] }, 33 | { "tag": "⏱️ Speedtest", "type": "selector", "outbounds": ["➡️ 直连", "🍖 自动选择", "🚀 节点选择", "🍤 手动切换", "🍔 美国"] }, 34 | { "tag": "🕸️ 兜底策略", "type": "selector", "outbounds": ["🚀 节点选择","➡️ 直连"] }, 35 | { "tag": "🍤 手动切换", "type": "selector", "outbounds": ["{all}"]}, 36 | { "tag": "🍨 香港", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }] }, 37 | { "tag": "🇨🇳 台湾", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇹🇼|TW|tw|台湾|台|TaiWan"] }] }, 38 | { "tag": "🥘 新加坡", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇸🇬|SG|sg|新加坡|加坡|Singapore"] }] }, 39 | { "tag": "🍣 日本", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇯🇵|JP|jp|日本|日|Japan"] }] }, 40 | { "tag": "🍔 美国", "type": "selector", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇺🇸|US|us|美国|美|United States"] }, { "action": "exclude", "keywords": ["香港|港|HK|hk|HongKong"] }] }, 41 | { "tag": "🔯 香港自动", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇭🇰|HK|hk|香港|港|HongKong"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 42 | { "tag": "🔯 美国自动", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "include", "keywords": ["🇺🇸|US|us|美国|美|United States"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 43 | { "tag": "🍖 自动选择", "type": "urltest", "outbounds": ["{all}"], "filter": [{ "action": "exclude", "keywords": ["网站|地址|剩余|过期|时间|有效"] }], "url": "http://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50 }, 44 | { "tag": "GLOBAL", "type": "selector", "outbounds": ["🚀 节点选择", "📹 YouTube", "🤖 OpenAI", "🍀 Google", "👨‍💻 Github", "🪟 Microsoft", "🐬 OneDrive", "🎵 TikTok", "🎥 Netflix", "🎥 Disney+", "🍄 Game", "📲 Telegram", "🍏 Apple", "⏱️ Speedtest", "🕸️ 兜底策略", "🍤 手动切换", "🍨 香港", "🇨🇳 台湾", "🥘 新加坡", "🍣 日本", "🍔 美国", "🔯 香港自动", "🔯 美国自动", "🍖 自动选择"]}, 45 | { "tag": "➡️ 直连", "type": "direct" } 46 | ], 47 | "route": { 48 | "rules": [ 49 | {"action": "sniff", "sniffer": ["http", "tls", "quic", "dns"]}, 50 | {"type": "logical", "mode": "or", "rules": [{"port": 53}, {"protocol": "dns"}], "action": "hijack-dns"}, 51 | {"ip_is_private": true, "outbound": "➡️ 直连"}, 52 | {"clash_mode": "direct", "outbound": "➡️ 直连"}, 53 | {"clash_mode": "global", "outbound": "GLOBAL"}, 54 | {"rule_set": "geosite-private", "outbound": "➡️ 直连"}, 55 | {"domain_keyword": ["midjourney","gogemini","flywheelstaging"], "outbound": "🤖 OpenAI"}, 56 | {"domain_suffix": ["deepl.com", "icloudnative.io"], "outbound": "🤖 OpenAI"}, 57 | {"rule_set": ["geosite-chat", "geosite-discord", "geoip-aibu"], "outbound": "🤖 OpenAI"}, 58 | {"rule_set": "geosite-youtube", "outbound": "📹 YouTube"}, 59 | {"rule_set": "geosite-github", "outbound": "👨‍💻 Github"}, 60 | {"rule_set": ["geosite-google", "geoip-google"], "outbound": "🍀 Google"}, 61 | {"rule_set": ["geosite-telegram", "geoip-telegram"], "outbound": "📲 Telegram"}, 62 | {"rule_set": "geosite-tiktok", "outbound": "🎵 TikTok"}, 63 | {"rule_set": ["geosite-netflix", "geoip-netflix"], "outbound": "🎥 Netflix"}, 64 | {"rule_set": "geosite-disney", "outbound": "🎥 Disney+"}, 65 | {"rule_set": "geosite-bahamut", "outbound": "🇨🇳 台湾"}, 66 | {"rule_set": ["geosite-steam", "geosite-Xbox", "geosite-playstation", "geosite-Nintendo", "geosite-nintendo@cn"], "outbound": "🍄 Game"}, 67 | {"rule_set": ["geosite-apple", "geoip-apple"], "outbound": "🍏 Apple"}, 68 | {"rule_set": "geosite-speedtest", "outbound": "⏱️ Speedtest"}, 69 | {"rule_set": "geosite-onedrive", "outbound": "🐬 OneDrive"}, 70 | {"rule_set": "geosite-microsoft", "outbound": "🪟 Microsoft"}, 71 | {"rule_set": "geosite-geolocation-!cn", "outbound": "🚀 节点选择"}, 72 | {"rule_set": ["geoip-cn", "geosite-cn"], "outbound": "➡️ 直连"} 73 | ], 74 | "rule_set": [ 75 | { "tag": "geosite-chat", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ai-chat-!cn.srs", "download_detour": "➡️ 直连" }, 76 | { "tag": "geosite-youtube", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/youtube.srs", "download_detour": "➡️ 直连" }, 77 | { "tag": "geosite-disney", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/disney.srs", "download_detour": "➡️ 直连" }, 78 | { "tag": "geosite-bahamut", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/disney.srs", "download_detour": "d➡️ 直连" }, 79 | { "tag": "geosite-adobe", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/qljsyph/ruleset-icon/refs/heads/main/sing-box/geosite/adobe.srs", "download_detour": "➡️ 直连" }, 80 | { "tag": "geosite-steam", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/steam.srs", "download_detour": "➡️ 直连" }, 81 | { "tag": "geosite-Xbox", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/xbox.srs", "download_detour": "➡️ 直连" }, 82 | { "tag": "geosite-playstation", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/playstation.srs", "download_detour": "➡️ 直连" }, 83 | { "tag": "geosite-Nintendo", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/nintendo.srs", "download_detour": "➡️ 直连" }, 84 | { "tag": "geosite-nintendo@cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/nintendo@cn.srs", "download_detour": "➡️ 直连" }, 85 | { "tag": "geosite-speedtest", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/ookla-speedtest.srs", "download_detour": "➡️ 直连" }, 86 | { "tag": "geosite-discord", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/discord.srs", "download_detour": "➡️ 直连" }, 87 | { "tag": "geosite-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/google.srs", "download_detour": "➡️ 直连" }, 88 | { "tag": "geosite-github", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs", "download_detour": "➡️ 直连" }, 89 | { "tag": "geosite-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/telegram.srs", "download_detour": "➡️ 直连" }, 90 | { "tag": "geosite-tiktok", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/tiktok.srs", "download_detour": "➡️ 直连" }, 91 | { "tag": "geosite-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/netflix.srs", "download_detour": "➡️ 直连" }, 92 | { "tag": "geosite-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/apple.srs", "download_detour": "➡️ 直连" }, 93 | { "tag": "geosite-microsoft", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/microsoft.srs", "download_detour": "➡️ 直连" }, 94 | { "tag": "geosite-onedrive", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/onedrive.srs", "download_detour": "➡️ 直连" }, 95 | { "tag": "geosite-geolocation-!cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/geolocation-!cn.srs", "download_detour": "➡️ 直连" }, 96 | { "tag": "geosite-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/cn.srs", "download_detour": "➡️ 直连" }, 97 | { "tag": "geosite-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/private.srs", "download_detour": "➡️ 直连" }, 98 | 99 | { "tag": "geoip-google", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/google.srs", "download_detour": "➡️ 直连" }, 100 | { "tag": "geoip-telegram", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/telegram.srs", "download_detour": "➡️ 直连" }, 101 | { "tag": "geoip-netflix", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/netflix.srs", "download_detour": "➡️ 直连" }, 102 | { "tag": "geoip-aibu", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/Loyalsoldier/geoip/refs/heads/release/srs/ai.srs", "download_detour": "➡️ 直连" }, 103 | { "tag": "geoip-apple", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo-lite/geoip/apple.srs", "download_detour": "➡️ 直连" }, 104 | { "tag": "geoip-cn", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/cn.srs", "download_detour": "➡️ 直连" }, 105 | { "tag": "geoip-private", "type": "remote", "format": "binary", "url": "https://gh-proxy.com/https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/private.srs", "download_detour": "➡️ 直连" } 106 | ], 107 | "final": "🕸️ 兜底策略", 108 | "auto_detect_interface": true, 109 | "default_mark": 666, 110 | "default_domain_resolver": {"server": "public"} 111 | }, 112 | "inbounds": [ 113 | { 114 | "type": "tproxy", 115 | "tag": "tproxy-in", 116 | "listen": "0.0.0.0", 117 | "listen_port": 7895 118 | } 119 | ], 120 | "experimental": { 121 | "cache_file": { 122 | "enabled": true, 123 | "path": "/etc/sing-box/cache.db", 124 | "store_fakeip": true 125 | }, 126 | "clash_api": { 127 | "external_controller": "0.0.0.0:9095", 128 | "external_ui": "/etc/sing-box/ui", 129 | "external_ui_download_url": "https://ghfast.top/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip", 130 | "external_ui_download_detour": "➡️ 直连", 131 | "secret": "", 132 | "default_mode": "rule" 133 | } 134 | }, 135 | "log": { 136 | "disabled": false, 137 | "level": "info", 138 | "timestamp": true 139 | } 140 | } --------------------------------------------------------------------------------