From 229797a7eb3c469665be36f90f0079ef87d78302 Mon Sep 17 00:00:00 2001 From: mike Date: Mon, 11 May 2026 00:21:10 +0800 Subject: [PATCH] Upload files to "/" --- vps_optimize.sh | 445 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 445 insertions(+) create mode 100644 vps_optimize.sh diff --git a/vps_optimize.sh b/vps_optimize.sh new file mode 100644 index 0000000..095b722 --- /dev/null +++ b/vps_optimize.sh @@ -0,0 +1,445 @@ +#!/bin/bash +# ============================================================ +# VPS 一键优化脚本 +# 适用: Debian 12 + VLESS + WS + TLS + Cloudflare CDN +# 功能: BBR / 内核参数 / 文件描述符 / Nginx / CF IP 白名单 +# ============================================================ + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +info() { echo -e "${CYAN}[INFO]${NC} $1"; } +success() { echo -e "${GREEN}[OK]${NC} $1"; } +warning() { echo -e "${YELLOW}[!]${NC} $1"; } +error() { echo -e "${RED}[ERR]${NC} $1"; exit 1; } +step() { + echo -e "\n${BOLD}${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${BOLD}${YELLOW} $1${NC}" + echo -e "${BOLD}${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +} + +RESULTS=() +add_result() { RESULTS+=("$1"); } + +check_root() { + [[ $EUID -eq 0 ]] || error "请使用 root 用户运行: sudo bash vps_optimize.sh" +} + +check_debian() { + [[ -f /etc/debian_version ]] || error "此脚本仅支持 Debian / Ubuntu 系统" + info "系统: $(lsb_release -d 2>/dev/null | cut -f2 || echo Debian)" + info "内核: $(uname -r)" +} + +print_banner() { + clear + echo -e "${CYAN}" + echo "╔══════════════════════════════════════════════════════╗" + echo "║ VPS 一键优化脚本 ║" + echo "║ VLESS + WS + TLS + Cloudflare CDN ║" + echo "╚══════════════════════════════════════════════════════╝" + echo -e "${NC}" +} + +# ── 默认值 ──────────────────────────────────────────────────── +NGINX_PORT="2053" +WS_PATH="/stickrouter" +DOMAIN="" +ENABLE_CF_WHITELIST="y" + +detect_and_collect() { + step "🔍 检测现有配置" + + local nginx_conf="" + if [[ -d /etc/nginx/sites-enabled ]]; then + nginx_conf=$(grep -rl "proxy_pass" /etc/nginx/sites-enabled/ 2>/dev/null | head -1 || true) + fi + + if [[ -n "$nginx_conf" ]]; then + local dp dd dpath + dp=$(grep -E 'listen\s+[0-9]+\s+ssl' "$nginx_conf" 2>/dev/null | grep -oE '[0-9]{2,5}' | head -1 || true) + dd=$(grep 'server_name' "$nginx_conf" 2>/dev/null | awk '{print $2}' | tr -d ';' | head -1 || true) + dpath=$(grep -E 'location\s+/' "$nginx_conf" 2>/dev/null | awk '{print $2}' | head -1 || true) + [[ -n "$dp" ]] && NGINX_PORT="$dp" + [[ -n "$dd" ]] && DOMAIN="$dd" + [[ -n "$dpath" ]] && WS_PATH="$dpath" + info "从 nginx 配置读取到:" + info " 端口: $NGINX_PORT 路径: $WS_PATH 域名: ${DOMAIN:-未检测到}" + else + if ! command -v nginx &>/dev/null; then + warning "nginx 尚未安装 —— Nginx 优化步骤将跳过" + warning "建议先运行 vless-ws-tls-setup.sh,部署完再跑本脚本" + warning "本次将完成: BBR / 内核参数 / 文件描述符 / 时间同步 / CF白名单" + else + warning "nginx 已安装但无反代配置,Nginx 优化将跳过" + fi + fi + + step "⚙️ 配置参数确认" + local input + + read -rp " Nginx 对外端口 [当前: ${NGINX_PORT},回车确认]: " input + [[ -n "$input" ]] && NGINX_PORT="$input" + + read -rp " WS 路径 [当前: ${WS_PATH},回车确认]: " input + [[ -n "$input" ]] && WS_PATH="$input" + + read -rp " 域名 [当前: ${DOMAIN:-空},回车确认]: " input + [[ -n "$input" ]] && DOMAIN="$input" + + read -rp " 开启 CF IP 白名单限制 ${NGINX_PORT} 端口? (Y/n): " input + input="${input:-y}" + [[ "$input" =~ ^[Nn]$ ]] && ENABLE_CF_WHITELIST="n" || ENABLE_CF_WHITELIST="y" + + echo "" + echo -e " ${BOLD}最终配置:${NC}" + echo -e " 端口: ${GREEN}${NGINX_PORT}${NC} 路径: ${GREEN}${WS_PATH}${NC} 域名: ${GREEN}${DOMAIN:-未填}${NC} CF白名单: ${GREEN}${ENABLE_CF_WHITELIST}${NC}" + echo "" + read -rp " 按 Enter 开始优化,输入 n 重新填写: " input + [[ "${input:-y}" =~ ^[Nn]$ ]] && detect_and_collect +} + +optimize_bbr() { + step "🚀 BBR 拥塞控制" + local current + current=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || echo "unknown") + info "当前拥塞算法: $current" + + modprobe tcp_bbr 2>/dev/null || true + + if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -q bbr; then + warning "内核不支持 BBR,跳过" + add_result "❌ BBR: 内核不支持" + return + fi + + cat > /etc/sysctl.d/99-bbr.conf << 'EOF' +net.core.default_qdisc = fq +net.ipv4.tcp_congestion_control = bbr +EOF + sysctl -p /etc/sysctl.d/99-bbr.conf >/dev/null 2>&1 || true + + local after + after=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || echo "unknown") + if [[ "$after" == "bbr" ]]; then + success "BBR 已启用 ✓" + add_result "✅ BBR: 已启用" + else + warning "BBR 配置已写入,重启后生效" + add_result "⚠️ BBR: 重启后生效" + fi +} + +optimize_sysctl() { + step "🔧 内核网络参数调优" + + cat > /etc/sysctl.d/99-vps-optimize.conf << 'EOF' +# 缓冲区(WebSocket 长连接) +net.core.rmem_max = 67108864 +net.core.wmem_max = 67108864 +net.ipv4.tcp_rmem = 4096 87380 67108864 +net.ipv4.tcp_wmem = 4096 65536 67108864 +net.core.netdev_max_backlog = 250000 +# 连接队列 +net.core.somaxconn = 32768 +net.ipv4.tcp_max_syn_backlog = 16384 +# TIME_WAIT +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_fin_timeout = 15 +net.ipv4.tcp_max_tw_buckets = 5000 +# WebSocket 保活 +net.ipv4.tcp_keepalive_time = 300 +net.ipv4.tcp_keepalive_intvl = 30 +net.ipv4.tcp_keepalive_probes = 3 +# 其他 +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_mtu_probing = 1 +net.ipv4.ip_local_port_range = 10000 65535 +EOF + sysctl -p /etc/sysctl.d/99-vps-optimize.conf >/dev/null 2>&1 && \ + success "内核参数写入完成" || warning "部分参数应用失败" + add_result "✅ 内核参数: 已优化" +} + +optimize_nofile() { + step "📁 文件描述符" + + cat > /etc/security/limits.d/99-nofile.conf << 'EOF' +* soft nofile 65535 +* hard nofile 65535 +root soft nofile 65535 +root hard nofile 65535 +EOF + success "limits.d 写入完成" + + for svc in sing-box nginx xray; do + if systemctl list-unit-files 2>/dev/null | grep -q "^${svc}.service"; then + local d="/etc/systemd/system/${svc}.service.d" + mkdir -p "$d" + printf '[Service]\nLimitNOFILE=65535\n' > "${d}/limits.conf" + success "systemd override: ${svc}" + fi + done + + systemctl daemon-reload 2>/dev/null || true + ulimit -n 65535 2>/dev/null || true + add_result "✅ 文件描述符: 65535" +} + +optimize_nginx() { + step "🌐 Nginx 配置优化" + + if ! command -v nginx &>/dev/null; then + warning "nginx 未安装,跳过" + add_result "⏭️ Nginx: 未安装,已跳过" + return + fi + + local nginx_conf + nginx_conf=$(grep -rl "proxy_pass" /etc/nginx/sites-available/ 2>/dev/null | head -1 || true) + + if [[ -z "$nginx_conf" ]]; then + warning "未找到反代站点配置,跳过" + add_result "⏭️ Nginx: 无反代配置,已跳过" + return + fi + + info "目标配置: $nginx_conf" + local backup="${nginx_conf}.bak.$(date +%Y%m%d%H%M%S)" + cp "$nginx_conf" "$backup" + info "已备份: $backup" + + sed -i 's/worker_processes\s\+[0-9]\+/worker_processes auto/' /etc/nginx/nginx.conf 2>/dev/null || true + sed -i '/events\s*{/,/}/{s/worker_connections\s\+[0-9]\+/worker_connections 65535/}' /etc/nginx/nginx.conf 2>/dev/null || true + + + # Python 精确修改站点配置 + python3 - "$nginx_conf" "$WS_PATH" << 'PYEOF' +import sys, re +conf_path, ws_path = sys.argv[1], sys.argv[2] +with open(conf_path) as f: + content = f.read() + +content = re.sub(r'ssl_protocols\s+[^;]+;', 'ssl_protocols TLSv1.2 TLSv1.3;', content) +content = re.sub(r'ssl_ciphers\s+[^;]+;', + 'ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;', content) +content = re.sub(r'ssl_prefer_server_ciphers\s+\w+;', 'ssl_prefer_server_ciphers off;', content) +for pat, rep in [ + (r'ssl_session_cache\s+[^;]+;', 'ssl_session_cache shared:SSL:20m;'), + (r'ssl_session_timeout\s+[^;]+;', 'ssl_session_timeout 1d;'), +]: + content = re.sub(pat, rep, content) +if 'ssl_session_tickets' not in content: + content = re.sub(r'(ssl_session_timeout\s+[^;]+;)', + r'\1\n ssl_session_tickets off;\n ssl_buffer_size 4k;', content) + +def patch_ws(m): + b = m.group(0) + for pat, rep in [ + (r'proxy_read_timeout\s+[^;]+;', 'proxy_read_timeout 600s;'), + (r'proxy_send_timeout\s+[^;]+;', 'proxy_send_timeout 600s;'), + (r'proxy_connect_timeout\s+[^;]+;', 'proxy_connect_timeout 10s;'), + ]: + b = re.sub(pat, rep, b) if re.search(pat, b) else \ + b.replace('proxy_buffering off;', 'proxy_buffering off;\n ' + rep) + if 'tcp_nodelay' not in b: + b = b.replace('proxy_buffering off;', 'proxy_buffering off;\n tcp_nodelay on;') + return b + +content = re.sub(r'location\s+' + re.escape(ws_path) + r'\s*\{[^}]+\}', + patch_ws, content, flags=re.DOTALL) +with open(conf_path, 'w') as f: + f.write(content) +print(" 站点配置更新完成") +PYEOF + + if nginx -t 2>/dev/null; then + systemctl reload nginx + success "Nginx 优化完成并重载" + add_result "✅ Nginx: 已优化并重载" + else + warning "配置测试失败,正在回滚..." + cp "$backup" "$nginx_conf" + systemctl reload nginx 2>/dev/null || true + add_result "❌ Nginx: 优化失败已回滚" + fi +} + +optimize_proxy_service() { + step "⚡ 代理服务重启" + local found=0 + for svc in sing-box xray; do + if systemctl is-active --quiet "$svc" 2>/dev/null; then + systemctl restart "$svc" && \ + success "$svc 重启完成(fd override 已生效)" && \ + add_result "✅ ${svc}: 已重启" + found=1 + fi + done + [[ $found -eq 0 ]] && warning "未检测到运行中的 sing-box / xray(部署后自动生效)" +} + +setup_cf_whitelist() { + step "🛡️ Cloudflare IP 白名单" + + if [[ "$ENABLE_CF_WHITELIST" != "y" ]]; then + info "已跳过" + add_result "⏭️ CF 白名单: 已跳过" + return + fi + + command -v ufw &>/dev/null || apt-get install -y -qq ufw + + ufw allow 22/tcp comment 'SSH' >/dev/null 2>&1 || true + ufw allow 80/tcp comment 'HTTP' >/dev/null 2>&1 || true + + info "拉取 Cloudflare IP 段..." + local cf_v4 cf_v6 + cf_v4=$(curl -sf --max-time 15 https://www.cloudflare.com/ips-v4/ 2>/dev/null || true) + cf_v6=$(curl -sf --max-time 15 https://www.cloudflare.com/ips-v6/ 2>/dev/null || true) + + if [[ -z "$cf_v4" ]]; then + warning "拉取失败,使用内置 IP 段" + cf_v4="173.245.48.0/20 +103.21.244.0/22 +103.22.200.0/22 +103.31.4.0/22 +141.101.64.0/18 +108.162.192.0/18 +190.93.240.0/20 +188.114.96.0/20 +197.234.240.0/22 +198.41.128.0/17 +162.158.0.0/15 +104.16.0.0/13 +104.24.0.0/14 +172.64.0.0/13 +131.0.72.0/22" + fi + + # 删除旧 CF 规则(逆序删除避免编号偏移) + mapfile -t old_nums < <(ufw status numbered 2>/dev/null | grep 'CF' | grep -oE '^\s*\[[0-9]+\]' | tr -d '[] ' | sort -rn || true) + for n in "${old_nums[@]}"; do + [[ -n "$n" ]] && ufw --force delete "$n" >/dev/null 2>&1 || true + done + + # 先添加 CF ALLOW(顺序必须在 DENY 之前) + local count=0 + while IFS= read -r ip; do + [[ -z "$ip" ]] && continue + ufw allow from "$ip" to any port "$NGINX_PORT" proto tcp comment 'CF' >/dev/null 2>&1 && (( count++ )) || true + done <<< "$cf_v4" + while IFS= read -r ip; do + [[ -z "$ip" ]] && continue + ufw allow from "$ip" to any port "$NGINX_PORT" proto tcp comment 'CF' >/dev/null 2>&1 && (( count++ )) || true + done <<< "$cf_v6" + + # 最后添加 DENY 兜底(排在所有 CF ALLOW 之后) + ufw deny "${NGINX_PORT}/tcp" comment 'deny-direct' >/dev/null 2>&1 || true + + if ufw status 2>/dev/null | grep -q "Status: active"; then + ufw reload >/dev/null 2>&1 || true + else + ufw --force enable >/dev/null 2>&1 || true + fi + + success "已添加 ${count} 条 CF 规则,端口 ${NGINX_PORT} 仅允许 CF 回源" + add_result "✅ CF 白名单: ${count} 条规则,端口 ${NGINX_PORT} 已锁定" + + # 自动更新脚本 + cat > /usr/local/bin/update-cf-whitelist.sh << CFEOF +#!/bin/bash +PORT="${NGINX_PORT}" +cf_v4=\$(curl -sf --max-time 15 https://www.cloudflare.com/ips-v4/ 2>/dev/null) +cf_v6=\$(curl -sf --max-time 15 https://www.cloudflare.com/ips-v6/ 2>/dev/null) +[[ -z "\$cf_v4" ]] && echo "拉取失败" && exit 1 +mapfile -t old_nums < <(ufw status numbered 2>/dev/null | grep 'CF' | grep -oE '^\s*\[[0-9]+\]' | tr -d '[] ' | sort -rn) +for n in "\${old_nums[@]}"; do [[ -n "\$n" ]] && ufw --force delete "\$n" >/dev/null 2>&1 || true; done +for ip in \$cf_v4 \$cf_v6; do + [[ -n "\$ip" ]] && ufw allow from "\$ip" to any port "\$PORT" proto tcp comment 'CF' >/dev/null 2>&1 || true +done +ufw reload >/dev/null 2>&1 +echo "\$(date '+%Y-%m-%d %H:%M:%S') CF 白名单已更新" +CFEOF + chmod +x /usr/local/bin/update-cf-whitelist.sh + echo "0 4 1 * * root /usr/local/bin/update-cf-whitelist.sh >> /var/log/cf-whitelist.log 2>&1" \ + > /etc/cron.d/update-cf-whitelist + success "自动更新任务已配置(每月1号凌晨4点)" +} + +optimize_time() { + step "🕐 时间同步" + if systemctl is-active --quiet systemd-timesyncd 2>/dev/null; then + timedatectl set-ntp true 2>/dev/null || true + success "systemd-timesyncd 运行中" + add_result "✅ 时间同步: 正常" + elif command -v ntpd &>/dev/null; then + success "ntpd 运行中" + add_result "✅ 时间同步: ntpd" + else + apt-get install -y -qq systemd-timesyncd 2>/dev/null || true + timedatectl set-ntp true 2>/dev/null || true + success "systemd-timesyncd 已安装" + add_result "✅ 时间同步: 已安装" + fi + info "当前时间: $(date '+%Y-%m-%d %H:%M:%S %Z')" +} + +print_report() { + step "📋 优化完成报告" + echo "" + for r in "${RESULTS[@]}"; do echo -e " $r"; done + + echo "" + echo -e " ${BOLD}服务状态:${NC}" + for svc in nginx sing-box xray; do + if systemctl list-unit-files 2>/dev/null | grep -q "^${svc}.service"; then + if systemctl is-active --quiet "$svc" 2>/dev/null; then + echo -e " ${GREEN}✔${NC} ${svc} 运行中" + else + echo -e " ${RED}✘${NC} ${svc} 未运行" + fi + fi + done + + echo "" + echo -e " ${BOLD}内核验证:${NC}" + echo -e " 拥塞算法 : ${GREEN}$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null)${NC}" + echo -e " 队列算法 : ${GREEN}$(sysctl -n net.core.default_qdisc 2>/dev/null)${NC}" + echo -e " 文件描述符: ${GREEN}$(ulimit -n)${NC}" + + if [[ "$ENABLE_CF_WHITELIST" == "y" ]]; then + echo "" + echo -e " ${BOLD}防火墙 (端口 ${NGINX_PORT}):${NC}" + ufw status 2>/dev/null | grep -E "Status:|${NGINX_PORT}" | sed 's/^/ /' || true + fi + + echo "" + echo -e " ${CYAN}Nginx 备份: /etc/nginx/sites-available/*.bak.*${NC}" + echo -e " ${CYAN}CF IP 手动更新: bash /usr/local/bin/update-cf-whitelist.sh${NC}" + echo "" + echo -e " ${YELLOW}${BOLD}建议执行 reboot 使全部内核参数生效${NC}" + echo "" +} + +main() { + check_root + print_banner + check_debian + detect_and_collect + optimize_bbr + optimize_sysctl + optimize_nofile + optimize_nginx + optimize_proxy_service + setup_cf_whitelist + optimize_time + print_report +} + +main