Add proxy protocol installer mirror
This commit is contained in:
27
README.md
Normal file
27
README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# proxy-installer
|
||||
|
||||
顶尖自己的协议一键脚本镜像入口,统一选择:
|
||||
|
||||
- ss2022 + shadowtls
|
||||
- anytls
|
||||
- snell v5
|
||||
- Reality (Xray)
|
||||
|
||||
## 推荐用法
|
||||
|
||||
```bash
|
||||
curl -fsSL https://mjjtop.com/proxy -o proxy.sh && chmod +x proxy.sh && ./proxy.sh
|
||||
```
|
||||
|
||||
## 直接指定协议
|
||||
|
||||
```bash
|
||||
curl -fsSL https://mjjtop.com/proxy | bash -s -- ss
|
||||
curl -fsSL https://mjjtop.com/proxy | bash -s -- anytls
|
||||
curl -fsSL https://mjjtop.com/proxy | bash -s -- snell
|
||||
curl -fsSL https://mjjtop.com/proxy | bash -s -- reality
|
||||
```
|
||||
|
||||
## 说明
|
||||
|
||||
这里镜像的是安装脚本本身,不再依赖 `*.shuijiao.de`。脚本内部仍会从官方 GitHub / Surge CDN 拉取对应二进制;如果要完全离线/完全不依赖外部下载源,需要下一步再镜像二进制 release。
|
||||
69
proxy.sh
Executable file
69
proxy.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
# 顶尖协议一键脚本统一入口
|
||||
# Mirror: https://mjjtop.com/proxy
|
||||
# Protocols: ss2022+shadowtls / anytls / snell v5 / reality
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${MIRROR_BASE_URL:-https://mjjtop.com/raw/proxy-installer}"
|
||||
TMP_DIR="/tmp/mjjtop-proxy-installer"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
info(){ echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn(){ echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
err(){ echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
|
||||
|
||||
if [[ "${PROXY_INSTALLER_SKIP_ROOT_CHECK:-0}" != "1" ]]; then
|
||||
[[ ${EUID:-$(id -u)} -eq 0 ]] || err "请用 root 运行"
|
||||
fi
|
||||
command -v curl >/dev/null 2>&1 || err "缺少 curl,请先安装: apt install -y curl"
|
||||
mkdir -p "$TMP_DIR"
|
||||
|
||||
run_remote() {
|
||||
local name="$1" path="$2" file="$TMP_DIR/$path"
|
||||
info "下载 $name 脚本:$BASE_URL/scripts/$path"
|
||||
curl -fsSL "$BASE_URL/scripts/$path" -o "$file"
|
||||
chmod +x "$file"
|
||||
info "开始执行 $name"
|
||||
exec bash "$file"
|
||||
}
|
||||
|
||||
show_menu() {
|
||||
clear 2>/dev/null || true
|
||||
echo -e "${CYAN}========================================${NC}"
|
||||
echo -e "${CYAN} 顶尖协议一键脚本 / mjjtop proxy${NC}"
|
||||
echo -e "${CYAN}========================================${NC}"
|
||||
echo "1) ss2022 + shadowtls"
|
||||
echo "2) anytls"
|
||||
echo "3) snell v5"
|
||||
echo "4) Reality (Xray)"
|
||||
echo "0) 退出"
|
||||
echo
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
ss|ss2022|shadowtls) run_remote "ss2022 + shadowtls" "ss2022-shadowtls.sh" ;;
|
||||
anytls|any) run_remote "anytls" "anytls.sh" ;;
|
||||
snell|snell5) run_remote "snell v5" "snell-v5.sh" ;;
|
||||
reality|xray) run_remote "Reality (Xray)" "reality.sh" ;;
|
||||
"") ;;
|
||||
*) err "未知参数:$1,可用: ss | anytls | snell | reality" ;;
|
||||
esac
|
||||
|
||||
while true; do
|
||||
show_menu
|
||||
read -rp "请选择协议 [0-4]: " choice
|
||||
case "$choice" in
|
||||
1) run_remote "ss2022 + shadowtls" "ss2022-shadowtls.sh" ;;
|
||||
2) run_remote "anytls" "anytls.sh" ;;
|
||||
3) run_remote "snell v5" "snell-v5.sh" ;;
|
||||
4) run_remote "Reality (Xray)" "reality.sh" ;;
|
||||
0|q|Q) exit 0 ;;
|
||||
*) warn "无效选择"; sleep 1 ;;
|
||||
esac
|
||||
done
|
||||
343
scripts/anytls.sh
Executable file
343
scripts/anytls.sh
Executable file
@@ -0,0 +1,343 @@
|
||||
#!/bin/bash
|
||||
|
||||
# =================================================================
|
||||
# anytls 管理脚本 (修复 Mihomo 缩进版)
|
||||
# 描述: 自动获取 GitHub 最新版本安装,同时显示 Surge 和 Mihomo 配置。
|
||||
# =================================================================
|
||||
|
||||
# 定义输出颜色
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # 无颜色
|
||||
|
||||
# --- 函数: 检查 anytls 安装和运行状态 ---
|
||||
check_anytls_status() {
|
||||
if [ -f /usr/local/bin/anytls-server ] && [ -f /etc/systemd/system/anytls.service ]; then
|
||||
echo -e "${GREEN}anytls 状态: 已安装${NC}"
|
||||
else
|
||||
echo -e "${RED}anytls 状态: 未安装${NC}"
|
||||
fi
|
||||
|
||||
if systemctl is-active --quiet anytls; then
|
||||
echo -e "${GREEN}服务状态: 运行中${NC}"
|
||||
else
|
||||
echo -e "${RED}服务状态: 未运行${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 显示菜单 ---
|
||||
show_menu() {
|
||||
clear
|
||||
echo "=================================================="
|
||||
echo " anytls-go 综合管理脚本 (v1.3)"
|
||||
echo "=================================================="
|
||||
check_anytls_status
|
||||
echo "--------------------------------------------------"
|
||||
echo "1. 安装 anytls"
|
||||
echo "2. 卸载 anytls"
|
||||
echo "3. 修改 anytls 配置 (端口/密码)"
|
||||
echo "4. 查看 anytls 配置"
|
||||
echo "5. 启动 anytls 服务"
|
||||
echo "6. 停止 anytls 服务"
|
||||
echo "7. 重启 anytls 服务"
|
||||
echo "8. 查看 anytls 运行状态"
|
||||
echo "0. 退出脚本"
|
||||
echo "=================================================="
|
||||
echo -n "请输入选项 [0-8]: "
|
||||
}
|
||||
|
||||
# --- 函数: 检查 root 权限 ---
|
||||
check_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo -e "${RED}错误:此脚本需要以 root 权限运行。${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 显示配置信息 (通用模块) ---
|
||||
# 参数: $1=ip, $2=port, $3=password
|
||||
display_configuration() {
|
||||
local ip=$1
|
||||
local port=$2
|
||||
local pwd=$3
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo " anytls 配置详情"
|
||||
echo "------------------------------------------"
|
||||
echo -e "地址 (IP) : ${GREEN}${ip}${NC}"
|
||||
echo -e "端口 (Port) : ${GREEN}${port}${NC}"
|
||||
echo -e "密码 (Password) : ${GREEN}${pwd}${NC}"
|
||||
echo "------------------------------------------"
|
||||
|
||||
echo "1. Surge 配置文件:"
|
||||
echo -e "${GREEN}VPS = anytls, ${ip}, ${port}, password=\"${pwd}\", skip-cert-verify=true, udp-relay=true, reuse=false${NC}"
|
||||
|
||||
echo ""
|
||||
echo "2. Mihomo (Clash Meta) 配置文件:"
|
||||
# 注意:下面这一行前面已经加了两个空格
|
||||
echo -e "${GREEN} - {\"name\":\"VPS\",\"server\":\"${ip}\",\"port\":${port},\"password\":\"${pwd}\",\"skip-cert-verify\":true,\"reuse\":false,\"type\":\"anytls\"}${NC}"
|
||||
echo "------------------------------------------"
|
||||
}
|
||||
|
||||
# --- 函数: 安装 anytls ---
|
||||
install_anytls() {
|
||||
if [ -f /usr/local/bin/anytls-server ]; then
|
||||
echo -e "${GREEN}anytls 似乎已经安装,无需重复安装。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "--> 正在准备安装环境..."
|
||||
if ! command -v curl &> /dev/null || ! command -v unzip &> /dev/null || ! command -v shuf &> /dev/null || ! command -v grep &> /dev/null; then
|
||||
echo "--> 检测到依赖缺失,正在尝试自动安装..."
|
||||
if command -v apt-get &> /dev/null; then
|
||||
apt-get update && apt-get install -y curl unzip coreutils grep
|
||||
elif command -v yum &> /dev/null; then
|
||||
yum install -y curl unzip coreutils grep
|
||||
else
|
||||
echo -e "${RED}无法确定包管理器,请手动安装 curl, unzip, coreutils, grep 后再运行此脚本。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "--> 正在获取 anytls 最新版本信息..."
|
||||
LATEST_URL=$(curl -s https://api.github.com/repos/anytls/anytls-go/releases/latest | grep "browser_download_url" | grep "linux_amd64.zip" | head -n 1 | cut -d '"' -f 4)
|
||||
|
||||
if [ -z "$LATEST_URL" ]; then
|
||||
echo -e "${RED}获取最新版本失败,尝试使用备用版本 (v0.0.12)...${NC}"
|
||||
LATEST_URL="https://github.com/anytls/anytls-go/releases/download/v0.0.12/anytls_0.0.12_linux_amd64.zip"
|
||||
else
|
||||
echo -e " 检测到最新版本下载地址: ${GREEN}$LATEST_URL${NC}"
|
||||
fi
|
||||
|
||||
echo "--> 正在下载 anytls..."
|
||||
if ! curl -sL -o anytls.zip "$LATEST_URL"; then
|
||||
echo -e "${RED}下载 anytls 失败!请检查网络连接。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "--> 正在解压并部署..."
|
||||
if ! unzip -o anytls.zip; then
|
||||
echo -e "${RED}解压 anytls 失败!${NC}"
|
||||
rm anytls.zip
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f anytls-server ]; then
|
||||
mv anytls-server /usr/local/bin/
|
||||
else
|
||||
FIND_SERVER=$(find . -maxdepth 1 -name "anytls*server*" | head -n 1)
|
||||
if [ -n "$FIND_SERVER" ]; then
|
||||
mv "$FIND_SERVER" /usr/local/bin/anytls-server
|
||||
else
|
||||
echo -e "${RED}错误:解压后未找到 anytls-server 文件。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f anytls-client* readme.md anytls.zip anytls*.zip
|
||||
chmod +x /usr/local/bin/anytls-server
|
||||
echo " anytls 程序部署完成。"
|
||||
|
||||
read -p "请输入 anytls 的监听端口 (留空则随机生成 10000-65535): " PORT
|
||||
if [ -z "$PORT" ]; then
|
||||
PORT=$((RANDOM % 55536 + 10000))
|
||||
echo -e " 使用随机端口: ${GREEN}$PORT${NC}"
|
||||
fi
|
||||
|
||||
read -p "请输入 anytls 的密码 (留空则随机生成): " PASSWORD
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14)
|
||||
SPECIAL_CHARS='-/@'
|
||||
S1_INDEX=$(($RANDOM % 3))
|
||||
S1=${SPECIAL_CHARS:$S1_INDEX:1}
|
||||
REMAINING_CHARS=${SPECIAL_CHARS//$S1/}
|
||||
S2_INDEX=$(($RANDOM % 2))
|
||||
S2=${REMAINING_CHARS:$S2_INDEX:1}
|
||||
COMBINED_CHARS="${ALPHANUM}${S1}${S2}"
|
||||
PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n')
|
||||
echo -e " 使用随机密码: ${GREEN}$PASSWORD${NC}"
|
||||
fi
|
||||
|
||||
echo "--> 正在创建 systemd 服务..."
|
||||
cat > /etc/systemd/system/anytls.service <<EOF
|
||||
[Unit]
|
||||
Description=AnyTLS Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
ExecStart=/usr/local/bin/anytls-server -l 0.0.0.0:${PORT} -p ${PASSWORD}
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "--> 正在启动服务..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable anytls > /dev/null 2>&1
|
||||
systemctl start anytls
|
||||
|
||||
echo "--> 正在获取 IP..."
|
||||
local ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org)
|
||||
[ -z "$ip_address" ] && ip_address="<您的服务器IP>"
|
||||
|
||||
echo -e "${GREEN}🎉 anytls 安装成功!${NC}"
|
||||
display_configuration "$ip_address" "$PORT" "$PASSWORD"
|
||||
}
|
||||
|
||||
# --- 函数: 卸载 anytls ---
|
||||
uninstall_anytls() {
|
||||
if [ ! -f /usr/local/bin/anytls-server ]; then
|
||||
echo -e "${RED}anytls 未安装。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${RED}警告:将停止服务并删除所有文件。${NC}"
|
||||
read -p "确认继续? [y/N]: " confirm
|
||||
if [[ $confirm != [yY] && $confirm != [yY][eE][sS] ]]; then
|
||||
echo "操作取消。"
|
||||
return
|
||||
fi
|
||||
|
||||
systemctl stop anytls
|
||||
systemctl disable anytls > /dev/null 2>&1
|
||||
rm -f /etc/systemd/system/anytls.service
|
||||
rm -f /usr/local/bin/anytls-server
|
||||
systemctl daemon-reload
|
||||
|
||||
echo -e "${GREEN}anytls 已卸载。${NC}"
|
||||
rm -- "$0"
|
||||
echo "脚本已自毁,退出。"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- 函数: 修改配置 ---
|
||||
modify_config() {
|
||||
if [ ! -f /etc/systemd/system/anytls.service ]; then
|
||||
echo -e "${RED}anytls 未安装。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
read -p "新端口 (留空随机): " PORT
|
||||
if [ -z "$PORT" ]; then
|
||||
PORT=$((RANDOM % 55536 + 10000))
|
||||
fi
|
||||
|
||||
read -p "新密码 (留空随机): " PASSWORD
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14)
|
||||
SPECIAL_CHARS='-/@'
|
||||
S1_INDEX=$(($RANDOM % 3))
|
||||
S1=${SPECIAL_CHARS:$S1_INDEX:1}
|
||||
REMAINING_CHARS=${SPECIAL_CHARS//$S1/}
|
||||
S2_INDEX=$(($RANDOM % 2))
|
||||
S2=${REMAINING_CHARS:$S2_INDEX:1}
|
||||
COMBINED_CHARS="${ALPHANUM}${S1}${S2}"
|
||||
PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n')
|
||||
fi
|
||||
|
||||
cat > /etc/systemd/system/anytls.service <<EOF
|
||||
[Unit]
|
||||
Description=AnyTLS Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
ExecStart=/usr/local/bin/anytls-server -l 0.0.0.0:${PORT} -p ${PASSWORD}
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl restart anytls
|
||||
|
||||
local ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org)
|
||||
[ -z "$ip_address" ] && ip_address="<您的服务器IP>"
|
||||
|
||||
echo -e "${GREEN}🎉 配置已更新!${NC}"
|
||||
display_configuration "$ip_address" "$PORT" "$PASSWORD"
|
||||
}
|
||||
|
||||
# --- 函数: 查看配置 ---
|
||||
view_config() {
|
||||
if [ ! -f /etc/systemd/system/anytls.service ]; then
|
||||
echo -e "${RED}anytls 未安装。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
local exec_start_line=$(grep 'ExecStart' /etc/systemd/system/anytls.service)
|
||||
local port=$(echo "$exec_start_line" | sed -n 's/.*-l 0\.0\.0\.0:\([0-9]*\).*/\1/p')
|
||||
local password=$(echo "$exec_start_line" | sed -n 's/.*-p \(.*\)/\1/p')
|
||||
|
||||
echo "--> 正在获取 IP..."
|
||||
local ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org)
|
||||
[ -z "$ip_address" ] && ip_address="<您的服务器IP>"
|
||||
|
||||
# 调用通用显示函数
|
||||
display_configuration "$ip_address" "$port" "$password"
|
||||
}
|
||||
|
||||
# --- 服务管理函数 ---
|
||||
start_anytls() {
|
||||
if systemctl is-active --quiet anytls; then
|
||||
echo -e "${GREEN}服务已在运行。${NC}"
|
||||
else
|
||||
systemctl start anytls && echo -e "${GREEN}启动成功。${NC}" || echo -e "${RED}启动失败。${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
stop_anytls() {
|
||||
if ! systemctl is-active --quiet anytls; then
|
||||
echo -e "${GREEN}服务未运行。${NC}"
|
||||
else
|
||||
systemctl stop anytls && echo -e "${GREEN}停止成功。${NC}" || echo -e "${RED}停止失败。${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
restart_anytls() {
|
||||
if [ ! -f /etc/systemd/system/anytls.service ]; then
|
||||
echo -e "${RED}anytls 未安装。${NC}"
|
||||
return
|
||||
fi
|
||||
systemctl restart anytls && echo -e "${GREEN}重启成功。${NC}" || echo -e "${RED}重启失败。${NC}"
|
||||
}
|
||||
|
||||
check_anytls_running() {
|
||||
if [ ! -f /etc/systemd/system/anytls.service ]; then
|
||||
echo -e "${RED}anytls 未安装。${NC}"
|
||||
return
|
||||
fi
|
||||
systemctl status anytls
|
||||
}
|
||||
|
||||
# --- 主程序 ---
|
||||
check_root
|
||||
|
||||
while true; do
|
||||
show_menu
|
||||
read choice
|
||||
case $choice in
|
||||
1) install_anytls ;;
|
||||
2) uninstall_anytls ;;
|
||||
3) modify_config ;;
|
||||
4) view_config ;;
|
||||
5) start_anytls ;;
|
||||
6) stop_anytls ;;
|
||||
7) restart_anytls ;;
|
||||
8) check_anytls_running ;;
|
||||
0) echo "退出。"; exit 0 ;;
|
||||
*) echo -e "${RED}无效选项。${NC}" ;;
|
||||
esac
|
||||
echo ""
|
||||
echo "按 Enter 键返回菜单..."
|
||||
read -r
|
||||
done
|
||||
438
scripts/reality.sh
Executable file
438
scripts/reality.sh
Executable file
@@ -0,0 +1,438 @@
|
||||
#!/bin/bash
|
||||
|
||||
# =================================================================
|
||||
# Xray (xtls-rprx-vision Reality) 服务器端管理脚本
|
||||
# =================================================================
|
||||
|
||||
# 定义输出颜色
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # 无颜色
|
||||
|
||||
XRAY_CONFIG_FILE="/usr/local/etc/xray/config.json"
|
||||
XRAY_KEYS_FILE="/usr/local/etc/xray/reality.keys"
|
||||
|
||||
# --- 通用函数 ---
|
||||
check_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo -e "${RED}错误:此脚本需要以 root 权限运行。${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 确保 jq 已安装 ---
|
||||
ensure_jq() {
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "--> 检测到依赖工具 jq 未安装,正在尝试自动安装..."
|
||||
if command -v apt-get &> /dev/null; then
|
||||
apt-get update >/dev/null && apt-get install -y jq
|
||||
elif command -v yum &> /dev/null; then
|
||||
yum install -y jq
|
||||
else
|
||||
echo -e "${RED}无法自动安装 jq。请手动安装 (sudo apt install jq / sudo yum install jq) 后再试。${NC}"
|
||||
return 1
|
||||
fi
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo -e "${RED}jq 安装失败,请检查包管理器或手动安装。${NC}"
|
||||
return 1
|
||||
fi
|
||||
echo " jq 安装成功。"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- 函数: 检查 Xray 安装和运行状态 ---
|
||||
check_xray_status() {
|
||||
if [ -f /usr/local/bin/xray ]; then
|
||||
echo -e "${GREEN}Xray 核心: 已安装${NC}"
|
||||
else
|
||||
echo -e "${RED}Xray 核心: 未安装${NC}"
|
||||
fi
|
||||
|
||||
if [ -f "${XRAY_CONFIG_FILE}" ]; then
|
||||
echo -e "${GREEN}配置状态 : 已配置${NC}"
|
||||
if systemctl is-active --quiet xray; then
|
||||
echo -e "${GREEN}服务状态 : 运行中${NC}"
|
||||
else
|
||||
echo -e "${RED}服务状态 : 未运行${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}配置状态 : 未配置${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# --- 函数: 生成 Reality 配置 ---
|
||||
generate_reality_simple_config() {
|
||||
echo "--> 正在配置 Reality 配置..."
|
||||
read -p "请输入监听端口 (例如 443, 留空随机): " PORT
|
||||
[ -z "$PORT" ] && PORT=$((RANDOM % 55536 + 10000))
|
||||
|
||||
read -p "请输入伪装域名 (留空则默认为 icloud.com): " SNI_DOMAIN
|
||||
[ -z "$SNI_DOMAIN" ] && SNI_DOMAIN="icloud.com"
|
||||
|
||||
local sni_domain_cleaned=$(echo "${SNI_DOMAIN}" | cut -d':' -f1)
|
||||
|
||||
echo "--> 正在生成 UUID 和 Reality 密钥对..."
|
||||
local uuid=$(/usr/local/bin/xray uuid)
|
||||
local key_pair=$(/usr/local/bin/xray x25519)
|
||||
local private_key=$(echo "$key_pair" | grep 'PrivateKey' | awk '{print $2}')
|
||||
local public_key=$(echo "$key_pair" | grep 'Password' | awk '{print $2}')
|
||||
|
||||
echo "PrivateKey: ${private_key}" > "${XRAY_KEYS_FILE}"
|
||||
echo "PublicKey: ${public_key}" >> "${XRAY_KEYS_FILE}"
|
||||
|
||||
echo "--> 正在创建配置文件 ${XRAY_CONFIG_FILE}..."
|
||||
cat > "${XRAY_CONFIG_FILE}" <<EOF
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"port": ${PORT},
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "${uuid}",
|
||||
"flow": "xtls-rprx-vision"
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp",
|
||||
"security": "reality",
|
||||
"realitySettings": {
|
||||
"dest": "${sni_domain_cleaned}:443",
|
||||
"serverNames": [ "${sni_domain_cleaned}" ],
|
||||
"privateKey": "${private_key}",
|
||||
"shortIds": [ "", "0123456789abcdef" ]
|
||||
}
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [ "http", "tls", "quic" ],
|
||||
"routeOnly": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
# --- 函数: 生成 Reality (防偷) 配置 ---
|
||||
generate_reality_dokodemo_config() {
|
||||
echo "--> 正在配置 Reality (防偷)..."
|
||||
read -p "请输入外部监听端口 (例如 443, 留空随机): " EXT_PORT
|
||||
[ -z "$EXT_PORT" ] && EXT_PORT=$((RANDOM % 55536 + 10000))
|
||||
|
||||
read -p "请输入内部 VLESS 端口 (留空随机): " INT_PORT
|
||||
[ -z "$INT_PORT" ] && INT_PORT=$((RANDOM % 55536 + 10000))
|
||||
|
||||
read -p "请输入伪装域名 (留空则默认为 icloud.com): " SNI_DOMAIN
|
||||
[ -z "$SNI_DOMAIN" ] && SNI_DOMAIN="icloud.com"
|
||||
|
||||
local sni_domain_cleaned=$(echo "${SNI_DOMAIN}" | cut -d':' -f1)
|
||||
|
||||
echo "--> 正在生成 UUID 和 Reality 密钥对..."
|
||||
local uuid=$(/usr/local/bin/xray uuid)
|
||||
local key_pair=$(/usr/local/bin/xray x25519)
|
||||
local private_key=$(echo "$key_pair" | grep 'PrivateKey' | awk '{print $2}')
|
||||
local public_key=$(echo "$key_pair" | grep 'Password' | awk '{print $2}')
|
||||
|
||||
echo "PrivateKey: ${private_key}" > "${XRAY_KEYS_FILE}"
|
||||
echo "PublicKey: ${public_key}" >> "${XRAY_KEYS_FILE}"
|
||||
|
||||
echo "--> 正在创建配置文件 ${XRAY_CONFIG_FILE}..."
|
||||
cat > "${XRAY_CONFIG_FILE}" <<EOF
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"tag": "dokodemo-in",
|
||||
"port": ${EXT_PORT},
|
||||
"protocol": "dokodemo-door",
|
||||
"settings": {
|
||||
"address": "127.0.0.1",
|
||||
"port": ${INT_PORT},
|
||||
"network": "tcp"
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [ "tls" ],
|
||||
"routeOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "127.0.0.1",
|
||||
"port": ${INT_PORT},
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "${uuid}",
|
||||
"flow": "xtls-rprx-vision"
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp",
|
||||
"security": "reality",
|
||||
"realitySettings": {
|
||||
"dest": "${sni_domain_cleaned}:443",
|
||||
"serverNames": [ "${sni_domain_cleaned}" ],
|
||||
"privateKey": "${private_key}",
|
||||
"shortIds": [ "", "0123456789abcdef" ]
|
||||
}
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [ "http", "tls", "quic" ],
|
||||
"routeOnly": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{ "protocol": "freedom", "tag": "direct" },
|
||||
{ "protocol": "blackhole", "tag": "block" }
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": [ "dokodemo-in" ],
|
||||
"domain": [ "${sni_domain_cleaned}" ],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"inboundTag": [ "dokodemo-in" ],
|
||||
"outboundTag": "block"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- 函数: 安装 Xray 核心 ---
|
||||
install_xray_core() {
|
||||
if [ -f /usr/local/bin/xray ]; then
|
||||
echo -e "${GREEN}Xray 核心已安装,无需重复操作。${NC}"
|
||||
return 0
|
||||
fi
|
||||
echo "--> 正在使用官方脚本安装 Xray 核心..."
|
||||
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -u root
|
||||
if [ ! -f /usr/local/bin/xray ]; then
|
||||
echo -e "${RED}Xray 核心安装失败。${NC}"
|
||||
return 1
|
||||
else
|
||||
echo -e "${GREEN}Xray 核心安装成功。${NC}"
|
||||
echo "--> 正在清理旧的配置文件..."
|
||||
systemctl stop xray >/dev/null 2>&1
|
||||
rm -f "${XRAY_CONFIG_FILE}"
|
||||
rm -f "${XRAY_KEYS_FILE}"
|
||||
echo " 旧配置已清理。"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: (包装器) 配置 Reality ---
|
||||
configure_reality_simple() {
|
||||
if ! [ -f /usr/local/bin/xray ]; then
|
||||
echo "--> Xray 核心未安装,正在自动安装..."
|
||||
install_xray_core || return
|
||||
fi
|
||||
|
||||
if [ -f "${XRAY_CONFIG_FILE}" ]; then
|
||||
read -p "检测到现有配置,继续将覆盖它。确定吗?[y/N]: " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY] ]]; then echo "操作已取消。"; return; fi
|
||||
fi
|
||||
|
||||
generate_reality_simple_config
|
||||
|
||||
echo "--> 正在测试配置并启动 Xray..."
|
||||
/usr/local/bin/xray -test -config "${XRAY_CONFIG_FILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}配置文件测试失败,请检查。配置未应用。${NC}"; return; fi
|
||||
|
||||
systemctl restart xray
|
||||
systemctl enable xray > /dev/null 2>&1
|
||||
echo -e "${GREEN}🎉 Xray Reality 配置成功!${NC}"
|
||||
view_config_xray
|
||||
}
|
||||
|
||||
# --- 函数: (包装器) 配置 Reality (防偷) ---
|
||||
configure_reality_dokodemo() {
|
||||
if ! [ -f /usr/local/bin/xray ]; then
|
||||
echo "--> Xray 核心未安装,正在自动安装..."
|
||||
install_xray_core || return
|
||||
fi
|
||||
|
||||
if [ -f "${XRAY_CONFIG_FILE}" ]; then
|
||||
read -p "检测到现有配置,继续将覆盖它。确定吗?[y/N]: " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY] ]]; then echo "操作已取消。"; return; fi
|
||||
fi
|
||||
|
||||
generate_reality_dokodemo_config
|
||||
|
||||
echo "--> 正在测试配置并启动 Xray..."
|
||||
/usr/local/bin/xray -test -config "${XRAY_CONFIG_FILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}配置文件测试失败,请检查。配置未应用。${NC}"; return; fi
|
||||
|
||||
systemctl restart xray
|
||||
systemctl enable xray > /dev/null 2>&1
|
||||
echo -e "${GREEN}🎉 Xray Reality (防偷) 配置成功!${NC}"
|
||||
view_config_xray
|
||||
}
|
||||
|
||||
|
||||
# --- 函数: 卸载 Xray ---
|
||||
uninstall_xray() {
|
||||
if [ ! -f /usr/local/bin/xray ]; then
|
||||
echo -e "${RED}Xray 未安装。${NC}"; return; fi
|
||||
|
||||
read -p "警告:确定要卸载 Xray 吗?这将删除所有数据。[y/N]: " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY]([eE][sS])?$ ]]; then
|
||||
echo "卸载操作已取消。"; return; fi
|
||||
|
||||
systemctl stop xray
|
||||
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge
|
||||
rm -f "${XRAY_KEYS_FILE}"
|
||||
echo -e "${GREEN}Xray 已成功卸载。${NC}"
|
||||
}
|
||||
|
||||
# --- 函数: 查看 Xray 配置 ---
|
||||
view_config_xray() {
|
||||
if [ ! -f "${XRAY_CONFIG_FILE}" ]; then
|
||||
echo -e "${RED}Xray 未配置。请先选择一个配置方案。${NC}"; return; fi
|
||||
ensure_jq || return
|
||||
|
||||
if ! jq . "${XRAY_CONFIG_FILE}" >/dev/null 2>&1; then
|
||||
echo -e "${RED}错误:配置文件 ${XRAY_CONFIG_FILE} 格式无效。${NC}"; return; fi
|
||||
|
||||
local ip_address=$(curl -s https://ipv4.icanhazip.com || echo "<您的服务器IP>")
|
||||
local public_key="<未找到>"
|
||||
if [ -f "${XRAY_KEYS_FILE}" ]; then
|
||||
public_key=$(grep 'PublicKey' "${XRAY_KEYS_FILE}" | awk '{print $2}')
|
||||
fi
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo " Xray (Reality) 当前配置信息"
|
||||
echo "------------------------------------------"
|
||||
|
||||
# 通过 tag 判断配置类型
|
||||
if jq -e '.inbounds[] | select(.tag=="dokodemo-in")' "${XRAY_CONFIG_FILE}" >/dev/null 2>&1; then
|
||||
# 防偷配置
|
||||
local ext_port=$(jq '.inbounds[] | select(.tag=="dokodemo-in") | .port' "${XRAY_CONFIG_FILE}")
|
||||
local vless_inbound=$(jq '.inbounds[] | select(.protocol=="vless")' "${XRAY_CONFIG_FILE}")
|
||||
local uuid=$(echo "$vless_inbound" | jq -r '.settings.clients[0].id')
|
||||
local flow=$(echo "$vless_inbound" | jq -r '.settings.clients[0].flow')
|
||||
local sni=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.serverNames[0]')
|
||||
local short_id=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.shortIds[0]')
|
||||
|
||||
echo -e "配置类型 : ${GREEN}Reality (防偷)${NC}"
|
||||
echo -e "监听地址 : ${GREEN}${ip_address}${NC}"
|
||||
echo -e "外部端口 : ${GREEN}${ext_port}${NC}"
|
||||
echo -e "UUID : ${GREEN}${uuid}${NC}"
|
||||
echo -e "Flow : ${GREEN}${flow}${NC}"
|
||||
echo -e "伪装域名 : ${GREEN}${sni}${NC}"
|
||||
echo -e "Short ID : ${GREEN}${short_id}${NC}"
|
||||
echo -e "公钥 (pbk) : ${GREEN}${public_key}${NC}"
|
||||
echo "------------------------------------------"
|
||||
echo "VLESS 分享链接:"
|
||||
local vless_link="vless://${uuid}@${ip_address}:${ext_port}?encryption=none&flow=${flow}&security=reality&sni=${sni}&fp=random&pbk=${public_key}&sid=${short_id}&allowInsecure=1&type=tcp&headerType=none#VPS_防偷"
|
||||
echo -e "${GREEN}${vless_link}${NC}"
|
||||
|
||||
else
|
||||
# Reality 配置
|
||||
local vless_inbound=$(jq '.inbounds[] | select(.protocol=="vless")' "${XRAY_CONFIG_FILE}")
|
||||
local port=$(echo "$vless_inbound" | jq -r '.port')
|
||||
local uuid=$(echo "$vless_inbound" | jq -r '.settings.clients[0].id')
|
||||
local flow=$(echo "$vless_inbound" | jq -r '.settings.clients[0].flow')
|
||||
local sni=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.serverNames[0]')
|
||||
local short_id=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.shortIds[0]')
|
||||
|
||||
echo -e "配置类型 : ${GREEN}Reality 配置${NC}"
|
||||
echo -e "监听地址 : ${GREEN}${ip_address}${NC}"
|
||||
echo -e "端口 : ${GREEN}${port}${NC}"
|
||||
echo -e "UUID : ${GREEN}${uuid}${NC}"
|
||||
echo -e "Flow : ${GREEN}${flow}${NC}"
|
||||
echo -e "伪装域名 : ${GREEN}${sni}${NC}"
|
||||
echo -e "Short ID : ${GREEN}${short_id}${NC}"
|
||||
echo -e "公钥 (pbk) : ${GREEN}${public_key}${NC}"
|
||||
echo "------------------------------------------"
|
||||
echo "VLESS 分享链接:"
|
||||
local vless_link="vless://${uuid}@${ip_address}:${port}?encryption=none&flow=${flow}&security=reality&sni=${sni}&fp=random&pbk=${public_key}&sid=${short_id}&allowInsecure=1&type=tcp&headerType=none#VPS_Reality"
|
||||
echo -e "${GREEN}${vless_link}${NC}"
|
||||
fi
|
||||
echo "------------------------------------------"
|
||||
}
|
||||
|
||||
# --- 函数: Xray 服务管理 ---
|
||||
manage_xray_service() {
|
||||
if ! systemctl list-units --type=service | grep -q "xray.service"; then
|
||||
echo -e "${RED}Xray 服务未安装。${NC}"; return; fi
|
||||
case $1 in
|
||||
start) systemctl start xray && echo -e "${GREEN}服务启动成功。${NC}" || echo -e "${RED}服务启动失败。${NC}" ;;
|
||||
stop) systemctl stop xray && echo -e "${GREEN}服务已停止。${NC}" || echo -e "${RED}服务停止失败。${NC}" ;;
|
||||
restart) systemctl restart xray && echo -e "${GREEN}服务重启成功。${NC}" || echo -e "${RED}服务重启失败。${NC}" ;;
|
||||
status) systemctl status xray ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- 函数: Xray 主菜单 ---
|
||||
xray_menu() {
|
||||
while true; do
|
||||
clear
|
||||
echo "=================================================="
|
||||
echo " XTLS-RPRX-VISION Reality 管理脚本"
|
||||
echo "=================================================="
|
||||
check_xray_status
|
||||
echo "--------------------------------------------------"
|
||||
echo "1. 安装 Xray 核心"
|
||||
echo "2. 配置 Reality"
|
||||
echo "3. 配置 Reality (防偷)"
|
||||
echo "4. 卸载 Xray"
|
||||
echo "5. 查看 Xray 配置"
|
||||
echo "6. 启动 Xray"
|
||||
echo "7. 停止 Xray"
|
||||
echo "8. 重启 Xray"
|
||||
echo "9. 查看运行状态"
|
||||
echo "0. 退出脚本"
|
||||
echo "=================================================="
|
||||
read -p "请输入选项 [0-9]: " choice
|
||||
|
||||
case $choice in
|
||||
1) install_xray_core ;;
|
||||
2) configure_reality_simple ;;
|
||||
3) configure_reality_dokodemo ;;
|
||||
4) uninstall_xray ;;
|
||||
5) view_config_xray ;;
|
||||
6) manage_xray_service start ;;
|
||||
7) manage_xray_service stop ;;
|
||||
8) manage_xray_service restart ;;
|
||||
9) manage_xray_service status ;;
|
||||
0) break ;;
|
||||
*) echo -e "${RED}无效选项,请重试。${NC}" ;;
|
||||
esac
|
||||
[ "$choice" != "0" ] && [ "$choice" != "9" ] && read -p "按 Enter 键返回..."
|
||||
done
|
||||
}
|
||||
|
||||
# --- 脚本入口 ---
|
||||
check_root
|
||||
xray_menu
|
||||
echo "脚本已退出。"
|
||||
|
||||
422
scripts/snell-v5.sh
Executable file
422
scripts/snell-v5.sh
Executable file
@@ -0,0 +1,422 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==============================================================================
|
||||
# Snell v5 管理脚本
|
||||
# ==============================================================================
|
||||
|
||||
# --- 函数: 检查 Snell 安装和运行状态 ---
|
||||
check_snell_status() {
|
||||
# 检查 Snell 是否安装
|
||||
if [ -f /usr/local/bin/snell-server ] && [ -f /etc/snell/snell-server.conf ]; then
|
||||
echo -e "\033[32mSnell 状态: 已安装\033[0m"
|
||||
else
|
||||
echo -e "\033[31mSnell 状态: 未安装\033[0m"
|
||||
fi
|
||||
|
||||
# 检查 Snell 服务是否运行
|
||||
if systemctl is-active --quiet snell; then
|
||||
echo -e "\033[32m服务状态: 运行中\033[0m"
|
||||
else
|
||||
echo -e "\033[31m服务状态: 未运行\033[0m"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 显示菜单 ---
|
||||
show_menu() {
|
||||
clear
|
||||
echo "=================================================="
|
||||
echo " Snell v5 管理脚本"
|
||||
echo "=================================================="
|
||||
check_snell_status
|
||||
echo "--------------------------------------------------"
|
||||
echo "1. 安装 Snell"
|
||||
echo "2. 卸载 Snell"
|
||||
echo "3. 修改 Snell 配置"
|
||||
echo "4. 查看 Snell 配置"
|
||||
echo "5. 查看 Snell 运行状态"
|
||||
echo "6. 启动 Snell 服务"
|
||||
echo "7. 停止 Snell 服务"
|
||||
echo "8. 重启 Snell 服务"
|
||||
echo "0. 退出脚本"
|
||||
echo "=================================================="
|
||||
echo -n "请输入选项 [0-8]: "
|
||||
}
|
||||
|
||||
# --- 函数: 检查 root 权限 ---
|
||||
check_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "错误:此脚本需要以 root 权限运行。" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 安装 Snell ---
|
||||
install_snell() {
|
||||
# --- 新增:检查 Snell 是否已安装 ---
|
||||
if [ -f /usr/local/bin/snell-server ] && [ -f /etc/snell/snell-server.conf ]; then
|
||||
echo -e "\033[32mSnell 似乎已经安装,无需重复安装。\033[0m"
|
||||
return
|
||||
fi
|
||||
|
||||
# --- 步骤 1: 更新软件包列表并安装必要工具 ---
|
||||
echo "--> 更新软件包列表并安装必要工具 (wget, unzip, coreutils)..."
|
||||
if ! apt-get update > /dev/null; then
|
||||
echo "错误:软件包列表更新失败。请检查网络连接或 apt 源。"
|
||||
exit 1
|
||||
fi
|
||||
# coreutils 包含 shuf 命令
|
||||
if ! apt-get install -y wget unzip coreutils > /dev/null; then
|
||||
echo "错误:工具安装失败。请检查 apt 源或网络连接。"
|
||||
exit 1
|
||||
fi
|
||||
echo " 工具安装完成。"
|
||||
|
||||
# --- 步骤 2: 下载、解压并部署 Snell ---
|
||||
echo "--> 正在下载、解压并部署 Snell 服务器程序..."
|
||||
if ! wget -q --show-progress https://dl.nssurge.com/snell/snell-server-v5.0.1-linux-amd64.zip -O snell.zip; then
|
||||
echo "错误:Snell 下载失败!请检查网络或链接是否有效。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! unzip -o snell.zip -d /usr/local/bin/ > /dev/null; then
|
||||
echo "错误:Snell 解压失败!"
|
||||
rm snell.zip
|
||||
exit 1
|
||||
fi
|
||||
chmod +x /usr/local/bin/snell-server
|
||||
mkdir -p /etc/snell
|
||||
rm snell.zip
|
||||
echo " Snell 程序部署完成。"
|
||||
|
||||
# --- 步骤 3: 用户输入端口和密码 ---
|
||||
read -p "请输入 Snell 的监听端口 (留空则随机生成): " snell_port
|
||||
if [ -z "${snell_port}" ]; then
|
||||
while true; do
|
||||
snell_port=$(shuf -i 30001-65535 -n 1)
|
||||
if ! ss -lntu | grep -q ":${snell_port} "; then
|
||||
echo " 端口未输入,使用随机端口: ${snell_port}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
read -p "请输入 Snell 的密码 (PSK,留空则随机生成): " snell_psk
|
||||
if [ -z "${snell_psk}" ]; then
|
||||
# --- 新的密码生成逻辑 ---
|
||||
# 1. 生成14位字母和数字
|
||||
ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14)
|
||||
|
||||
# 2. 从 '-/@' 中随机选择两个不同的特殊字符
|
||||
SPECIAL_CHARS='-/@'
|
||||
S1_INDEX=$(($RANDOM % 3))
|
||||
S1=${SPECIAL_CHARS:$S1_INDEX:1}
|
||||
REMAINING_CHARS=${SPECIAL_CHARS//$S1/} # 移除已选的字符
|
||||
S2_INDEX=$(($RANDOM % 2))
|
||||
S2=${REMAINING_CHARS:$S2_INDEX:1}
|
||||
|
||||
# 3. 组合所有字符并打乱顺序
|
||||
COMBINED_CHARS="${ALPHANUM}${S1}${S2}"
|
||||
snell_psk=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n')
|
||||
|
||||
echo " 密码未输入,使用随机密码: ${snell_psk}"
|
||||
fi
|
||||
|
||||
# --- 步骤 4: 配置确认 ---
|
||||
echo ""
|
||||
echo "============================================="
|
||||
echo "端口 (Port): ${snell_port}"
|
||||
echo "密码 (PSK): ${snell_psk}"
|
||||
echo "============================================="
|
||||
echo "安装将在 2 秒后继续,按 Ctrl+C 取消"
|
||||
sleep 2
|
||||
|
||||
# --- 步骤 5: 生成配置文件 ---
|
||||
echo "--> 正在创建配置文件..."
|
||||
cat > /etc/snell/snell-server.conf <<EOF
|
||||
[snell-server]
|
||||
listen = 0.0.0.0:${snell_port}
|
||||
psk = ${snell_psk}
|
||||
EOF
|
||||
|
||||
# --- 步骤 6: 创建 systemd 服务并启动 ---
|
||||
echo "--> 正在创建 systemd 服务并启动..."
|
||||
cat > /etc/systemd/system/snell.service <<EOF
|
||||
[Unit]
|
||||
Description=Snell Proxy Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=nogroup
|
||||
LimitNOFILE=32768
|
||||
ExecStart=/usr/local/bin/snell-server -c /etc/snell/snell-server.conf
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
SyslogIdentifier=snell-server
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable snell > /dev/null 2>&1
|
||||
systemctl start snell
|
||||
|
||||
# --- 步骤 7: 显示结果 ---
|
||||
echo "--> 正在获取服务器公网 IP 地址..."
|
||||
ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org)
|
||||
if [ -z "$ip_address" ]; then
|
||||
echo "警告:无法获取公网 IP 地址,请手动检查。"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=================================================="
|
||||
echo "🎉 Snell 服务器安装并配置成功!"
|
||||
echo ""
|
||||
echo "--------------- 服务状态 ---------------"
|
||||
systemctl status snell
|
||||
echo ""
|
||||
echo "---------- 客户端配置信息 ----------"
|
||||
echo "在Surge使用以下配置:"
|
||||
echo ""
|
||||
echo "vps = snell, ${ip_address:-<您的服务器IP>}, ${snell_port}, psk=${snell_psk}, version=5"
|
||||
echo ""
|
||||
echo "=================================================="
|
||||
}
|
||||
|
||||
# --- 函数: 卸载 Snell ---
|
||||
uninstall_snell() {
|
||||
echo "警告:此操作将彻底卸载 Snell 并删除所有相关文件!"
|
||||
read -p "确定要继续吗?(y/n): " confirm
|
||||
if [ "$confirm" != "y" ]; then
|
||||
echo "卸载操作已取消。"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "--> 正在停止并禁用 Snell 服务..."
|
||||
systemctl stop snell > /dev/null 2>&1
|
||||
systemctl disable snell > /dev/null 2>&1
|
||||
|
||||
echo "--> 正在删除 Snell systemd 服务文件..."
|
||||
rm -f /etc/systemd/system/snell.service
|
||||
systemctl daemon-reload
|
||||
|
||||
echo "--> 正在删除 Snell 可执行文件..."
|
||||
rm -f /usr/local/bin/snell-server
|
||||
|
||||
echo "--> 正在删除 Snell 配置文件..."
|
||||
rm -rf /etc/snell
|
||||
|
||||
echo "--> 正在删除此脚本..."
|
||||
rm -- "$0"
|
||||
|
||||
echo ""
|
||||
echo "✅ Snell 已被彻底卸载。"
|
||||
echo "脚本自身也已被删除。退出。"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
# --- 函数: 修改 Snell 配置 ---
|
||||
modify_config() {
|
||||
if [ -f /etc/snell/snell-server.conf ]; then
|
||||
# --- 步骤 1: 用户输入新端口和密码 ---
|
||||
read -p "请输入新的 Snell 监听端口 (留空则随机生成): " snell_port
|
||||
if [ -z "${snell_port}" ]; then
|
||||
while true; do
|
||||
snell_port=$(shuf -i 30001-65535 -n 1)
|
||||
if ! ss -lntu | grep -q ":${snell_port} "; then
|
||||
echo " 端口未输入,使用随机端口: ${snell_port}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
read -p "请输入新的 Snell 密码 (PSK,留空则随机生成): " snell_psk
|
||||
if [ -z "${snell_psk}" ]; then
|
||||
# --- 新的密码生成逻辑 ---
|
||||
# 1. 生成14位字母和数字
|
||||
ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14)
|
||||
|
||||
# 2. 从 '-/@' 中随机选择两个不同的特殊字符
|
||||
SPECIAL_CHARS='-/@'
|
||||
S1_INDEX=$(($RANDOM % 3))
|
||||
S1=${SPECIAL_CHARS:$S1_INDEX:1}
|
||||
REMAINING_CHARS=${SPECIAL_CHARS//$S1/} # 移除已选的字符
|
||||
S2_INDEX=$(($RANDOM % 2))
|
||||
S2=${REMAINING_CHARS:$S2_INDEX:1}
|
||||
|
||||
# 3. 组合所有字符并打乱顺序
|
||||
COMBINED_CHARS="${ALPHANUM}${S1}${S2}"
|
||||
snell_psk=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n')
|
||||
|
||||
echo " 密码未输入,使用随机密码: ${snell_psk}"
|
||||
fi
|
||||
|
||||
# --- 步骤 2: 配置确认 ---
|
||||
echo ""
|
||||
echo "============================================="
|
||||
echo "新端口 (Port): ${snell_port}"
|
||||
echo "新密码 (PSK): ${snell_psk}"
|
||||
echo "============================================="
|
||||
echo "配置将在 2 秒后更新,按 Ctrl+C 取消"
|
||||
sleep 2
|
||||
|
||||
# --- 步骤 3: 更新配置文件 ---
|
||||
echo "--> 正在更新配置文件..."
|
||||
cat > /etc/snell/snell-server.conf <<EOF
|
||||
[snell-server]
|
||||
listen = ::0:${snell_port}
|
||||
psk = ${snell_psk}
|
||||
EOF
|
||||
|
||||
# --- 步骤 4: 显示客户端配置信息 ---
|
||||
echo "--> 正在获取服务器公网 IP 地址..."
|
||||
ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org)
|
||||
if [ -z "$ip_address" ]; then
|
||||
echo "警告:无法获取公网 IP 地址,请手动检查。"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=================================================="
|
||||
echo "🎉 Snell 配置已更新!"
|
||||
echo ""
|
||||
echo "---------- 客户端配置信息 ----------"
|
||||
echo "在Surge使用以下配置:"
|
||||
echo ""
|
||||
echo "vps = snell, ${ip_address:-<您的服务器IP>}, ${snell_port}, psk=${snell_psk}, version=5"
|
||||
echo ""
|
||||
echo "=================================================="
|
||||
|
||||
# --- 步骤 5: 自动重启服务 ---
|
||||
restart_snell
|
||||
else
|
||||
echo "错误:Snell 配置文件不存在,可能尚未安装。"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 查看 Snell 配置 ---
|
||||
view_config() {
|
||||
if [ -f /etc/snell/snell-server.conf ]; then
|
||||
echo "--> Snell 配置文件内容:"
|
||||
cat /etc/snell/snell-server.conf
|
||||
echo ""
|
||||
ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org)
|
||||
# --- 使用 awk 和 cut 准确提取配置 ---
|
||||
port=$(grep "listen" /etc/snell/snell-server.conf | awk -F':' '{print $NF}')
|
||||
psk=$(grep "psk" /etc/snell/snell-server.conf | cut -d'=' -f2 | tr -d ' ')
|
||||
echo "--> 客户端配置信息:"
|
||||
echo "vps = snell, ${ip_address:-<您的服务器IP>}, ${port}, psk=${psk}, version=5"
|
||||
else
|
||||
echo "错误:Snell 配置文件不存在,可能尚未安装。"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 查看 Snell 运行状态 ---
|
||||
check_snell_running() {
|
||||
echo "--> Snell 服务运行状态:"
|
||||
systemctl status snell
|
||||
}
|
||||
|
||||
# --- 函数: 启动 Snell 服务 ---
|
||||
start_snell() {
|
||||
if [ -f /etc/systemd/system/snell.service ]; then
|
||||
echo "--> 正在启动 Snell 服务..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable snell > /dev/null 2>&1
|
||||
if systemctl start snell; then
|
||||
echo " Snell 服务已启动并启用。"
|
||||
echo ""
|
||||
echo "--> Snell 服务运行状态:"
|
||||
systemctl status snell
|
||||
else
|
||||
echo " 错误:Snell 服务启动失败,请使用 'journalctl -u snell' 查看日志。"
|
||||
echo ""
|
||||
echo "--> Snell 服务运行状态:"
|
||||
systemctl status snell
|
||||
fi
|
||||
else
|
||||
echo "错误:Snell 服务未安装。"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 停止 Snell 服务 ---
|
||||
stop_snell() {
|
||||
if systemctl is-active --quiet snell || systemctl is-enabled --quiet snell; then
|
||||
echo "--> 正在停止 Snell 服务..."
|
||||
systemctl stop snell
|
||||
systemctl disable snell > /dev/null 2>&1
|
||||
echo " Snell 服务已停止并禁用。"
|
||||
echo ""
|
||||
echo "--> Snell 服务运行状态:"
|
||||
systemctl status snell
|
||||
else
|
||||
echo "错误:Snell 服务未安装或未运行。"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 重启 Snell 服务 ---
|
||||
restart_snell() {
|
||||
if [ -f /etc/systemd/system/snell.service ]; then
|
||||
echo "--> 正在重启 Snell 服务..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable snell > /dev/null 2>&1
|
||||
if systemctl restart snell; then
|
||||
echo " Snell 服务已重启并启用。"
|
||||
echo ""
|
||||
echo "--> Snell 服务运行状态:"
|
||||
systemctl status snell
|
||||
else
|
||||
echo " 错误:Snell 服务重启失败,请使用 'journalctl -u snell' 查看日志。"
|
||||
echo ""
|
||||
echo "--> Snell 服务运行状态:"
|
||||
systemctl status snell
|
||||
fi
|
||||
else
|
||||
echo "错误:Snell 服务未安装。"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 主程序: 检查 root 权限并显示菜单 ---
|
||||
check_root
|
||||
|
||||
while true; do
|
||||
show_menu
|
||||
read choice
|
||||
case $choice in
|
||||
1)
|
||||
install_snell
|
||||
;;
|
||||
2)
|
||||
uninstall_snell
|
||||
;;
|
||||
3)
|
||||
modify_config
|
||||
;;
|
||||
4)
|
||||
view_config
|
||||
;;
|
||||
5)
|
||||
check_snell_running
|
||||
;;
|
||||
6)
|
||||
start_snell
|
||||
;;
|
||||
7)
|
||||
stop_snell
|
||||
;;
|
||||
8)
|
||||
restart_snell
|
||||
;;
|
||||
0)
|
||||
echo "退出脚本。"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "无效选项,请输入 0-8。"
|
||||
;;
|
||||
esac
|
||||
echo ""
|
||||
echo "按 Enter 键返回菜单..."
|
||||
read -r
|
||||
done
|
||||
518
scripts/ss2022-shadowtls.sh
Executable file
518
scripts/ss2022-shadowtls.sh
Executable file
@@ -0,0 +1,518 @@
|
||||
#!/bin/bash
|
||||
|
||||
# =================================================================
|
||||
# shadowsocks-rust & shadowtls 服务器端综合管理脚本
|
||||
# 描述: 提供一个主菜单,分别进入 ss-rust 和 shadowtls 的管理界面。
|
||||
# =================================================================
|
||||
|
||||
# 定义输出颜色
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # 无颜色
|
||||
|
||||
# --- 通用函数 ---
|
||||
check_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo -e "${RED}错误:此脚本需要以 root 权限运行。${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 新增函数: 检查是否所有组件都已卸载,如果是则删除脚本 ---
|
||||
check_and_delete_script_if_all_uninstalled() {
|
||||
# 检查 ss-rust 和 shadowtls 的二进制文件是否都不存在
|
||||
if [ ! -f /usr/local/bin/ss-rust ] && [ ! -f /usr/local/bin/shadowtls ]; then
|
||||
echo -e "${GREEN}检测到 ss-rust 和 shadowtls 均已卸载。${NC}"
|
||||
echo "--> 正在删除此脚本..."
|
||||
rm -- "$0"
|
||||
echo "脚本自身也已被删除。即将退出。"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# =================================================================
|
||||
# S-S-R-U-S-T M-A-N-A-G-E-M-E-N-T
|
||||
# =================================================================
|
||||
|
||||
# --- ss-rust 变量定义 (这里改为了动态获取,不再硬编码版本号) ---
|
||||
# SS_VERSION, SS_URL, SS_TAR_FILE 将在安装函数中动态生成
|
||||
|
||||
# --- 函数: 检查 ss-rust 安装和运行状态 ---
|
||||
check_ss_rust_status() {
|
||||
if [ -f /usr/local/bin/ss-rust ] && [ -f /etc/systemd/system/ss-rust.service ]; then
|
||||
echo -e "${GREEN}ss-rust 状态: 已安装${NC}"
|
||||
else
|
||||
echo -e "${RED}ss-rust 状态: 未安装${NC}"
|
||||
fi
|
||||
|
||||
if systemctl is-active --quiet ss-rust; then
|
||||
echo -e "${GREEN}服务状态 : 运行中${NC}"
|
||||
else
|
||||
echo -e "${RED}服务状态 : 未运行${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 确保 jq 已安装 ---
|
||||
ensure_jq() {
|
||||
if ! command -v jq &> /dev/null || ! command -v curl &> /dev/null; then
|
||||
echo "--> 检测到依赖工具 jq 或 curl 未安装,正在尝试自动安装..."
|
||||
if command -v apt-get &> /dev/null; then
|
||||
apt-get update >/dev/null && apt-get install -y jq curl
|
||||
elif command -v yum &> /dev/null; then
|
||||
yum install -y jq curl
|
||||
else
|
||||
echo -e "${RED}无法自动安装 jq/curl。请手动安装后再试。${NC}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- 函数: 安装 ss-rust ---
|
||||
install_ss_rust() {
|
||||
if [ -f /usr/local/bin/ss-rust ]; then
|
||||
echo -e "${GREEN}ss-rust 似乎已经安装,无需重复安装。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
# --- 新增: 自动获取最新版本逻辑 ---
|
||||
ensure_jq || exit 1
|
||||
echo "--> 正在获取 ss-rust 最新版本号..."
|
||||
SS_VERSION=$(curl -s "https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest" | jq -r .tag_name)
|
||||
if [ -z "$SS_VERSION" ] || [ "$SS_VERSION" == "null" ]; then
|
||||
echo -e "${RED}获取最新版本失败,请检查网络!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
SS_URL="https://github.com/shadowsocks/shadowsocks-rust/releases/download/${SS_VERSION}/shadowsocks-${SS_VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
SS_TAR_FILE="shadowsocks-${SS_VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
echo -e "${GREEN}检测到最新版本: ${SS_VERSION}${NC}"
|
||||
# ----------------------------
|
||||
|
||||
echo "--> 正在准备安装环境..."
|
||||
if command -v apt-get &> /dev/null; then
|
||||
apt-get update && apt-get install -y wget tar xz-utils openssl jq coreutils
|
||||
elif command -v yum &> /dev/null; then
|
||||
yum install -y wget tar xz-utils openssl jq coreutils
|
||||
else
|
||||
echo -e "${RED}无法确定包管理器,请手动安装 wget, tar, xz-utils, openssl, jq, coreutils。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "--> 正在下载、解压并部署 ss-rust..."
|
||||
if ! wget -O "${SS_TAR_FILE}" "${SS_URL}"; then
|
||||
echo -e "${RED}下载 ss-rust 失败!请检查网络或链接是否有效。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tar -xf "${SS_TAR_FILE}"
|
||||
mv ssserver /usr/local/bin/ss-rust
|
||||
chmod +x /usr/local/bin/ss-rust
|
||||
rm -f sslocal ssmanager ssurl "${SS_TAR_FILE}"
|
||||
echo " ss-rust 程序部署完成。"
|
||||
|
||||
mkdir -p /etc/ss-rust
|
||||
|
||||
read -p "请输入 ss-rust 的监听端口 (留空则随机生成): " PORT
|
||||
[ -z "$PORT" ] && PORT=$((RANDOM % 55536 + 10000))
|
||||
|
||||
read -p "请输入 ss-rust 的密码 (留空则随机生成): " PASSWORD
|
||||
[ -z "$PASSWORD" ] && PASSWORD=$(head -c 16 /dev/urandom | base64 -w 0)
|
||||
|
||||
echo "--> 正在创建配置文件..."
|
||||
cat > /etc/ss-rust/config.json <<EOF
|
||||
{
|
||||
"server": "0.0.0.0",
|
||||
"server_port": ${PORT},
|
||||
"password": "${PASSWORD}",
|
||||
"method": "2022-blake3-aes-128-gcm",
|
||||
"timeout": 300,
|
||||
"fast_open": false,
|
||||
"mode": "tcp_and_udp"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "--> 正在创建 systemd 服务..."
|
||||
cat > /etc/systemd/system/ss-rust.service <<EOF
|
||||
[Unit]
|
||||
Description=Shadowsocks Rust Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/ss-rust -c /etc/ss-rust/config.json
|
||||
Restart=always
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable ss-rust > /dev/null 2>&1
|
||||
systemctl start ss-rust
|
||||
|
||||
echo -e "${GREEN}🎉 ss-rust 服务器安装并配置成功!${NC}"
|
||||
view_config_ss_rust
|
||||
}
|
||||
|
||||
# --- 函数: 卸载 ss-rust ---
|
||||
uninstall_ss_rust() {
|
||||
if [ ! -f /usr/local/bin/ss-rust ]; then
|
||||
echo -e "${RED}ss-rust 未安装,无需卸载。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
read -p "警告:确定要卸载 ss-rust 吗?[y/N]: " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY]([eE][sS])?$ ]]; then
|
||||
echo "卸载操作已取消。"
|
||||
return
|
||||
fi
|
||||
|
||||
systemctl stop ss-rust
|
||||
systemctl disable ss-rust > /dev/null 2>&1
|
||||
rm -f /etc/systemd/system/ss-rust.service
|
||||
rm -f /usr/local/bin/ss-rust
|
||||
rm -rf /etc/ss-rust
|
||||
systemctl daemon-reload
|
||||
echo -e "${GREEN}ss-rust 已成功卸载。${NC}"
|
||||
|
||||
# 调用检查函数
|
||||
check_and_delete_script_if_all_uninstalled
|
||||
}
|
||||
|
||||
# --- 函数: 修改 ss-rust 配置 ---
|
||||
modify_config_ss_rust() {
|
||||
if [ ! -f /etc/ss-rust/config.json ]; then
|
||||
echo -e "${RED}ss-rust 未安装,无法修改配置。${NC}"; return; fi
|
||||
ensure_jq || return
|
||||
|
||||
read -p "请输入新的监听端口 (留空则随机生成): " PORT
|
||||
[ -z "$PORT" ] && PORT=$((RANDOM % 55536 + 10000))
|
||||
|
||||
read -p "请输入新的密码 (留空则随机生成): " PASSWORD
|
||||
[ -z "$PASSWORD" ] && PASSWORD=$(head -c 16 /dev/urandom | base64 -w 0)
|
||||
|
||||
jq ".server_port = ${PORT} | .password = \"${PASSWORD}\"" /etc/ss-rust/config.json > /tmp/ss-config.tmp && mv /tmp/ss-config.tmp /etc/ss-rust/config.json
|
||||
|
||||
systemctl restart ss-rust
|
||||
echo -e "${GREEN}🎉 ss-rust 配置已更新!${NC}"
|
||||
view_config_ss_rust
|
||||
}
|
||||
|
||||
# --- 函数: 查看 ss-rust 配置 ---
|
||||
view_config_ss_rust() {
|
||||
if [ ! -f /etc/ss-rust/config.json ]; then
|
||||
echo -e "${RED}ss-rust 未安装,无法查看配置。${NC}"; return; fi
|
||||
ensure_jq || return
|
||||
|
||||
local port=$(jq .server_port /etc/ss-rust/config.json)
|
||||
local password=$(jq -r .password /etc/ss-rust/config.json)
|
||||
local method=$(jq -r .method /etc/ss-rust/config.json)
|
||||
local ip_address=$(curl -s https://ipv4.icanhazip.com || echo "<您的服务器IP>")
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo " ss-rust 当前配置信息"
|
||||
echo "------------------------------------------"
|
||||
echo -e "端口 (Port) : ${GREEN}${port}${NC}"
|
||||
echo -e "密码 (Password) : ${GREEN}${password}${NC}"
|
||||
echo -e "加密 (Method) : ${GREEN}${method}${NC}"
|
||||
echo "------------------------------------------"
|
||||
echo "Surge 客户端配置:"
|
||||
echo -e "${GREEN}VPS = ss, ${ip_address}, ${port}, encrypt-method=${method}, password=${password}, udp-relay=true${NC}"
|
||||
echo "------------------------------------------"
|
||||
}
|
||||
|
||||
# --- 函数: ss-rust 服务管理 ---
|
||||
manage_ss_rust_service() {
|
||||
if [ ! -f /etc/systemd/system/ss-rust.service ]; then
|
||||
echo -e "${RED}ss-rust 未安装。${NC}"; return; fi
|
||||
case $1 in
|
||||
start) systemctl start ss-rust && echo -e "${GREEN}服务启动成功。${NC}" || echo -e "${RED}服务启动失败。${NC}" ;;
|
||||
stop) systemctl stop ss-rust && echo -e "${GREEN}服务已停止。${NC}" || echo -e "${RED}服务停止失败。${NC}" ;;
|
||||
restart) systemctl restart ss-rust && echo -e "${GREEN}服务重启成功。${NC}" || echo -e "${RED}服务重启失败。${NC}" ;;
|
||||
status) systemctl status ss-rust ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- 函数: ss-rust 子菜单 ---
|
||||
ss_rust_menu() {
|
||||
while true; do
|
||||
clear
|
||||
echo "=================================================="
|
||||
echo " shadowsocks-rust 管理界面"
|
||||
echo "=================================================="
|
||||
check_ss_rust_status
|
||||
echo "--------------------------------------------------"
|
||||
echo "1. 安装 ss-rust"
|
||||
echo "2. 卸载 ss-rust"
|
||||
echo "3. 修改 ss-rust 配置"
|
||||
echo "4. 查看 ss-rust 配置"
|
||||
echo "5. 启动 ss-rust"
|
||||
echo "6. 停止 ss-rust"
|
||||
echo "7. 重启 ss-rust"
|
||||
echo "8. 查看运行状态"
|
||||
echo "0. 返回主菜单"
|
||||
echo "=================================================="
|
||||
read -p "请输入选项 [0-8]: " choice
|
||||
|
||||
case $choice in
|
||||
1) install_ss_rust ;;
|
||||
2) uninstall_ss_rust ;;
|
||||
3) modify_config_ss_rust ;;
|
||||
4) view_config_ss_rust ;;
|
||||
5) manage_ss_rust_service start ;;
|
||||
6) manage_ss_rust_service stop ;;
|
||||
7) manage_ss_rust_service restart ;;
|
||||
8) manage_ss_rust_service status ;;
|
||||
0) return ;;
|
||||
*) echo -e "${RED}无效选项,请重试。${NC}" ;;
|
||||
esac
|
||||
[ "$choice" != "0" ] && read -p "按 Enter 键返回..."
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# =================================================================
|
||||
# S-H-A-D-O-W-T-L-S M-A-N-A-G-E-M-E-N-T
|
||||
# =================================================================
|
||||
|
||||
# --- shadowtls 变量定义 ---
|
||||
STLS_URL="https://github.com/ihciah/shadow-tls/releases/download/v0.2.25/shadow-tls-x86_64-unknown-linux-musl"
|
||||
|
||||
# --- 函数: 检查 shadowtls 安装和运行状态 ---
|
||||
check_shadowtls_status() {
|
||||
if [ -f /usr/local/bin/shadowtls ] && [ -f /etc/systemd/system/shadowtls.service ]; then
|
||||
echo -e "${GREEN}shadowtls 状态: 已安装${NC}"
|
||||
else
|
||||
echo -e "${RED}shadowtls 状态: 未安装${NC}"
|
||||
fi
|
||||
|
||||
if systemctl is-active --quiet shadowtls; then
|
||||
echo -e "${GREEN}服务状态 : 运行中${NC}"
|
||||
else
|
||||
echo -e "${RED}服务状态 : 未运行${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 函数: 安装 shadowtls ---
|
||||
install_shadowtls() {
|
||||
if [ -f /usr/local/bin/shadowtls ]; then
|
||||
echo -e "${GREEN}shadowtls 似乎已经安装。${NC}"; return; fi
|
||||
|
||||
echo "--> 正在下载 shadowtls..."
|
||||
curl -L "$STLS_URL" -o /usr/local/bin/shadowtls
|
||||
chmod +x /usr/local/bin/shadowtls
|
||||
|
||||
read -p "请输入 shadowtls 监听端口 (留空默认 8443): " LISTEN_PORT
|
||||
[ -z "$LISTEN_PORT" ] && LISTEN_PORT=8443
|
||||
|
||||
read -p "请输入后端的 ss-rust 端口: " SS_PORT
|
||||
while [ -z "$SS_PORT" ]; do
|
||||
read -p "${RED}后端 ss-rust 端口不能为空,请重新输入: ${NC}" SS_PORT
|
||||
done
|
||||
|
||||
read -p "请输入伪装域名 (留空默认 www.muji.com): " SNI_HOST
|
||||
[ -z "$SNI_HOST" ] && SNI_HOST="www.muji.com"
|
||||
|
||||
read -p "请输入 shadowtls 密码 (留空随机生成): " PASSWORD
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14)
|
||||
SPECIAL_CHARS='-/@'
|
||||
S1_INDEX=$(($RANDOM % 3)); S1=${SPECIAL_CHARS:$S1_INDEX:1}
|
||||
REMAINING_CHARS=${SPECIAL_CHARS//$S1/}; S2_INDEX=$(($RANDOM % 2)); S2=${REMAINING_CHARS:$S2_INDEX:1}
|
||||
COMBINED_CHARS="${ALPHANUM}${S1}${S2}"
|
||||
PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n')
|
||||
fi
|
||||
|
||||
echo "--> 正在创建 systemd 服务..."
|
||||
cat > /etc/systemd/system/shadowtls.service <<EOF
|
||||
[Unit]
|
||||
Description=ShadowTLS Server Service
|
||||
After=network-online.target
|
||||
Wants=network-online.target systemd-networkd-wait-online.service
|
||||
|
||||
[Service]
|
||||
LimitNOFILE=32767
|
||||
Type=simple
|
||||
User=root
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
ExecStart=/usr/local/bin/shadowtls --v3 --strict server --listen 0.0.0.0:${LISTEN_PORT} --server 127.0.0.1:${SS_PORT} --tls ${SNI_HOST}:443 --password ${PASSWORD}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable shadowtls > /dev/null 2>&1
|
||||
systemctl start shadowtls
|
||||
echo -e "${GREEN}🎉 shadowtls 服务器安装并配置成功!${NC}"
|
||||
view_config_shadowtls
|
||||
}
|
||||
|
||||
# --- 函数: 卸载 shadowtls ---
|
||||
uninstall_shadowtls() {
|
||||
if [ ! -f /usr/local/bin/shadowtls ]; then
|
||||
echo -e "${RED}shadowtls 未安装。${NC}"; return; fi
|
||||
|
||||
read -p "警告:确定要卸载 shadowtls 吗?[y/N]: " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY]([eE][sS])?$ ]]; then
|
||||
echo "卸载操作已取消。"; return; fi
|
||||
|
||||
systemctl stop shadowtls
|
||||
systemctl disable shadowtls > /dev/null 2>&1
|
||||
rm -f /etc/systemd/system/shadowtls.service
|
||||
rm -f /usr/local/bin/shadowtls
|
||||
systemctl daemon-reload
|
||||
echo -e "${GREEN}shadowtls 已成功卸载。${NC}"
|
||||
|
||||
# 调用检查函数
|
||||
check_and_delete_script_if_all_uninstalled
|
||||
}
|
||||
|
||||
# --- 函数: 查看 shadowtls 配置 ---
|
||||
view_config_shadowtls() {
|
||||
if [ ! -f /etc/systemd/system/shadowtls.service ]; then
|
||||
echo -e "${RED}shadowtls 未安装。${NC}"; return; fi
|
||||
|
||||
local exec_start=$(grep 'ExecStart=' /etc/systemd/system/shadowtls.service)
|
||||
# 使用更通用的正则表达式解析端口,以提高兼容性
|
||||
local listen_port=$(echo "$exec_start" | sed -n 's/.*--listen [^ ]*:\([0-9]*\).*/\1/p')
|
||||
local server_port=$(echo "$exec_start" | sed -n 's/.*--server [^ ]*:\([0-9]*\).*/\1/p')
|
||||
local sni_host=$(echo "$exec_start" | sed -n 's/.*--tls \([^:]*\):443.*/\1/p')
|
||||
local stls_password=$(echo "$exec_start" | sed -n 's/.*--password \([^ ]*\).*/\1/p')
|
||||
local ip_address=$(curl -s https://ipv4.icanhazip.com || echo "<您的服务器IP>")
|
||||
|
||||
local ss_password="<ss密码>"
|
||||
local ss_method="2022-blake3-aes-128-gcm"
|
||||
if [ -f /etc/ss-rust/config.json ] && ensure_jq; then
|
||||
ss_password=$(jq -r .password /etc/ss-rust/config.json)
|
||||
ss_method=$(jq -r .method /etc/ss-rust/config.json)
|
||||
fi
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo " shadowtls 当前配置信息"
|
||||
echo "------------------------------------------"
|
||||
echo -e "监听端口 : ${GREEN}${listen_port}${NC}"
|
||||
echo -e "密码 : ${GREEN}${stls_password}${NC}"
|
||||
echo -e "后端 SS 端口: ${GREEN}${server_port}${NC}"
|
||||
echo -e "伪装域名 : ${GREEN}${sni_host}${NC}"
|
||||
echo "------------------------------------------"
|
||||
echo "Surge 客户端配置:"
|
||||
echo -e "${GREEN}VPS = ss, ${ip_address}, ${listen_port}, encrypt-method=${ss_method}, password=${ss_password}, shadow-tls-password=${stls_password}, shadow-tls-sni=${sni_host}, shadow-tls-version=3, udp-relay=true${NC}"
|
||||
echo "------------------------------------------"
|
||||
}
|
||||
|
||||
# --- 函数: 修改 shadowtls 配置 ---
|
||||
modify_config_shadowtls() {
|
||||
if [ ! -f /etc/systemd/system/shadowtls.service ]; then
|
||||
echo -e "${RED}shadowtls 未安装。${NC}"; return; fi
|
||||
|
||||
read -p "请输入新的 shadowtls 监听端口 (留空默认 8443): " LISTEN_PORT
|
||||
[ -z "$LISTEN_PORT" ] && LISTEN_PORT=8443
|
||||
|
||||
read -p "请输入新的后端 ss-rust 端口: " SS_PORT
|
||||
while [ -z "$SS_PORT" ]; do
|
||||
read -p "${RED}后端 ss-rust 端口不能为空,请重新输入: ${NC}" SS_PORT
|
||||
done
|
||||
|
||||
read -p "请输入新的伪装域名 (留空默认 www.muji.com): " SNI_HOST
|
||||
[ -z "$SNI_HOST" ] && SNI_HOST="www.muji.com"
|
||||
|
||||
read -p "请输入新的 shadowtls 密码 (留空随机): " PASSWORD
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14)
|
||||
SPECIAL_CHARS='-/@'
|
||||
S1_INDEX=$(($RANDOM % 3)); S1=${SPECIAL_CHARS:$S1_INDEX:1}
|
||||
REMAINING_CHARS=${SPECIAL_CHARS//$S1/}; S2_INDEX=$(($RANDOM % 2)); S2=${REMAINING_CHARS:$S2_INDEX:1}
|
||||
COMBINED_CHARS="${ALPHANUM}${S1}${S2}"
|
||||
PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n')
|
||||
fi
|
||||
|
||||
local exec_line="ExecStart=/usr/local/bin/shadowtls --v3 --strict server --listen 0.0.0.0:${LISTEN_PORT} --server 127.0.0.1:${SS_PORT} --tls ${SNI_HOST}:443 --password ${PASSWORD}"
|
||||
sed -i "s|^ExecStart=.*|$exec_line|" /etc/systemd/system/shadowtls.service
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl restart shadowtls
|
||||
echo -e "${GREEN}🎉 shadowtls 配置已更新!${NC}"
|
||||
view_config_shadowtls
|
||||
}
|
||||
|
||||
# --- 函数: shadowtls 服务管理 ---
|
||||
manage_shadowtls_service() {
|
||||
if [ ! -f /etc/systemd/system/shadowtls.service ]; then
|
||||
echo -e "${RED}shadowtls 未安装。${NC}"; return; fi
|
||||
case $1 in
|
||||
start) systemctl start shadowtls && echo -e "${GREEN}服务启动成功。${NC}" || echo -e "${RED}服务启动失败。${NC}" ;;
|
||||
stop) systemctl stop shadowtls && echo -e "${GREEN}服务已停止。${NC}" || echo -e "${RED}服务停止失败。${NC}" ;;
|
||||
restart) systemctl restart shadowtls && echo -e "${GREEN}服务重启成功。${NC}" || echo -e "${RED}服务重启失败。${NC}" ;;
|
||||
status) systemctl status shadowtls ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- 函数: shadowtls 子菜单 ---
|
||||
shadowtls_menu() {
|
||||
while true; do
|
||||
clear
|
||||
echo "=================================================="
|
||||
echo " shadowtls 管理界面"
|
||||
echo "=================================================="
|
||||
check_shadowtls_status
|
||||
echo "--------------------------------------------------"
|
||||
echo "1. 安装 shadowtls"
|
||||
echo "2. 卸载 shadowtls"
|
||||
echo "3. 修改 shadowtls 配置"
|
||||
echo "4. 查看 shadowtls 配置"
|
||||
echo "5. 启动 shadowtls"
|
||||
echo "6. 停止 shadowtls"
|
||||
echo "7. 重启 shadowtls"
|
||||
echo "8. 查看运行状态"
|
||||
echo "0. 返回主菜单"
|
||||
echo "=================================================="
|
||||
read -p "请输入选项 [0-8]: " choice
|
||||
|
||||
case $choice in
|
||||
1) install_shadowtls ;;
|
||||
2) uninstall_shadowtls ;;
|
||||
3) modify_config_shadowtls ;;
|
||||
4) view_config_shadowtls ;;
|
||||
5) manage_shadowtls_service start ;;
|
||||
6) manage_shadowtls_service stop ;;
|
||||
7) manage_shadowtls_service restart ;;
|
||||
8) manage_shadowtls_service status ;;
|
||||
0) return ;;
|
||||
*) echo -e "${RED}无效选项,请重试。${NC}" ;;
|
||||
esac
|
||||
[ "$choice" != "0" ] && read -p "按 Enter 键返回..."
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# =================================================================
|
||||
# M-A-I-N M-E-N-U
|
||||
# =================================================================
|
||||
main_menu() {
|
||||
while true; do
|
||||
clear
|
||||
echo "=================================================="
|
||||
echo " SS-Rust & ShadowTLS 综合管理脚本"
|
||||
echo "=================================================="
|
||||
echo "1. shadowsocks-rust 管理"
|
||||
echo "2. shadowtls 管理"
|
||||
echo "0. 退出脚本"
|
||||
echo "=================================================="
|
||||
read -p "请输入选项 [0-2]: " choice
|
||||
|
||||
case $choice in
|
||||
1) ss_rust_menu ;;
|
||||
2) shadowtls_menu ;;
|
||||
0) break ;;
|
||||
*) echo -e "${RED}无效选项,请重试。${NC}"; sleep 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# --- 脚本入口 ---
|
||||
check_root
|
||||
main_menu
|
||||
echo "脚本已退出。"
|
||||
Reference in New Issue
Block a user