AC2100/vps_optimize.sh

446 lines
16 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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="n"
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:-n}"
[[ "$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