#!/bin/bash # SS-Rust 一键安装脚本 # 支持: ss2022 (2022-blake3-aes-128-gcm) / ss128 (aes-128-gcm) / 双节点 # 自动生成 SS订阅 + Surge + Clash 配置 # GitHub: https://github.com/mango082888-bit/ss-rust # ============ 颜色 ============ 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} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } # ============ 全局变量 ============ SERVER_IP="" PORT_2022="" KEY_2022="" METHOD_2022="" PORT_RAW="" KEY_RAW="" METHOD_RAW="" PORT_OBFS="" KEY_OBFS="" METHOD_OBFS="" OBFS_BACKEND_PORT="" OBFS_HOST="" NODE_MODE="" ENABLE_UDP="1" # ============ 基础检测 ============ check_root() { [[ $EUID -ne 0 ]] && error "请使用 root 用户运行" } get_pkg_manager() { if command -v apt &>/dev/null; then PKG="apt" elif command -v yum &>/dev/null; then PKG="yum" elif command -v apk &>/dev/null; then PKG="apk" else error "不支持的包管理器" fi } install_deps() { info "安装依赖..." case $PKG in apt) apt update -qq &>/dev/null; apt install -y -qq curl openssl xz-utils tar chrony python3 ca-certificates &>/dev/null ;; yum) yum install -y -q curl openssl xz tar chrony python3 ca-certificates &>/dev/null ;; apk) apk add --quiet curl openssl xz tar chrony python3 ca-certificates &>/dev/null ;; esac } get_arch() { case $(uname -m) in x86_64) echo "x86_64-unknown-linux-gnu" ;; aarch64) echo "aarch64-unknown-linux-gnu" ;; armv7l) echo "armv7-unknown-linux-gnueabihf" ;; *) error "不支持的架构: $(uname -m)" ;; esac } get_ip() { local ip ip=$(curl -s4m5 ip.sb 2>/dev/null || curl -s4m5 ifconfig.me 2>/dev/null || curl -s4m5 ipinfo.io/ip 2>/dev/null) [[ -z "$ip" ]] && error "无法获取公网IP" echo "$ip" } # ============ 时间同步 ============ sync_time() { info "同步系统时间..." # 1. 配置 chrony NTP 源 (国际 + 阿里云) if command -v chronyd &>/dev/null; then local chrony_conf if [[ -f /etc/chrony/chrony.conf ]]; then chrony_conf="/etc/chrony/chrony.conf" elif [[ -f /etc/chrony.conf ]]; then chrony_conf="/etc/chrony.conf" fi if [[ -n "${chrony_conf:-}" ]]; then # 备份原配置 cp "$chrony_conf" "${chrony_conf}.bak.$(date +%s)" 2>/dev/null || true # 检查是否已配置过 if ! grep -q '# SS-Rust NTP' "$chrony_conf" 2>/dev/null; then # 注释掉原有 server/pool 行 sed -i 's/^\(server \|pool \)/#&/' "$chrony_conf" 2>/dev/null || true # 追加可靠 NTP 源 cat >> "$chrony_conf" <<'NTP' # SS-Rust NTP — 多源冗余 server ntp.aliyun.com iburst server ntp1.aliyun.com iburst server time.cloudflare.com iburst pool pool.ntp.org iburst maxsources 4 # 允许大幅时钟跳变 (SS2022 对时间敏感) makestep 1 -1 NTP fi fi # 确保 chrony 服务启动并持久化 systemctl enable --now chronyd 2>/dev/null || \ systemctl enable --now chrony 2>/dev/null || true # 等一下让 chrony 连上源 sleep 1 chronyc makestep 2>/dev/null || true # 2. 没有 chrony 就用 ntpd elif command -v ntpd &>/dev/null; then systemctl enable --now ntpd 2>/dev/null || \ systemctl enable --now ntp 2>/dev/null || true ntpdate -u pool.ntp.org 2>/dev/null || true fi # 3. timedatectl 兜底 if command -v timedatectl &>/dev/null; then timedatectl set-ntp true 2>/dev/null || true fi # 4. 验证 local offset="" if command -v chronyc &>/dev/null; then offset=$(chronyc tracking 2>/dev/null | awk '/System time/{print $4, $5}') fi info "当前时间: $(date '+%Y-%m-%d %H:%M:%S %Z')${offset:+ | 偏移: $offset}" # 5. 检查偏移是否过大 (>30s 告警) if command -v chronyc &>/dev/null; then local drift_s drift_s=$(chronyc tracking 2>/dev/null | awk '/System time/{gsub(/[^0-9.]/,"",$4); printf "%d", $4}') if [[ "${drift_s:-0}" -gt 30 ]]; then warn "时钟偏移 ${drift_s}s 过大! SS2022 可能连接失败, 正在强制同步..." chronyc makestep 2>/dev/null || true sleep 2 info "同步后时间: $(date '+%Y-%m-%d %H:%M:%S %Z')" fi fi } # ============ 安装 ss-rust ============ install_ssrust() { info "安装 shadowsocks-rust..." local arch_name arch_name=$(get_arch) local latest latest=$(curl -sLm10 https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest | grep tag_name | head -1 | sed 's/.*"v/v/;s/".*//') [[ -z "$latest" ]] && latest="v1.24.0" info "版本: $latest" local url="https://github.com/shadowsocks/shadowsocks-rust/releases/download/${latest}/shadowsocks-${latest}.${arch_name}.tar.xz" cd /tmp rm -f ss-rust-dl.tar.xz ssserver sslocal ssurl ssmanager ssservice curl -sLm120 "$url" -o ss-rust-dl.tar.xz local fsize fsize=$(stat -c%s ss-rust-dl.tar.xz 2>/dev/null || stat -f%z ss-rust-dl.tar.xz 2>/dev/null) [[ "$fsize" -lt 100000 ]] && error "下载失败 (${fsize} bytes)" if command -v file &>/dev/null; then file ss-rust-dl.tar.xz | grep -q "XZ" || error "下载的文件不是有效的 XZ 压缩包" fi tar xf ss-rust-dl.tar.xz || error "解压失败" [[ ! -f ssserver ]] && error "找不到 ssserver" cp -f ssserver /usr/local/bin/ cp -f sslocal /usr/local/bin/ 2>/dev/null || true chmod +x /usr/local/bin/ssserver /usr/local/bin/sslocal 2>/dev/null rm -f ss-rust-dl.tar.xz ssserver sslocal ssurl ssmanager ssservice /usr/local/bin/ssserver --version && info "shadowsocks-rust 安装完成" || error "安装验证失败" } # ============ 安装 simple-obfs ============ install_simple_obfs() { command -v obfs-server &>/dev/null && return 0 info "安装 simple-obfs (HTTP 伪装插件)..." case $PKG in apt) apt update -qq &>/dev/null apt install -y -qq --no-install-recommends git build-essential autoconf automake libtool pkg-config libssl-dev libev-dev libc-ares-dev libpcre2-dev asciidoc xmlto &>/dev/null \ || error "安装 simple-obfs 编译依赖失败" ;; yum) yum install -y -q git gcc gcc-c++ make autoconf automake libtool pkgconfig openssl-devel libev-devel c-ares-devel pcre-devel asciidoc xmlto &>/dev/null \ || error "安装 simple-obfs 编译依赖失败" ;; apk) apk add --quiet git build-base autoconf automake libtool pkgconf openssl-dev libev-dev c-ares-dev pcre2-dev asciidoc xmlto &>/dev/null \ || error "安装 simple-obfs 编译依赖失败" ;; esac rm -rf /tmp/simple-obfs-src git clone --depth=1 https://github.com/shadowsocks/simple-obfs.git /tmp/simple-obfs-src &>/dev/null \ || error "下载 simple-obfs 失败" cd /tmp/simple-obfs-src git submodule update --init --recursive &>/dev/null || true ./autogen.sh &>/tmp/simple-obfs-autogen.log || error "simple-obfs autogen 失败: /tmp/simple-obfs-autogen.log" ./configure --disable-documentation &>/tmp/simple-obfs-configure.log || error "simple-obfs configure 失败: /tmp/simple-obfs-configure.log" make -j"$(nproc 2>/dev/null || echo 1)" &>/tmp/simple-obfs-make.log || error "simple-obfs 编译失败: /tmp/simple-obfs-make.log" make install &>/tmp/simple-obfs-install.log || error "simple-obfs 安装失败: /tmp/simple-obfs-install.log" ldconfig 2>/dev/null || true command -v obfs-server &>/dev/null || error "simple-obfs 安装验证失败" info "simple-obfs 安装完成" } # ============ 节点选择 + 端口密码 + 写配置 ============ select_and_configure() { SERVER_IP=$(get_ip) mkdir -p /etc/shadowsocks-rust # 清空 PORT_2022="" ; KEY_2022="" ; METHOD_2022="" PORT_RAW="" ; KEY_RAW="" ; METHOD_RAW="" PORT_OBFS="" ; KEY_OBFS="" ; METHOD_OBFS="" ; OBFS_BACKEND_PORT="" ; OBFS_HOST="" ENABLE_UDP="1" echo "" echo -e "${CYAN}════════════════════════════════════════${NC}" echo -e "${CYAN} 🔐 选择节点类型${NC}" echo -e "${CYAN}════════════════════════════════════════${NC}" echo "" echo -e " ${GREEN}1.${NC} SS2022-128 (2022-blake3-aes-128-gcm) — 新协议,推荐" echo -e " ${GREEN}2.${NC} SS-AES-128 (aes-128-gcm) — 传统协议,兼容性好" echo -e " ${GREEN}3.${NC} 双节点全装 (SS2022 + SS128)" echo -e " ${GREEN}4.${NC} SS2022-128 + HTTP obfs (simple-obfs 伪装)" echo "" read -rp "请选择 [1-4] (默认3): " node_choice node_choice=${node_choice:-3} read -rp "启用 UDP 转发? [Y/n]: " udp_choice udp_choice=${udp_choice:-Y} if [[ "$udp_choice" =~ ^[Yy]$ ]]; then ENABLE_UDP="1" else ENABLE_UDP="0" fi if [[ "$node_choice" == "1" || "$node_choice" == "3" ]]; then local dp=$((RANDOM % 10000 + 20000)) local dk=$(openssl rand -base64 16) echo "" echo -e " ${GREEN}SS2022-128 配置:${NC}" read -rp " 端口 [回车=${dp}]: " PORT_2022 PORT_2022=${PORT_2022:-$dp} read -rp " 密码 [回车=${dk}]: " KEY_2022 KEY_2022=${KEY_2022:-$dk} METHOD_2022="2022-blake3-aes-128-gcm" fi if [[ "$node_choice" == "2" || "$node_choice" == "3" ]]; then local dp2=$((RANDOM % 10000 + 30000)) local dk2=$(openssl rand -base64 16) echo "" echo -e " ${GREEN}SS-AES-128 配置:${NC}" read -rp " 端口 [回车=${dp2}]: " PORT_RAW PORT_RAW=${PORT_RAW:-$dp2} read -rp " 密码 [回车=${dk2}]: " KEY_RAW KEY_RAW=${KEY_RAW:-$dk2} METHOD_RAW="aes-128-gcm" fi if [[ "$node_choice" == "4" ]]; then local dp3=$((RANDOM % 10000 + 20000)) local dk3=$(openssl rand -base64 16) local bp=$((RANDOM % 10000 + 40000)) echo "" echo -e " ${GREEN}SS2022-128 + HTTP obfs 配置:${NC}" read -rp " 对外端口 [回车=${dp3}]: " PORT_OBFS PORT_OBFS=${PORT_OBFS:-$dp3} read -rp " 后端本地端口 [回车=${bp}]: " OBFS_BACKEND_PORT OBFS_BACKEND_PORT=${OBFS_BACKEND_PORT:-$bp} read -rp " 密码 [回车=${dk3}]: " KEY_OBFS KEY_OBFS=${KEY_OBFS:-$dk3} read -rp " 伪装 Host [回车=www.microsoft.com]: " OBFS_HOST OBFS_HOST=${OBFS_HOST:-www.microsoft.com} METHOD_OBFS="2022-blake3-aes-128-gcm" install_simple_obfs fi # 写 JSON 配置 python3 -c " import json servers = [] udp_enabled = '${ENABLE_UDP}' == '1' direct_mode = 'tcp_and_udp' if udp_enabled else 'tcp_only' if '${PORT_2022}': servers.append({ 'server': '0.0.0.0', 'server_port': int('${PORT_2022}'), 'method': '${METHOD_2022}', 'password': '${KEY_2022}', 'timeout': 300, 'fast_open': True, 'mode': direct_mode }) if '${PORT_RAW}': servers.append({ 'server': '0.0.0.0', 'server_port': int('${PORT_RAW}'), 'method': '${METHOD_RAW}', 'password': '${KEY_RAW}', 'timeout': 300, 'fast_open': True, 'mode': direct_mode }) if '${PORT_OBFS}': # simple-obfs only fronts TCP. Keep the obfuscated TCP backend on # localhost and expose native Shadowsocks UDP on the public port. servers.append({ 'server': '127.0.0.1', 'server_port': int('${OBFS_BACKEND_PORT}'), 'method': '${METHOD_OBFS}', 'password': '${KEY_OBFS}', 'timeout': 300, 'fast_open': True, 'mode': 'tcp_only' }) if udp_enabled: servers.append({ 'server': '0.0.0.0', 'server_port': int('${PORT_OBFS}'), 'method': '${METHOD_OBFS}', 'password': '${KEY_OBFS}', 'timeout': 300, 'mode': 'udp_only' }) with open('/etc/shadowsocks-rust/config.json', 'w') as f: json.dump({'servers': servers}, f, indent=4) print('OK') " || error "生成配置失败" if [[ -n "$PORT_OBFS" ]]; then cat > /etc/shadowsocks-rust/obfs.env < /etc/systemd/system/ss-rust.service << 'EOF' [Unit] Description=Shadowsocks-Rust Server After=network.target [Service] Type=simple ExecStart=/usr/local/bin/ssserver -c /etc/shadowsocks-rust/config.json Restart=on-failure RestartSec=5 LimitNOFILE=65535 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now ss-rust sleep 2 if systemctl is-active --quiet ss-rust; then info "ss-rust 服务启动成功" else journalctl -u ss-rust -n 5 --no-pager error "ss-rust 服务启动失败" fi setup_obfs_service } setup_obfs_service() { if [[ ! -f /etc/shadowsocks-rust/obfs.env ]]; then systemctl disable --now ss-rust-obfs 2>/dev/null || true rm -f /etc/systemd/system/ss-rust-obfs.service systemctl daemon-reload return 0 fi # shellcheck disable=SC1091 source /etc/shadowsocks-rust/obfs.env install_simple_obfs cat > /etc/systemd/system/ss-rust-obfs.service << EOF [Unit] Description=Shadowsocks simple-obfs HTTP Frontend After=network.target ss-rust.service Wants=ss-rust.service [Service] Type=simple ExecStart=/usr/local/bin/obfs-server -s 0.0.0.0 -p ${PORT_OBFS} -r 127.0.0.1:${OBFS_BACKEND_PORT} --obfs http --http-method GET Restart=on-failure RestartSec=5 LimitNOFILE=65535 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now ss-rust-obfs sleep 1 if systemctl is-active --quiet ss-rust-obfs; then info "simple-obfs 服务启动成功: 0.0.0.0:${PORT_OBFS} -> 127.0.0.1:${OBFS_BACKEND_PORT}" else journalctl -u ss-rust-obfs -n 10 --no-pager error "simple-obfs 服务启动失败" fi } # ============ 读取现有配置 ============ load_config() { [[ ! -f /etc/shadowsocks-rust/config.json ]] && return 1 SERVER_IP=$(get_ip) PORT_2022="" ; KEY_2022="" ; METHOD_2022="" PORT_RAW="" ; KEY_RAW="" ; METHOD_RAW="" PORT_OBFS="" ; KEY_OBFS="" ; METHOD_OBFS="" ; OBFS_BACKEND_PORT="" ; OBFS_HOST="" ENABLE_UDP="0" if [[ -f /etc/shadowsocks-rust/obfs.env ]]; then # shellcheck disable=SC1091 source /etc/shadowsocks-rust/obfs.env fi eval $(OBFS_BACKEND_PORT="${OBFS_BACKEND_PORT}" PORT_OBFS="${PORT_OBFS}" python3 -c " import json, os with open('/etc/shadowsocks-rust/config.json') as f: c = json.load(f) skip_ports = { int(p) for p in (os.environ.get('OBFS_BACKEND_PORT'), os.environ.get('PORT_OBFS')) if p and p.isdigit() } udp_enabled = False for s in c['servers']: mode = s.get('mode', 'tcp_only') if mode in ('tcp_and_udp', 'udp_only'): udp_enabled = True if s.get('server_port') in skip_ports or mode == 'udp_only': continue m = s['method'] if '2022' in m: print(f'PORT_2022={s[\"server_port\"]}') print(f'KEY_2022={s[\"password\"]}') print(f'METHOD_2022={m}') else: print(f'PORT_RAW={s[\"server_port\"]}') print(f'KEY_RAW={s[\"password\"]}') print(f'METHOD_RAW={m}') print(f'ENABLE_UDP={1 if udp_enabled else 0}') " 2>/dev/null) return 0 } # ============ 生成订阅 ============ gen_subscribe() { load_config || return local sub_dir="/etc/shadowsocks-rust/subscribe" mkdir -p "$sub_dir" local uris="" surge="" clash="" info_txt="" local udp_clash="false" udp_label="关闭" if [[ "${ENABLE_UDP:-0}" == "1" ]]; then udp_clash="true" udp_label="开启" fi if [[ -n "$PORT_2022" ]]; then local uri="ss://$(echo -n "${METHOD_2022}:${KEY_2022}" | base64 -w0)@${SERVER_IP}:${PORT_2022}#SS2022-128" URI_2022="$uri" uris="${uris}${uri}\n" surge="${surge}SS2022-128 = ss, ${SERVER_IP}, ${PORT_2022}, encrypt-method=${METHOD_2022}, password=${KEY_2022}\n" clash="${clash} - name: SS2022-128\n type: ss\n server: ${SERVER_IP}\n port: ${PORT_2022}\n cipher: ${METHOD_2022}\n password: \"${KEY_2022}\"\n udp: ${udp_clash}\n\n" info_txt="${info_txt}【SS2022-AES-128】新协议\n 地址: ${SERVER_IP}\n 端口: ${PORT_2022}\n 加密: ${METHOD_2022}\n 密码: ${KEY_2022}\n UDP: ${udp_label}\n\n" fi if [[ -n "$PORT_RAW" ]]; then local uri="ss://$(echo -n "${METHOD_RAW}:${KEY_RAW}" | base64 -w0)@${SERVER_IP}:${PORT_RAW}#SS-AES-128" URI_RAW="$uri" uris="${uris}${uri}\n" surge="${surge}SS-AES-128 = ss, ${SERVER_IP}, ${PORT_RAW}, encrypt-method=${METHOD_RAW}, password=${KEY_RAW}\n" clash="${clash} - name: SS-AES-128\n type: ss\n server: ${SERVER_IP}\n port: ${PORT_RAW}\n cipher: ${METHOD_RAW}\n password: \"${KEY_RAW}\"\n udp: ${udp_clash}\n\n" info_txt="${info_txt}【SS-AES-128】传统协议\n 地址: ${SERVER_IP}\n 端口: ${PORT_RAW}\n 加密: ${METHOD_RAW}\n 密码: ${KEY_RAW}\n UDP: ${udp_label}\n\n" fi if [[ -n "$PORT_OBFS" ]]; then local plugin_raw="obfs-local;obfs=http;obfs-host=${OBFS_HOST}" local plugin_enc plugin_enc=$(PLUGIN_RAW="$plugin_raw" python3 -c 'import os, urllib.parse; print(urllib.parse.quote(os.environ["PLUGIN_RAW"], safe=""))') local uri="ss://$(echo -n "${METHOD_OBFS}:${KEY_OBFS}" | base64 -w0)@${SERVER_IP}:${PORT_OBFS}/?plugin=${plugin_enc}#SS2022-OBFS-HTTP" URI_OBFS="$uri" uris="${uris}${uri}\n" surge="${surge}SS2022-OBFS-HTTP = ss, ${SERVER_IP}, ${PORT_OBFS}, encrypt-method=${METHOD_OBFS}, password=${KEY_OBFS}, obfs=http, obfs-host=${OBFS_HOST}\n" clash="${clash} - name: SS2022-OBFS-HTTP\n type: ss\n server: ${SERVER_IP}\n port: ${PORT_OBFS}\n cipher: ${METHOD_OBFS}\n password: \"${KEY_OBFS}\"\n udp: ${udp_clash}\n plugin: obfs\n plugin-opts:\n mode: http\n host: ${OBFS_HOST}\n\n" info_txt="${info_txt}【SS2022 + HTTP obfs】simple-obfs 伪装\n 地址: ${SERVER_IP}\n 端口: ${PORT_OBFS}\n 加密: ${METHOD_OBFS}\n 密码: ${KEY_OBFS}\n 插件: obfs/http\n Host: ${OBFS_HOST}\n 后端: 127.0.0.1:${OBFS_BACKEND_PORT}\n UDP: ${udp_label}(公网原生 SS UDP)\n\n" fi echo -e "$uris" | base64 -w0 > "$sub_dir/subscribe.txt" echo -e "# Surge SS | $(date '+%Y-%m-%d %H:%M:%S') | ${SERVER_IP}\n[Proxy]\n${surge}" > "$sub_dir/surge.conf" echo -e "# Clash SS | $(date '+%Y-%m-%d %H:%M:%S')\nproxies:\n${clash}" > "$sub_dir/clash.yaml" echo -e "═══ SS-Rust 节点 | $(date '+%Y-%m-%d %H:%M:%S') | ${SERVER_IP} ═══\n\n${info_txt}\n【SS 链接】\n${uris}" > "$sub_dir/info.txt" } # ============ 显示结果 ============ show_result() { load_config || return local udp_label="关闭" [[ "${ENABLE_UDP:-0}" == "1" ]] && udp_label="开启" echo "" echo -e "${CYAN}════════════════════════════════════════${NC}" echo -e "${CYAN} 🚀 Shadowsocks-Rust 安装完成${NC}" echo -e "${CYAN}════════════════════════════════════════${NC}" echo "" if [[ -n "$PORT_2022" ]]; then echo -e "${GREEN}【SS2022-AES-128】新协议${NC}" echo -e " 地址: ${SERVER_IP}" echo -e " 端口: ${YELLOW}${PORT_2022}${NC}" echo -e " 加密: ${METHOD_2022}" echo -e " 密码: ${YELLOW}${KEY_2022}${NC}" echo -e " UDP: ${udp_label}" echo "" fi if [[ -n "$PORT_RAW" ]]; then echo -e "${GREEN}【SS-AES-128】传统协议${NC}" echo -e " 地址: ${SERVER_IP}" echo -e " 端口: ${YELLOW}${PORT_RAW}${NC}" echo -e " 加密: ${METHOD_RAW}" echo -e " 密码: ${YELLOW}${KEY_RAW}${NC}" echo -e " UDP: ${udp_label}" echo "" fi if [[ -n "$PORT_OBFS" ]]; then echo -e "${GREEN}【SS2022 + HTTP obfs】simple-obfs 伪装${NC}" echo -e " 地址: ${SERVER_IP}" echo -e " 端口: ${YELLOW}${PORT_OBFS}${NC}" echo -e " 加密: ${METHOD_OBFS}" echo -e " 密码: ${YELLOW}${KEY_OBFS}${NC}" echo -e " 插件: obfs / http" echo -e " Host: ${OBFS_HOST}" echo -e " UDP: ${udp_label}" echo "" fi echo -e "${CYAN}────────────────────────────────────────${NC}" echo -e "${GREEN}【Surge 格式】${NC}" [[ -n "$PORT_2022" ]] && echo " SS2022-128 = ss, ${SERVER_IP}, ${PORT_2022}, encrypt-method=${METHOD_2022}, password=${KEY_2022}" [[ -n "$PORT_RAW" ]] && echo " SS-AES-128 = ss, ${SERVER_IP}, ${PORT_RAW}, encrypt-method=${METHOD_RAW}, password=${KEY_RAW}" [[ -n "$PORT_OBFS" ]] && echo " SS2022-OBFS-HTTP = ss, ${SERVER_IP}, ${PORT_OBFS}, encrypt-method=${METHOD_OBFS}, password=${KEY_OBFS}, obfs=http, obfs-host=${OBFS_HOST}" echo "" echo -e "${CYAN}────────────────────────────────────────${NC}" echo -e "${GREEN}【SS 链接】${NC}" [[ -n "${URI_2022:-}" ]] && echo " ${URI_2022}" [[ -n "${URI_RAW:-}" ]] && echo " ${URI_RAW}" [[ -n "${URI_OBFS:-}" ]] && echo " ${URI_OBFS}" echo "" echo -e "${CYAN}────────────────────────────────────────${NC}" echo -e "${GREEN}【文件】${NC}" echo " 配置: /etc/shadowsocks-rust/config.json" echo " 订阅: /etc/shadowsocks-rust/subscribe/" echo "" echo -e "${CYAN}【管理】${NC} 再次运行脚本进入管理菜单" echo -e "${CYAN}════════════════════════════════════════${NC}" } # ============ 查看配置 ============ show_config() { load_config || error "未安装" echo "" echo -e "${CYAN} 📋 当前配置 | 状态: $(systemctl is-active ss-rust 2>/dev/null)${NC}" echo "" cat /etc/shadowsocks-rust/config.json echo "" [[ -f /etc/shadowsocks-rust/subscribe/info.txt ]] && cat /etc/shadowsocks-rust/subscribe/info.txt } # ============ 修改端口 ============ change_port() { load_config || error "未安装" echo "" [[ -n "$PORT_2022" ]] && echo -e " 1) SS2022-128 | 端口 ${PORT_2022}" [[ -n "$PORT_RAW" ]] && echo -e " 2) SS-AES-128 | 端口 ${PORT_RAW}" echo "" read -rp "节点编号: " pn read -rp "新端口: " new_port python3 -c " import json with open('/etc/shadowsocks-rust/config.json') as f: c = json.load(f) idx = int('${pn}') - 1 if 0 <= idx < len(c['servers']): c['servers'][idx]['server_port'] = int('${new_port}') with open('/etc/shadowsocks-rust/config.json','w') as f: json.dump(c, f, indent=4) " systemctl restart ss-rust setup_obfs_service gen_subscribe info "端口已改为 ${new_port}" } # ============ 重置密钥 ============ reset_keys() { load_config || error "未安装" python3 -c " import json,base64,os with open('/etc/shadowsocks-rust/config.json') as f: c = json.load(f) for s in c['servers']: s['password'] = base64.b64encode(os.urandom(16)).decode() with open('/etc/shadowsocks-rust/config.json','w') as f: json.dump(c, f, indent=4) " if [[ -f /etc/shadowsocks-rust/obfs.env ]]; then local new_obfs_key new_obfs_key=$(openssl rand -base64 16) sed -i "s|^KEY_OBFS=.*|KEY_OBFS=${new_obfs_key}|" /etc/shadowsocks-rust/obfs.env # shellcheck disable=SC1091 source /etc/shadowsocks-rust/obfs.env python3 -c " import json with open('/etc/shadowsocks-rust/config.json') as f: c = json.load(f) for s in c.get('servers', []): if str(s.get('server_port')) in ('${OBFS_BACKEND_PORT}', '${PORT_OBFS}'): s['password'] = '${KEY_OBFS}' with open('/etc/shadowsocks-rust/config.json','w') as f: json.dump(c, f, indent=4) " fi systemctl restart ss-rust setup_obfs_service gen_subscribe info "密钥已重置" show_result } # ============ BBR 优化 ============ setup_bbr() { echo "" echo -e "${CYAN}════════════════════════════════════════${NC}" echo -e "${CYAN} ⚡ BBR Blast Smooth v2${NC}" echo -e "${CYAN}════════════════════════════════════════${NC}" echo "" # 检测是否已启用 local cc=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null) local qd=$(sysctl -n net.core.default_qdisc 2>/dev/null) if [[ "$cc" == "bbr" && "$qd" == "fq" ]] && grep -q "TCP Tuning" /etc/sysctl.conf 2>/dev/null; then info "BBR + TCP 完整调优已启用,无需重复配置" return 0 fi if [[ "$cc" == "bbr" && "$qd" == "fq" ]]; then info "检测到 BBR 已启用,升级为完整 TCP 调优..." fi # 检测系统 if [[ ! -f /etc/os-release ]]; then warn "无法检测系统,跳过 BBR"; return 1 fi . /etc/os-release local os_name="$ID $VERSION_ID" info "系统: $os_name" # 检测内存,选择 profile local mem=$(free -m | awk '/^Mem:/{print $2}') local profile rmem wmem tcp_rmem tcp_wmem if [[ "$mem" -lt 512 ]]; then profile="micro"; rmem=8388608; wmem=8388608 tcp_rmem="4096 32768 8388608"; tcp_wmem="4096 32768 8388608" elif [[ "$mem" -lt 1024 ]]; then profile="small"; rmem=16777216; wmem=16777216 tcp_rmem="4096 65536 16777216"; tcp_wmem="4096 65536 16777216" elif [[ "$mem" -lt 2048 ]]; then profile="medium"; rmem=33554432; wmem=33554432 tcp_rmem="4096 87380 33554432"; tcp_wmem="4096 65536 33554432" elif [[ "$mem" -lt 4096 ]]; then profile="large"; rmem=67108864; wmem=67108864 tcp_rmem="4096 87380 67108864"; tcp_wmem="4096 65536 67108864" else profile="xlarge"; rmem=134217728; wmem=134217728 tcp_rmem="4096 87380 134217728"; tcp_wmem="4096 65536 134217728" fi info "内存: ${mem}MB | Profile: $profile | Buffer: $((rmem/1024/1024))MB" # 备份 if [[ -f /etc/sysctl.conf ]]; then cp /etc/sysctl.conf /etc/sysctl.conf.bak.$(date +%Y%m%d%H%M%S) fi # 写入配置 sed -i '/# === BBR Blast/,/# === END BBR/d' /etc/sysctl.conf 2>/dev/null || true cat >> /etc/sysctl.conf </dev/null 2>&1 # 验证 cc=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null) qd=$(sysctl -n net.core.default_qdisc 2>/dev/null) if [[ "$cc" == "bbr" && "$qd" == "fq" ]]; then info "BBR 启用成功 ✓ (congestion=$cc, qdisc=$qd)" else warn "BBR 可能需要重启生效" fi } # ============ 卸载 ============ uninstall() { warn "卸载 shadowsocks-rust..." systemctl stop ss-rust ss-rust-obfs 2>/dev/null systemctl disable ss-rust ss-rust-obfs 2>/dev/null rm -f /etc/systemd/system/ss-rust.service /etc/systemd/system/ss-rust-obfs.service rm -f /usr/local/bin/ssserver /usr/local/bin/sslocal /usr/local/bin/ssurl rm -rf /etc/shadowsocks-rust systemctl daemon-reload info "卸载完成" } # ============ 安装流程 ============ do_install() { get_pkg_manager install_deps sync_time install_ssrust select_and_configure setup_service gen_subscribe show_result echo "" read -rp "是否开启 BBR 加速? [Y/n]: " bbr_choice bbr_choice=${bbr_choice:-Y} [[ "$bbr_choice" =~ ^[Yy]$ ]] && setup_bbr } # ============ 管理菜单 ============ show_menu() { echo "" echo -e "${CYAN}════════════════════════════════════════${NC}" echo -e "${CYAN} 🚀 SS-Rust 管理面板${NC}" echo -e "${CYAN}════════════════════════════════════════${NC}" echo "" echo -e " ${GREEN}1.${NC} 重新安装 (选择节点类型)" echo -e " ${GREEN}2.${NC} 查看配置 + 节点信息" echo -e " ${GREEN}3.${NC} 修改端口" echo -e " ${GREEN}4.${NC} 重置密钥" echo -e " ${GREEN}5.${NC} 启动服务" echo -e " ${GREEN}6.${NC} 停止服务" echo -e " ${GREEN}7.${NC} 重启服务" echo -e " ${GREEN}8.${NC} 查看日志" echo -e " ${GREEN}10.${NC} ⚡ BBR 加速优化" echo -e " ${GREEN}11.${NC} 🕐 时间同步 (SS2022必需)" echo -e " ${RED}9.${NC} 卸载" echo -e " ${YELLOW}0.${NC} 退出" echo "" read -rp "请选择 [0-11]: " choice case "$choice" in 1) do_install ;; 2) show_config ;; 3) change_port ;; 4) reset_keys ;; 5) systemctl start ss-rust && info "已启动" ;; 6) systemctl stop ss-rust && info "已停止" ;; 7) systemctl restart ss-rust; setup_obfs_service; info "已重启" ;; 8) journalctl -u ss-rust -u ss-rust-obfs --no-pager -n 50 ;; 9) uninstall ;; 10) setup_bbr ;; 11) get_pkg_manager; install_deps; sync_time ;; 0) exit 0 ;; *) warn "无效选择" ;; esac } # ============ 主入口 ============ main() { check_root case "${1:-}" in install) do_install ;; uninstall|remove) uninstall ;; show|config|info) show_config ;; restart) systemctl restart ss-rust; setup_obfs_service; info "已重启" ;; start) systemctl start ss-rust && info "已启动" ;; stop) systemctl stop ss-rust && info "已停止" ;; log|logs) journalctl -u ss-rust -u ss-rust-obfs --no-pager -n 50 ;; reset) reset_keys ;; bbr) setup_bbr ;; sync|time) get_pkg_manager; install_deps; sync_time ;; *) if [[ -f /etc/shadowsocks-rust/config.json ]]; then show_menu else do_install fi ;; esac } main "$@"