snell脚本

支持Debian、Ubuntu系统 支持仅v6机器 可以多配置启动

snell安装版本v5 向下兼容客户端v4 支持交互修改的参数: 端口、PSK、OBFS、TFO、DNS

脚本

bash <(curl -sL https://raw.githubusercontent.com/Emokui/Nothing/Zero/Shell/snell.sh)

源码

#!/bin/bash

RED='\033[0;31m'
GREEN="\033[1;32m"
YELLOW='\033[1;33m'
BLUE="\033[1;34m"
PLAIN='\033[0m'

SNELL_DIR="/root/snell"
SNELL_CONFIGS="${SNELL_DIR}/configs"
SNELL_BIN="${SNELL_DIR}/snell-server"
SNELL_VERSION_FILE="${SNELL_DIR}/version"
TFO_SYSCTL_CONF="/etc/sysctl.d/local.conf"

pause_and_clear() {
  read -n 1 -s -r -p "$(echo -e "${YELLOW}按任意键继续...${PLAIN}")"
  clear
}

snell_installed() {
  [[ -f "$SNELL_BIN" ]] && [[ -x "$SNELL_BIN" ]]
}

snell_config_exists() {
  [[ -d "$SNELL_CONFIGS" ]] && [[ $(ls -A "$SNELL_CONFIGS"/*.conf 2>/dev/null) ]]
}

tfo_enabled() {
  [[ "$(cat /proc/sys/net/ipv4/tcp_fastopen 2>/dev/null)" == "3" ]] && grep -q "net.ipv4.tcp_fastopen = 3" "$TFO_SYSCTL_CONF" 2>/dev/null
}

has_ipv4() {
  ip -4 addr show scope global | grep -q inet
}

get_latest_snell_version() {
    uname_arch=$(uname -m)
    if [[ "$uname_arch" == "i686" ]] || [[ "$uname_arch" == "i386" ]]; then
        arch="i386"
    elif [[ "$uname_arch" == *"armv7"* ]] || [[ "$uname_arch" == "armv6l" ]]; then
        arch="armv7l"
    elif [[ "$uname_arch" == *"armv8"* ]] || [[ "$uname_arch" == "aarch64" ]]; then
        arch="aarch64"
    else
        arch="amd64"
    fi

    page=$(curl -s "https://kb.nssurge.com/surge-knowledge-base/zh/release-notes/snell")

    all_links=$(echo "$page" | grep -oE "https://dl.nssurge.com/snell/snell-server-v[0-9]+\.[0-9]+\.[0-9]+[a-z0-9]*-linux-${arch}\.zip")

    latest_stable=$(echo "$all_links" | grep -vE 'b[0-9]+|beta' | sort -V | tail -n 1)
    latest_beta=$(echo "$all_links" | grep -E 'b[0-9]+|beta' | sort -V | tail -n 1)

    if ! has_ipv4; then
      latest_stable=$(echo "$latest_stable" | sed 's|dl.nssurge.com|snell-cdn.pages.dev|')
      latest_beta=$(echo "$latest_beta" | sed 's|dl.nssurge.com|snell-cdn.pages.dev|')
    fi

    if [[ -n "$latest_stable" ]]; then
        SNELL_VERSION=$(echo "$latest_stable" | sed -E "s/.*snell-server-(v[0-9]+\.[0-9]+\.[0-9]+)-linux-${arch}\.zip/\1/")
        SNELL_ZIP=$(basename "$latest_stable")
        SNELL_URL="$latest_stable"
        SNELL_ARCH="$arch"
    else
        SNELL_VERSION=""
        SNELL_ZIP=""
        SNELL_URL=""
        SNELL_ARCH="$arch"
    fi

    if [[ -n "$latest_beta" ]]; then
        SNELL_BETA_VERSION=$(echo "$latest_beta" | sed -E "s/.*snell-server-(v[0-9]+\.[0-9]+\.[0-9]+[a-z0-9]*)-linux-${arch}\.zip/\1/")
        SNELL_BETA_ZIP=$(basename "$latest_beta")
        SNELL_BETA_URL="$latest_beta"
        SNELL_BETA_ARCH="$arch"
    else
        SNELL_BETA_VERSION=""
        SNELL_BETA_ZIP=""
        SNELL_BETA_URL=""
        SNELL_BETA_ARCH="$arch"
    fi
}

get_latest_snell_beta_version() {
    get_latest_snell_version
    SNELL_VERSION="$SNELL_BETA_VERSION"
    SNELL_ZIP="$SNELL_BETA_ZIP"
    SNELL_URL="$SNELL_BETA_URL"
    SNELL_ARCH="$SNELL_BETA_ARCH"
}

install_unzip_if_missing() {
    if ! command -v unzip >/dev/null 2>&1; then
        echo -e "${YELLOW}未检测到 unzip,正在自动安装...${PLAIN}"
        if command -v apt &>/dev/null; then
            apt update && apt install -y unzip
        elif command -v dnf &>/dev/null; then
            dnf install -y unzip
        elif command -v yum &>/dev/null; then
            yum install -y unzip
        elif command -v apk &>/dev/null; then
            apk add unzip
        elif command -v pacman &>/dev/null; then
            pacman -Sy --noconfirm unzip
        elif command -v zypper &>/dev/null; then
            zypper --non-interactive install unzip
        else
            echo -e "${RED}无法识别的包管理器,unzip 安装失败,请手动安装!${PLAIN}"
            exit 1
        fi
        echo -e "${GREEN}unzip 安装完成${PLAIN}"
    fi
}

auto_enable_tcp_fastopen() {
  if tfo_enabled; then
    return
  fi

  sysctl_conf="$TFO_SYSCTL_CONF"

  if [ -w /proc/sys/net/ipv4/tcp_fastopen ]; then
    echo 3 > /proc/sys/net/ipv4/tcp_fastopen
  fi

  [[ ! -e $sysctl_conf ]] && cat >"$sysctl_conf" <<EOF
net.core.netdev_max_backlog = 4096
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_mtu_probing = 1
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.core.rmem_max = 8388608
net.core.wmem_max = 8388608
net.core.optmem_max = 4194304
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192
EOF
  sysctl --system >/dev/null 2>&1
}

install_snell() {
  clear
  if snell_installed; then
    echo -e "${YELLOW}Snell 已安装,如需更新请选择【4.更新 Snell】${PLAIN}"
    pause_and_clear
    return
  fi
  echo -e "${BLUE}开始安装 Snell...${PLAIN}"

  get_latest_snell_version

  if [[ -z "$SNELL_VERSION" || -z "$SNELL_URL" ]]; then
      echo -e "${RED}未获取到 Snell 最新正式版信息,请检查网络或稍后再试!${PLAIN}"
      pause_and_clear
      return 1
  fi

  mkdir -p "$SNELL_DIR"
  cd "$SNELL_DIR"

  echo -e "${YELLOW}下载 Snell(${SNELL_ARCH},${SNELL_VERSION})...${PLAIN}"
  wget --no-check-certificate -N "$SNELL_URL" -O "$SNELL_ZIP"
  if [[ ! -e "$SNELL_ZIP" ]]; then
      echo -e "${RED}Snell 下载失败,请检查网络连接!${PLAIN}"
      pause_and_clear
      return 1
  else
      install_unzip_if_missing
      unzip -o "$SNELL_ZIP"
  fi

  if [[ ! -e "snell-server" ]]; then
      echo -e "${RED}Snell 解压失败!${PLAIN}"
      pause_and_clear
      return 1
  else
      rm -f "$SNELL_ZIP"
      chmod +x snell-server
      mv -f snell-server "${SNELL_BIN}"
      echo "$SNELL_VERSION" > ${SNELL_VERSION_FILE}
      echo -e "${GREEN}Snell (${SNELL_ARCH}) 已下载安装完成${PLAIN}"
      echo -e "${BLUE}请选择【2.配置 Snell】生成并管理配置文件${PLAIN}"
      pause_and_clear
      return 0
  fi
}

update_snell_stable() {
  clear
  if ! snell_installed; then
    echo -e "${YELLOW}检测到未安装Snell,请先安装并配置${PLAIN}"
    pause_and_clear
    return 1
  fi

  echo -e "${BLUE}开始检查并更新 Snell 正式版 ...${PLAIN}"

  get_latest_snell_version

  if [[ -z "$SNELL_VERSION" || -z "$SNELL_URL" ]]; then
      echo -e "${RED}未获取到 Snell 最新正式版信息,请检查网络或稍后再试!${PLAIN}"
      pause_and_clear
      return 1
  fi

  current_ver=""
  if [[ -f "$SNELL_VERSION_FILE" ]]; then
    current_ver=$(cat "$SNELL_VERSION_FILE")
  fi

  if [[ "$current_ver" == "$SNELL_VERSION" && -f "$SNELL_BIN" ]]; then
    echo -e "${GREEN}Snell 已经是正式版最新版:${SNELL_VERSION}${PLAIN}"
    pause_and_clear
    return 0
  fi

  mkdir -p "$SNELL_DIR"
  cd "$SNELL_DIR"

  echo -e "${YELLOW}下载 Snell 正式版(${SNELL_ARCH}, ${SNELL_VERSION})...${PLAIN}"
  wget --no-check-certificate -N "$SNELL_URL" -O "$SNELL_ZIP"
  if [[ ! -e "$SNELL_ZIP" ]]; then
      echo -e "${RED}Snell 正式版下载失败,请检查网络连接!${PLAIN}"
      pause_and_clear
      return 1
  else
      install_unzip_if_missing
      unzip -o "$SNELL_ZIP"
  fi

  if [[ ! -e "snell-server" ]]; then
      echo -e "${RED}Snell 正式版解压失败!${PLAIN}"
      pause_and_clear
      return 1
else
    rm -f "$SNELL_ZIP"
    chmod +x snell-server
    mv -f snell-server "${SNELL_BIN}"
    echo "$SNELL_VERSION" > ${SNELL_VERSION_FILE}
    echo -e "${GREEN}Snell 已更新到正式版:${SNELL_VERSION} (${SNELL_ARCH})${PLAIN}"
    echo -e "${YELLOW}正在重启所有 Snell systemd 服务...${PLAIN}"
    systemctl daemon-reload
    for svc in /etc/systemd/system/snell@*.service; do
      [ ! -e "$svc" ] && continue
      svc_name=$(basename "$svc")
      systemctl restart "$svc_name"
      echo -e "${GREEN}已重启服务: $svc_name${PLAIN}"
    done
    echo -e "${GREEN}所有 Snell 服务已重启${PLAIN}"
    pause_and_clear
    return 0
  fi
}

update_snell_beta() {
  clear
  if ! snell_installed; then
    echo -e "${YELLOW}检测到未安装Snell,请先安装并配置${PLAIN}"
    pause_and_clear
    return 1
  fi
  echo -e "${BLUE}开始检查并更新 Snell 测试版 ...${PLAIN}"

  get_latest_snell_beta_version

  if [[ -z "$SNELL_VERSION" || -z "$SNELL_URL" ]]; then
    echo -e "${RED}未检测到任何 Snell 测试版!${PLAIN}"
    pause_and_clear
    return 1
  fi

  current_ver=""
  if [[ -f "$SNELL_VERSION_FILE" ]]; then
    current_ver=$(cat "$SNELL_VERSION_FILE")
  fi

  if [[ "$current_ver" == "$SNELL_VERSION" && -f "$SNELL_BIN" ]]; then
    echo -e "${GREEN}Snell 已经是测试版最新版:${SNELL_VERSION}${PLAIN}"
    pause_and_clear
    return 0
  fi

  mkdir -p "$SNELL_DIR"
  cd "$SNELL_DIR"

  echo -e "${YELLOW}下载 Snell 测试版(${SNELL_ARCH}, ${SNELL_VERSION})...${PLAIN}"
  wget --no-check-certificate -N "$SNELL_URL" -O "$SNELL_ZIP"
  if [[ ! -e "$SNELL_ZIP" ]]; then
      echo -e "${RED}Snell 测试版下载失败,请检查网络连接!${PLAIN}"
      pause_and_clear
      return 1
  else
      install_unzip_if_missing
      unzip -o "$SNELL_ZIP"
  fi

  if [[ ! -e "snell-server" ]]; then
      echo -e "${RED}Snell 测试版解压失败!${PLAIN}"
      pause_and_clear
      return 1
else
    rm -f "$SNELL_ZIP"
    chmod +x snell-server
    mv -f snell-server "${SNELL_BIN}"
    echo "$SNELL_VERSION" > ${SNELL_VERSION_FILE}
    echo -e "${GREEN}Snell 已更新到测试版:${SNELL_VERSION} (${SNELL_ARCH})${PLAIN}"
    echo -e "${YELLOW}正在重启所有 Snell systemd 服务...${PLAIN}"
    systemctl daemon-reload
    for svc in /etc/systemd/system/snell@*.service; do
      [ ! -e "$svc" ] && continue
      svc_name=$(basename "$svc")
      systemctl restart "$svc_name"
      echo -e "${GREEN}已重启服务: $svc_name${PLAIN}"
    done
    echo -e "${GREEN}所有 Snell 服务已重启${PLAIN}"
    pause_and_clear
    return 0
  fi
}

update_snell_menu() {
  clear
  echo -e "${BLUE}✦ Snell_Update ✦${PLAIN}"
  echo -e "${GREEN}  1.${PLAIN}更新正式版"
  echo -e "${GREEN}  2.${PLAIN}更新测试版"
  echo -e "${GREEN}  0.${PLAIN}返回主菜单"
  read -p "$(echo -e "${BLUE}✦ Steins Gate ✦ : ${PLAIN}")" update_choice
  case $update_choice in
    1) update_snell_stable ;;
    2) update_snell_beta ;;
    0) return ;;
    *) echo -e "${RED}无效选项,请重新选择${PLAIN}"; pause_and_clear ;;
  esac
}

delete_all_snell() {
  clear
  if ! snell_installed && ! snell_config_exists; then
    echo -e "${YELLOW}未安装及配置 Snell,请先安装并配置 Snell。${PLAIN}"
    pause_and_clear
    return
  fi

  echo -e "${RED}警告!此操作将彻底删除 /root/snell 目录及相关 systemd 服务${PLAIN}"
  read -p "$(echo -e "${YELLOW}确定继续? [y/N]: ${PLAIN}")" confirm
  [[ ! "$confirm" =~ ^[yY]$ ]] && echo -e "${YELLOW}操作已取消${PLAIN}" && pause_and_clear && return

  for svc in /etc/systemd/system/snell@*.service; do
    [ ! -e "$svc" ] && continue
    svc_name=$(basename "$svc")
    systemctl disable --now "$svc_name" &>/dev/null
    rm -f "$svc"
  done

  systemctl daemon-reload

  if [ -d "/root/snell" ]; then
    rm -rf /root/snell
  fi

  echo -e "${GREEN}已彻底删除 /root/snell 及 systemd 服务${PLAIN}"
  pause_and_clear
}

generate_and_enable_config() {
  clear
  local config_dir="$SNELL_CONFIGS"
  mkdir -p "$config_dir"
  echo -e "${BLUE}请输入配置名称:${PLAIN}"
  read -p "$(echo -e "${GREEN}(如: config1): ${PLAIN}")" config_name
  [[ -z "$config_name" ]] && echo -e "${RED}配置名称不能为空!${PLAIN}" && pause_and_clear && return
  local config_file="${config_dir}/${config_name}.conf"
  if [[ -f "$config_file" ]]; then
    echo -e "${RED}配置文件 $config_name 已存在!${PLAIN}"
    pause_and_clear
    return
  fi
  read -p "$(echo -e "${BLUE}请输入监听端口 ${YELLOW}(默认5000)${BLUE}: ${PLAIN}")" port
  port=${port:-5000}
  read -p "$(echo -e "${BLUE}请输入PSK密钥 ${YELLOW}(回车随机生成)${BLUE}: ${PLAIN}")" psk
  [[ -z "$psk" ]] && psk=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)
  obfs="off"
  obfs_host=""
  read -p "$(echo -e "${BLUE}是否开启 obfs ${YELLOW}(默认不开启 Y/N)${BLUE}: ${PLAIN}")" enable_obfs
  if [[ "$enable_obfs" =~ ^[yY]$ ]]; then
    obfs="http"
    read -p "$(echo -e "${BLUE}请输入 obfs 域名 ${YELLOW}(默认 icloud.com)${BLUE}: ${PLAIN}")" obfs_host
    obfs_host=${obfs_host:-icloud.com}
  fi

  read -p "$(echo -e "${BLUE}是否开启 TFO ${YELLOW}(默认开启 Y/N)${BLUE}: ${PLAIN}")" enable_tfo
  if [[ "$enable_tfo" =~ ^[nN]$ ]]; then
    tfo="false"
  else
    tfo="true"
  fi

  read -p "$(echo -e "${BLUE}是否自定义DNS ${YELLOW}(默认8.8.8.8,1.1.1.1 Y/N)${BLUE}: ${PLAIN}")" custom_dns
  if [[ "$custom_dns" =~ ^[yY]$ ]]; then
    read -p "$(echo -e "${BLUE}请输入 DNS ${YELLOW}(用英文逗号分隔)${BLUE}: ${PLAIN}")" dns
    dns=${dns:-"8.8.8.8, 1.1.1.1"}
    dns=$(echo "$dns" | sed 's/, */, /g')
  else
    dns="8.8.8.8, 1.1.1.1"
  fi

  cat > "$config_file" << EOF
[snell-server]
listen = ::0:${port}
psk = ${psk}
obfs = ${obfs}
$(if [[ "$obfs" == "http" ]]; then echo "obfs-host = ${obfs_host}"; fi)
ipv6 = true
tfo = ${tfo}
dns = ${dns}
EOF

  echo -e "${GREEN}配置文件已生成: $config_file${PLAIN}"

  local config_bin="$SNELL_BIN"
  local service_name="snell@${config_name}.service"
  cat > "/etc/systemd/system/$service_name" << EOF
[Unit]
Description=Snell Instance (${config_name})
After=network.target

[Service]
ExecStart=$config_bin -c $config_file
Restart=always
User=root

[Install]
WantedBy=multi-user.target
EOF
  systemctl daemon-reload
  systemctl enable --now $service_name
  echo -e "${GREEN}配置 $config_name 已启动并设置为开机自启${PLAIN}"
  pause_and_clear
}

delete_config() {
  clear
  local config_dir="$SNELL_CONFIGS"
  if [[ ! -d "$config_dir" || -z "$(ls -A "$config_dir" 2>/dev/null)" ]]; then
    echo -e "${YELLOW}当前没有任何配置文件${PLAIN}"
    pause_and_clear
    return
  fi
  echo -e "${BLUE}当前可用配置:${PLAIN}"
  list_configs
  echo -e "${BLUE}请输入要删除的配置名称,输入99删除全部配置:${PLAIN}"
  read -p "$(echo -e "${GREEN}配置名称: ${PLAIN}")" config_name
  if [[ "$config_name" == "99" ]]; then
    delete_all_configs
    return
  fi
  [[ -z "$config_name" ]] && echo -e "${RED}配置名称不能为空${PLAIN}" && pause_and_clear && return
  local config_file="${config_dir}/${config_name}.conf"
  local service_name="snell@${config_name}.service"
  if [[ ! -f "$config_file" ]]; then
    echo -e "${RED}配置文件 $config_name 不存在!${PLAIN}"
    pause_and_clear
    return
  fi
  systemctl disable --now "$service_name" &>/dev/null
  rm -f "/etc/systemd/system/$service_name"
  rm -f "$config_file"
  echo -e "${GREEN}配置 $config_name 及其服务已删除。${PLAIN}"
  pause_and_clear
}
delete_all_configs() {
  clear
  local config_dir="$SNELL_CONFIGS"
  if [[ ! -d "$config_dir" || -z "$(ls -A "$config_dir" 2>/dev/null)" ]]; then
    echo -e "${YELLOW}当前没有任何配置文件${PLAIN}"
    pause_and_clear
    return
  fi
  local service_prefix="snell@"
  echo -e "${RED}警告:即将删除所有配置及服务!${PLAIN}"
  read -p "$(echo -e "${YELLOW}确定继续?[y/N]: ${PLAIN}")" choice
  [[ ! "$choice" =~ ^[yY]$ ]] && pause_and_clear && return
  for config_file in "$config_dir"/*.conf; do
    [[ ! -f "$config_file" ]] && continue
    local config_name=$(basename "$config_file" .conf)
    local service_name="${service_prefix}${config_name}.service"
    systemctl disable --now "$service_name" &>/dev/null
    rm -f "/etc/systemd/system/$service_name"
  done
  rm -rf "$config_dir"
  echo -e "${GREEN}所有配置及服务已删除${PLAIN}"
  pause_and_clear
}

modify_config() {
  clear
  local config_dir="$SNELL_CONFIGS"
  if [[ ! -d "$config_dir" || -z "$(ls -A "$config_dir" 2>/dev/null)" ]]; then
    echo -e "${YELLOW}当前没有任何配置文件,请先生成配置${PLAIN}"
    pause_and_clear
    return
  fi
  echo -e "${BLUE}当前可用配置:${PLAIN}"
  list_configs
  echo -e "${BLUE}请选择要修改的配置名称:${PLAIN}"
  read -p "$(echo -e "${GREEN}配置名称: ${PLAIN}")" config_name
  [[ -z "$config_name" ]] && echo -e "${RED}配置名称不能为空!${PLAIN}" && pause_and_clear && return
  local config_file="${config_dir}/${config_name}.conf"
  local service_name="snell@${config_name}.service"
  if [[ ! -f "$config_file" ]]; then
    echo -e "${RED}配置文件 $config_name 不存在!${PLAIN}"
    pause_and_clear
    return
  fi

  local current_port=$(grep "^listen[[:space:]]*=" "$config_file" | awk -F: '{print $NF}' | tr -d ' ')
  local current_psk=$(grep "^psk[[:space:]]*=" "$config_file" | awk -F'=' '{print $2}' | tr -d ' ')
  local current_obfs=$(grep "^obfs[[:space:]]*=" "$config_file" | awk -F'=' '{print $2}' | tr -d ' ')
  local current_obfs_host=$(grep "^obfs-host[[:space:]]*=" "$config_file" | awk -F'=' '{print $2}' | tr -d ' ')
  local current_tfo=$(grep "^tfo[[:space:]]*=" "$config_file" | awk -F'=' '{print $2}' | tr -d ' ')
  local current_dns=$(grep "^dns[[:space:]]*=" "$config_file" | awk -F'=' '{print $2}' | sed 's/^ *//;s/ *$//')

  clear
  echo -e "${BLUE}当前配置内容:${PLAIN}"
  echo -e "端口: ${GREEN}${current_port}${PLAIN}"
  echo -e "PSK: ${GREEN}${current_psk}${PLAIN}"
  echo -e "OBFS: ${GREEN}${current_obfs}${PLAIN}"
  [[ "$current_obfs" == "http" ]] && echo -e "OBFS域名: ${GREEN}${current_obfs_host}${PLAIN}"
  echo -e "TFO: ${GREEN}${current_tfo:-true}${PLAIN}"
  echo -e "DNS: ${GREEN}${current_dns:-8.8.8.8, 1.1.1.1}${PLAIN}"

  local status
  status=$(systemctl is-active "$service_name" 2>/dev/null)
  if [[ "$status" == "active" ]]; then
    echo -e "服务状态: ${GREEN}已启动(active)${PLAIN}"
  elif [[ "$status" == "inactive" ]]; then
    echo -e "服务状态: ${YELLOW}已停止(inactive)${PLAIN}"
  elif [[ "$status" == "failed" ]]; then
    echo -e "服务状态: ${RED}启动失败(failed)${PLAIN}"
  else
    echo -e "服务状态: ${BLUE}未知或未安装${PLAIN}"
  fi

  read -p "$(echo -e "${YELLOW}是否修改此配置? (Y/N): ${PLAIN}")" confirm_modify
  if [[ "$confirm_modify" =~ ^[nN]$ ]]; then
    return
  fi

  echo -e "${YELLOW}开始修改配置(回车不变)...${PLAIN}"
  read -p "$(echo -e "${BLUE}请输入新端口 ${YELLOW}(当前${current_port})${BLUE}: ${PLAIN}")" port
  port=${port:-$current_port}
  read -p "$(echo -e "${BLUE}请输入新PSK密钥 ${YELLOW}(当前${current_psk} R随机生成)${BLUE}: ${PLAIN}")" psk
  if [[ "$psk" == "r" ]]; then
    psk=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)
  elif [[ -z "$psk" ]]; then
    psk=$current_psk
  fi
  read -p "$(echo -e "${BLUE}是否开启 obfs ${YELLOW}(当前${current_obfs} Y/N)${BLUE}: ${PLAIN}")" enable_obfs
  if [[ "$enable_obfs" =~ ^[yY]$ ]]; then
    obfs="http"
    read -p "$(echo -e "${BLUE}请输入 obfs 域名 ${YELLOW}(当前${current_obfs_host:-icloud.com})${BLUE}: ${PLAIN}")" obfs_host
    obfs_host=${obfs_host:-$current_obfs_host}
    obfs_host=${obfs_host:-icloud.com}
  else
    obfs="off"
    obfs_host=""
  fi

  read -p "$(echo -e "${BLUE}是否开启 TFO ${YELLOW}(当前${current_tfo:-true} Y/N)${BLUE}: ${PLAIN}")" enable_tfo
  if [[ "$enable_tfo" =~ ^[nN]$ ]]; then
    tfo="false"
  elif [[ -z "$enable_tfo" ]]; then
    tfo=${current_tfo:-true}
  else
    tfo="true"
  fi

  read -p "$(echo -e "${BLUE}是否自定义DNS ${YELLOW}(当前${current_dns:-8.8.8.8, 1.1.1.1}, Y/N)${BLUE}: ${PLAIN}")" custom_dns
  if [[ "$custom_dns" =~ ^[yY]$ ]]; then
    read -p "$(echo -e "${BLUE}请输入 DNS ${YELLOW}(用英文逗号分隔)${BLUE}: ${PLAIN}")" dns
    dns=${dns:-"8.8.8.8, 1.1.1.1"}
    dns=$(echo "$dns" | sed 's/, */, /g')
  elif [[ -z "$custom_dns" ]]; then
    dns=${current_dns:-"8.8.8.8, 1.1.1.1"}
    dns=$(echo "$dns" | sed 's/, */, /g')
  else
    dns=${current_dns:-"8.8.8.8, 1.1.1.1"}
    dns=$(echo "$dns" | sed 's/, */, /g')
  fi

  cat > "$config_file" << EOF
[snell-server]
listen = ::0:${port}
psk = ${psk}
obfs = ${obfs}
$(if [[ "$obfs" == "http" ]]; then echo "obfs-host = ${obfs_host}"; fi)
ipv6 = true
tfo = ${tfo}
dns = ${dns}
EOF

  echo -e "${YELLOW}配置已更新,正在重启服务...${PLAIN}"
  systemctl restart "$service_name"
  echo -e "${GREEN}服务已重启,新配置已生效${PLAIN}"
  echo -e "${BLUE}------ 当前服务状态 ------${PLAIN}"
  systemctl status "$service_name" --no-pager
  pause_and_clear
}

stop_or_restart_snell() {
  clear
  local config_dir="$SNELL_CONFIGS"
  if [[ ! -d "$config_dir" || -z "$(ls -A "$config_dir" 2>/dev/null)" ]]; then
    echo -e "${YELLOW}当前没有任何配置文件${PLAIN}"
    pause_and_clear
    return
  fi
  echo -e "${BLUE}当前可用配置:${PLAIN}"
  list_configs
  echo -e "${BLUE}请输入要停止的配置名称,输入0重启全部配置:${PLAIN}"
  read -p "$(echo -e "${GREEN}配置名称: ${PLAIN}")" config_name
  if [[ "$config_name" == "0" ]]; then
    for config_file in "$config_dir"/*.conf; do
      [[ ! -f "$config_file" ]] && continue
      local cn=$(basename "$config_file" .conf)
      local service_name="snell@${cn}.service"
      systemctl restart "$service_name"
      echo -e "${GREEN}已重启服务: $service_name${PLAIN}"
    done
    echo -e "${GREEN}所有 Snell 服务已重启${PLAIN}"
    pause_and_clear
    return
  fi
  [[ -z "$config_name" ]] && echo -e "${RED}配置名称不能为空${PLAIN}" && pause_and_clear && return
  local config_file="${config_dir}/${config_name}.conf"
  local service_name="snell@${config_name}.service"
  if [[ ! -f "$config_file" ]]; then
    echo -e "${RED}配置文件 $config_name 不存在!${PLAIN}"
    pause_and_clear
    return
  fi
  systemctl stop "$service_name"
  echo -e "${YELLOW}已停止服务: $service_name${PLAIN}"
  pause_and_clear
}

list_configs() {
  local config_dir="$SNELL_CONFIGS"
  if [[ ! -d "$config_dir" || -z "$(ls -A "$config_dir")" ]]; then
    echo -e "${YELLOW}没有找到任何配置文件${PLAIN}"
    return
  fi
  for f in "$config_dir"/*.conf; do
    [[ ! -f "$f" ]] && continue
    local name=$(basename "$f" .conf)
    echo -e "  ${YELLOW}${name}${PLAIN}"
  done
}

config_snell_menu() {
  while true; do
    show_sub_menu
    read -p "$(echo -e "${BLUE}✦ Steins Gate ✦ : ${PLAIN}")" sub_choice
    case $sub_choice in
      1) generate_and_enable_config ;;
      2) stop_or_restart_snell ;;
      3) modify_config ;;
      4) delete_config ;;
      0) break ;;
      *) echo -e "${RED}无效选项,请重新选择${PLAIN}"; pause_and_clear ;;
    esac
  done
}

show_sub_menu() {
  clear
  echo -e "${BLUE}✦ Confing_Menu ✦${PLAIN}"
  echo -e "${GREEN}  1.${PLAIN}生成配置"
  echo -e "${GREEN}  2.${PLAIN}停止服务"
  echo -e "${GREEN}  3.${PLAIN}查看配置"
  echo -e "${GREEN}  4.${PLAIN}删除配置"
  echo -e "${GREEN}  0.${PLAIN}返回主页"
}

show_main_menu() {
  clear
  echo -e "${BLUE}✦ Snell_Ver.1.1 ✦${PLAIN}"
  echo -e "${GREEN}  1.${PLAIN}安装Snell"
  echo -e "${GREEN}  2.${PLAIN}配置Snell"
  echo -e "${GREEN}  3.${PLAIN}删除Snell"
  echo -e "${GREEN}  4.${PLAIN}更新Snell"
  echo -e "${GREEN}  0.${PLAIN}离开Snell"
}

main() {
  install_unzip_if_missing
  auto_enable_tcp_fastopen
  while true; do
    show_main_menu
    read -p "$(echo -e "${BLUE}✦ Steins Gate ✦ : ${PLAIN}")" main_choice
    case $main_choice in
      1) install_snell ;;
      2) config_snell_menu ;;
      3) delete_all_snell ;;
      4) update_snell_menu ;;
      0) exit 0 ;;
      *) echo -e "${RED}无效选项,请重新选择${PLAIN}"; pause_and_clear ;;
    esac
  done
}

main
4 个赞

感谢分享

好高端

这是大佬

支持

学习一下

不行 我的让AI给我理解下 请给我点个赞

感谢分享

努力学习中

学习学习

又学习到了,感谢

好帖子,马上收藏了,感谢楼主的分享!

学习

谢谢分享

又学习到了,感谢

这是干嘛的呢,没用过

观望

surge私有协议

学习学习

感谢分享