495 lines
15 KiB
Bash
495 lines
15 KiB
Bash
#!/bin/bash
|
||
# SS-Rust 一键安装脚本 (ss2022 + aes-128-gcm)
|
||
# 自动生成订阅链接 + Surge 配置
|
||
# Usage: curl -sL <url> | bash
|
||
|
||
# 不用 set -e,手动处理错误
|
||
|
||
# ============ 颜色 ============
|
||
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; }
|
||
|
||
# ============ 检测系统 ============
|
||
check_root() {
|
||
[[ $EUID -ne 0 ]] && error "请使用 root 用户运行"
|
||
}
|
||
|
||
check_os() {
|
||
if [[ -f /etc/debian_version ]]; then
|
||
PKG="apt"
|
||
elif [[ -f /etc/redhat-release ]]; then
|
||
PKG="yum"
|
||
else
|
||
error "不支持的系统"
|
||
fi
|
||
}
|
||
|
||
# ============ 时间同步 ============
|
||
sync_time() {
|
||
info "同步系统时间..."
|
||
if command -v timedatectl &>/dev/null; then
|
||
timedatectl set-ntp true 2>/dev/null || true
|
||
fi
|
||
if command -v ntpdate &>/dev/null; then
|
||
ntpdate -u pool.ntp.org 2>/dev/null || true
|
||
elif command -v chronyd &>/dev/null; then
|
||
chronyc makestep 2>/dev/null || true
|
||
else
|
||
$PKG install -y chrony &>/dev/null
|
||
systemctl enable --now chronyd 2>/dev/null || true
|
||
chronyc makestep 2>/dev/null || true
|
||
fi
|
||
info "当前时间: $(date '+%Y-%m-%d %H:%M:%S %Z')"
|
||
}
|
||
|
||
# ============ 安装 ss-rust ============
|
||
install_ssrust() {
|
||
info "安装 shadowsocks-rust..."
|
||
|
||
ARCH=$(uname -m)
|
||
case $ARCH in
|
||
x86_64) ARCH_NAME="x86_64-unknown-linux-gnu" ;;
|
||
aarch64) ARCH_NAME="aarch64-unknown-linux-gnu" ;;
|
||
*) error "不支持的架构: $ARCH" ;;
|
||
esac
|
||
|
||
# 获取最新版本
|
||
LATEST=$(curl -sL https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest | grep tag_name | head -1 | grep -oP 'v[\d.]+')
|
||
[[ -z "$LATEST" ]] && LATEST="v1.21.2"
|
||
info "版本: $LATEST"
|
||
|
||
URL="https://github.com/shadowsocks/shadowsocks-rust/releases/download/${LATEST}/shadowsocks-${LATEST}.${ARCH_NAME}.tar.xz"
|
||
|
||
cd /tmp
|
||
curl -sL "$URL" -o ss-rust.tar.xz || error "下载失败"
|
||
tar xf ss-rust.tar.xz
|
||
cp -f ssserver sslocal ssurl /usr/local/bin/ 2>/dev/null || cp -f ss* /usr/local/bin/
|
||
chmod +x /usr/local/bin/ss*
|
||
rm -f ss-rust.tar.xz
|
||
|
||
info "shadowsocks-rust 安装完成"
|
||
}
|
||
|
||
# ============ 生成密钥 ============
|
||
gen_key_128() {
|
||
openssl rand -base64 16
|
||
}
|
||
|
||
gen_key_256() {
|
||
openssl rand -base64 32
|
||
}
|
||
|
||
# ============ 获取公网IP ============
|
||
get_ip() {
|
||
IP=$(curl -s4 ip.sb 2>/dev/null || curl -s4 ifconfig.me 2>/dev/null || curl -s4 ipinfo.io/ip 2>/dev/null)
|
||
[[ -z "$IP" ]] && error "无法获取公网IP"
|
||
echo "$IP"
|
||
}
|
||
|
||
# ============ 生成配置 ============
|
||
gen_config() {
|
||
SERVER_IP=$(get_ip)
|
||
|
||
# ss2022-128 + ss裸128 端口和密钥
|
||
PORT_2022=$((RANDOM % 10000 + 20000))
|
||
PORT_RAW=$((RANDOM % 10000 + 30000))
|
||
KEY_2022=$(gen_key_128)
|
||
KEY_RAW=$(openssl rand -base64 16)
|
||
|
||
METHOD_2022="2022-blake3-aes-128-gcm"
|
||
METHOD_RAW="aes-128-gcm"
|
||
|
||
mkdir -p /etc/shadowsocks-rust
|
||
|
||
# 多端口配置
|
||
cat > /etc/shadowsocks-rust/config.json << EOF
|
||
{
|
||
"servers": [
|
||
{
|
||
"server": "0.0.0.0",
|
||
"server_port": ${PORT_2022},
|
||
"method": "${METHOD_2022}",
|
||
"password": "${KEY_2022}",
|
||
"timeout": 300,
|
||
"fast_open": true
|
||
},
|
||
{
|
||
"server": "0.0.0.0",
|
||
"server_port": ${PORT_RAW},
|
||
"method": "${METHOD_RAW}",
|
||
"password": "${KEY_RAW}",
|
||
"timeout": 300,
|
||
"fast_open": true
|
||
}
|
||
]
|
||
}
|
||
EOF
|
||
|
||
info "配置文件: /etc/shadowsocks-rust/config.json"
|
||
}
|
||
|
||
# ============ systemd 服务 ============
|
||
setup_service() {
|
||
cat > /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 1
|
||
|
||
if systemctl is-active --quiet ss-rust; then
|
||
info "ss-rust 服务启动成功"
|
||
else
|
||
error "ss-rust 服务启动失败,请检查日志: journalctl -u ss-rust"
|
||
fi
|
||
}
|
||
|
||
# ============ 生成订阅 ============
|
||
gen_subscribe() {
|
||
SERVER_IP=$(get_ip)
|
||
SUB_DIR="/etc/shadowsocks-rust/subscribe"
|
||
mkdir -p "$SUB_DIR"
|
||
|
||
# SS URI 格式: ss://method:password@host:port#name
|
||
URI_2022="ss://$(echo -n "${METHOD_2022}:${KEY_2022}" | base64 -w0)@${SERVER_IP}:${PORT_2022}#SS2022-128"
|
||
URI_RAW="ss://$(echo -n "${METHOD_RAW}:${KEY_RAW}" | base64 -w0)@${SERVER_IP}:${PORT_RAW}#SS-AES-128"
|
||
|
||
# Base64 订阅
|
||
echo -e "${URI_2022}\n${URI_RAW}" | base64 -w0 > "$SUB_DIR/subscribe.txt"
|
||
|
||
# Surge 配置
|
||
cat > "$SUB_DIR/surge.conf" << EOF
|
||
# Surge SS 配置
|
||
# 生成时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||
# 服务器: ${SERVER_IP}
|
||
|
||
[Proxy]
|
||
SS2022-128 = ss, ${SERVER_IP}, ${PORT_2022}, encrypt-method=${METHOD_2022}, password=${KEY_2022}
|
||
SS-AES-128 = ss, ${SERVER_IP}, ${PORT_RAW}, encrypt-method=${METHOD_RAW}, password=${KEY_RAW}
|
||
|
||
[Proxy Group]
|
||
Proxy = select, SS2022-128, SS-AES-128, DIRECT
|
||
EOF
|
||
|
||
# Clash 配置
|
||
cat > "$SUB_DIR/clash.yaml" << EOF
|
||
# Clash SS 配置
|
||
# 生成时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||
|
||
proxies:
|
||
- name: SS2022-128
|
||
type: ss
|
||
server: ${SERVER_IP}
|
||
port: ${PORT_2022}
|
||
cipher: ${METHOD_2022}
|
||
password: "${KEY_2022}"
|
||
|
||
- name: SS-AES-128
|
||
type: ss
|
||
server: ${SERVER_IP}
|
||
port: ${PORT_RAW}
|
||
cipher: ${METHOD_RAW}
|
||
password: "${KEY_RAW}"
|
||
EOF
|
||
|
||
# 纯文本信息
|
||
cat > "$SUB_DIR/info.txt" << EOF
|
||
========================================
|
||
Shadowsocks-Rust 节点信息
|
||
生成时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||
服务器IP: ${SERVER_IP}
|
||
========================================
|
||
|
||
【节点1】SS2022-AES-128 (新协议)
|
||
地址: ${SERVER_IP}
|
||
端口: ${PORT_2022}
|
||
加密: ${METHOD_2022}
|
||
密码: ${KEY_2022}
|
||
|
||
【节点2】SS-AES-128 (传统协议)
|
||
地址: ${SERVER_IP}
|
||
端口: ${PORT_RAW}
|
||
加密: ${METHOD_RAW}
|
||
密码: ${KEY_RAW}
|
||
|
||
【SS 订阅链接】
|
||
${URI_2022}
|
||
${URI_RAW}
|
||
|
||
【Surge 配置】
|
||
SS2022-128 = ss, ${SERVER_IP}, ${PORT_2022}, encrypt-method=${METHOD_2022}, password=${KEY_2022}
|
||
SS-AES-128 = ss, ${SERVER_IP}, ${PORT_RAW}, encrypt-method=${METHOD_RAW}, password=${KEY_RAW}
|
||
|
||
========================================
|
||
EOF
|
||
}
|
||
|
||
# ============ 输出结果 ============
|
||
show_result() {
|
||
echo ""
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
echo -e "${CYAN} 🚀 Shadowsocks-Rust 安装完成${NC}"
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}【节点1】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 ""
|
||
echo -e "${GREEN}【节点2】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 ""
|
||
echo -e "${CYAN}────────────────────────────────────────${NC}"
|
||
echo -e "${GREEN}【Surge 格式】${NC}"
|
||
echo -e " SS2022-128 = ss, ${SERVER_IP}, ${PORT_2022}, encrypt-method=${METHOD_2022}, password=${KEY_2022}"
|
||
echo -e " SS-AES-128 = ss, ${SERVER_IP}, ${PORT_RAW}, encrypt-method=${METHOD_RAW}, password=${KEY_RAW}"
|
||
echo ""
|
||
echo -e "${CYAN}────────────────────────────────────────${NC}"
|
||
echo -e "${GREEN}【SS 链接】${NC}"
|
||
echo -e " ${URI_2022}"
|
||
echo -e " ${URI_RAW}"
|
||
echo ""
|
||
echo -e "${CYAN}────────────────────────────────────────${NC}"
|
||
echo -e "${GREEN}【文件位置】${NC}"
|
||
echo -e " 配置: /etc/shadowsocks-rust/config.json"
|
||
echo -e " 订阅: /etc/shadowsocks-rust/subscribe/subscribe.txt"
|
||
echo -e " Surge: /etc/shadowsocks-rust/subscribe/surge.conf"
|
||
echo -e " Clash: /etc/shadowsocks-rust/subscribe/clash.yaml"
|
||
echo -e " 信息: /etc/shadowsocks-rust/subscribe/info.txt"
|
||
echo ""
|
||
echo -e "${CYAN}【管理命令】${NC}"
|
||
echo -e " 启动: systemctl start ss-rust"
|
||
echo -e " 停止: systemctl stop ss-rust"
|
||
echo -e " 状态: systemctl status ss-rust"
|
||
echo -e " 日志: journalctl -u ss-rust -f"
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
}
|
||
|
||
# ============ 卸载 ============
|
||
uninstall() {
|
||
warn "卸载 shadowsocks-rust..."
|
||
systemctl stop ss-rust 2>/dev/null
|
||
systemctl disable ss-rust 2>/dev/null
|
||
rm -f /etc/systemd/system/ss-rust.service
|
||
rm -f /usr/local/bin/ss{server,local,url}
|
||
rm -rf /etc/shadowsocks-rust
|
||
systemctl daemon-reload
|
||
info "卸载完成"
|
||
exit 0
|
||
}
|
||
|
||
# ============ 查看配置 ============
|
||
show_config() {
|
||
if [[ ! -f /etc/shadowsocks-rust/config.json ]]; then
|
||
error "未安装 shadowsocks-rust"
|
||
fi
|
||
echo ""
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
echo -e "${CYAN} 📋 当前配置${NC}"
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
echo ""
|
||
cat /etc/shadowsocks-rust/config.json
|
||
echo ""
|
||
echo -e "${CYAN}────────────────────────────────────────${NC}"
|
||
echo -e "${GREEN}服务状态:${NC}"
|
||
systemctl status ss-rust --no-pager 2>/dev/null | head -5
|
||
echo ""
|
||
if [[ -f /etc/shadowsocks-rust/subscribe/info.txt ]]; then
|
||
cat /etc/shadowsocks-rust/subscribe/info.txt
|
||
fi
|
||
}
|
||
|
||
# ============ 修改端口 ============
|
||
change_port() {
|
||
if [[ ! -f /etc/shadowsocks-rust/config.json ]]; then
|
||
error "未安装 shadowsocks-rust"
|
||
fi
|
||
echo ""
|
||
echo -e "${GREEN}当前配置:${NC}"
|
||
python3 -c "
|
||
import json
|
||
with open('/etc/shadowsocks-rust/config.json') as f:
|
||
c = json.load(f)
|
||
for i,s in enumerate(c['servers']):
|
||
print(f\" 节点{i+1}: {s['method']} | 端口 {s['server_port']}\")
|
||
" 2>/dev/null || cat /etc/shadowsocks-rust/config.json
|
||
echo ""
|
||
read -p "输入节点编号 (1/2): " node_num
|
||
read -p "输入新端口: " new_port
|
||
|
||
python3 -c "
|
||
import json,sys
|
||
with open('/etc/shadowsocks-rust/config.json') as f:
|
||
c = json.load(f)
|
||
idx = int('${node_num}') - 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)
|
||
print('端口已修改')
|
||
else:
|
||
print('无效节点编号')
|
||
sys.exit(1)
|
||
" 2>/dev/null
|
||
|
||
systemctl restart ss-rust
|
||
info "服务已重启,新端口: ${new_port}"
|
||
# 重新生成订阅
|
||
SERVER_IP=$(get_ip)
|
||
source_config
|
||
gen_subscribe
|
||
info "订阅配置已更新"
|
||
}
|
||
|
||
# ============ 读取现有配置 ============
|
||
source_config() {
|
||
if [[ -f /etc/shadowsocks-rust/config.json ]]; then
|
||
eval $(python3 -c "
|
||
import json
|
||
with open('/etc/shadowsocks-rust/config.json') as f:
|
||
c = json.load(f)
|
||
s = c['servers']
|
||
print(f'PORT_2022={s[0][\"server_port\"]}')
|
||
print(f'KEY_2022={s[0][\"password\"]}')
|
||
print(f'METHOD_2022={s[0][\"method\"]}')
|
||
print(f'PORT_RAW={s[1][\"server_port\"]}')
|
||
print(f'KEY_RAW={s[1][\"password\"]}')
|
||
print(f'METHOD_RAW={s[1][\"method\"]}')
|
||
" 2>/dev/null)
|
||
fi
|
||
}
|
||
|
||
# ============ 重置密钥 ============
|
||
reset_keys() {
|
||
if [[ ! -f /etc/shadowsocks-rust/config.json ]]; then
|
||
error "未安装 shadowsocks-rust"
|
||
fi
|
||
SERVER_IP=$(get_ip)
|
||
KEY_2022=$(gen_key_128)
|
||
KEY_RAW=$(openssl rand -base64 16)
|
||
|
||
python3 -c "
|
||
import json
|
||
with open('/etc/shadowsocks-rust/config.json') as f:
|
||
c = json.load(f)
|
||
c['servers'][0]['password'] = '${KEY_2022}'
|
||
c['servers'][1]['password'] = '${KEY_RAW}'
|
||
with open('/etc/shadowsocks-rust/config.json','w') as f:
|
||
json.dump(c, f, indent=4)
|
||
" 2>/dev/null
|
||
|
||
systemctl restart ss-rust
|
||
source_config
|
||
gen_subscribe
|
||
info "密钥已重置,服务已重启"
|
||
show_result
|
||
}
|
||
|
||
# ============ 交互菜单 ============
|
||
show_menu() {
|
||
echo ""
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
echo -e "${CYAN} 🚀 SS-Rust 管理面板${NC}"
|
||
echo -e "${CYAN}════════════════════════════════════════${NC}"
|
||
echo ""
|
||
echo -e " ${GREEN}1.${NC} 安装 SS-Rust"
|
||
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 " ${RED}9.${NC} 卸载"
|
||
echo -e " ${YELLOW}0.${NC} 退出"
|
||
echo ""
|
||
read -p "请选择 [0-9]: " choice
|
||
|
||
case "$choice" in
|
||
1)
|
||
check_os
|
||
sync_time
|
||
install_ssrust
|
||
gen_config
|
||
setup_service
|
||
gen_subscribe
|
||
show_result
|
||
;;
|
||
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 && info "服务已重启" ;;
|
||
8) journalctl -u ss-rust --no-pager -n 30 ;;
|
||
9) uninstall ;;
|
||
0) exit 0 ;;
|
||
*) warn "无效选择" ;;
|
||
esac
|
||
}
|
||
|
||
# ============ 主流程 ============
|
||
main() {
|
||
check_root
|
||
case "${1:-}" in
|
||
install)
|
||
check_os; sync_time; install_ssrust; gen_config; setup_service; gen_subscribe; show_result
|
||
;;
|
||
uninstall|remove)
|
||
uninstall
|
||
;;
|
||
show|config|info)
|
||
show_config
|
||
;;
|
||
restart)
|
||
systemctl restart ss-rust && info "服务已重启"
|
||
;;
|
||
start)
|
||
systemctl start ss-rust && info "服务已启动"
|
||
;;
|
||
stop)
|
||
systemctl stop ss-rust && info "服务已停止"
|
||
;;
|
||
log|logs)
|
||
journalctl -u ss-rust --no-pager -n 30
|
||
;;
|
||
reset)
|
||
reset_keys
|
||
;;
|
||
*)
|
||
# 无参数时:已安装显示菜单,未安装直接安装
|
||
if [[ -f /etc/shadowsocks-rust/config.json ]]; then
|
||
show_menu
|
||
else
|
||
check_os; sync_time; install_ssrust; gen_config; setup_service; gen_subscribe; show_result
|
||
fi
|
||
;;
|
||
esac
|
||
}
|
||
|
||
main "$@"
|