空色天絵 / NEO TOKYO NOIR 01
5770 字
29 分钟
新服务器可能需要进行的一些配置
服务器配置
1. 配置 Fail2ban 和 TuneTCP
402 collapsed lines
#!/bin/bash# ========================================# Fail2Ban SSH 防护一键管理脚本# 作者: hua hua# 功能:# 1. 安装并配置 Fail2Ban(封禁一年累加)# 2. 查看当前 SSH 防护状态# 3. 查看 Fail2Ban 日志尾部# 4. 重启 Fail2Ban 服务# 5. 今日攻击统计# 6. 历史累计攻击统计# 7. 查看详细封禁列表# 8. 退出脚本# ========================================
set -e
# --- 配置 ---JAIL_NAME="sshd"JAIL_LOCAL="/etc/fail2ban/jail.local"# 主日志文件LOG_FILE="/var/log/fail2ban.log"# 历史日志文件(支持压缩归档)LOG_FILES="/var/log/fail2ban.log*"
# --- 检查环境 ---if [[ $EUID -ne 0 ]]; then echo "错误: 此脚本必须以 root 权限运行。" exit 1fi
# --- 核心工具函数 ---
# 检测系统类型并设置 SSH 日志路径detect_system() { if [ -f /etc/debian_version ]; then OS_FAMILY="debian" LOG_PATH="/var/log/auth.log" elif [ -f /etc/redhat-release ] || [ -f /etc/centos-release ] || \ [ -f /etc/almalinux-release ] || [ -f /etc/rocky-release ] || \ [ -f /etc/fedora-release ] || [ -f /etc/amazon-linux-release ]; then OS_FAMILY="rhel" LOG_PATH="/var/log/secure" else OS_FAMILY="unknown" LOG_PATH="/var/log/auth.log" echo "[WARN] 未识别系统类型,默认使用 ${LOG_PATH}" fi}
# 将秒数转换为易读的格式 (天/小时/分钟)seconds_to_readable() { local seconds=$1 if [ "$seconds" -le 0 ]; then echo "即将解封" return fi local days=$((seconds / 86400)) local hours=$(((seconds % 86400) / 3600)) local mins=$(((seconds % 3600) / 60)) echo "${days}天${hours}小时${mins}分钟"}
# [已升级] 获取 IP 封禁剩余时间,精确处理累进封禁get_ip_remaining() { local ip=$1 local now_ts=$(date +%s)
local log_entry=$(grep " Ban $ip" "$LOG_FILE" 2>/dev/null | grep -v "Restore" | tail -1) if [ -z "$log_entry" ]; then echo "未知 (无法从日志找到封禁记录)" return fi
local ban_datetime=$(echo "$log_entry" | awk '{print $1" "$2}' | cut -d',' -f1) local ban_ts=$(date -d "$ban_datetime" +%s 2>/dev/null) if ! [[ "$ban_ts" =~ ^[0-9]+$ ]]; then echo "未知 (日期解析失败)" return fi
local base_bantime=31536000 local increment="false" local factor=2
if [ -f "$JAIL_LOCAL" ]; then local config_bantime=$(grep -E "^\s*bantime\s*=" "$JAIL_LOCAL" | awk '{print $3}' | tail -n 1) if [[ "$config_bantime" =~ ^-?[0-9]+$ ]]; then base_bantime=$config_bantime fi local config_increment=$(grep -E "^\s*bantime.increment\s*=" "$JAIL_LOCAL" | awk '{print $3}' | tail -n 1) if [[ "$config_increment" == "true" ]]; then increment="true" fi local config_factor=$(grep -E "^\s*bantime.factor\s*=" "$JAIL_LOCAL" | awk '{print $3}' | tail -n 1) if [[ "$config_factor" =~ ^[0-9]+$ ]]; then factor=$config_factor fi fi
if [ "$base_bantime" = "-1" ]; then echo "永久封禁" return fi
local final_bantime=$base_bantime if [ "$increment" == "true" ]; then local ban_count=$(grep " Ban $ip" "$LOG_FILE" 2>/dev/null | grep -v "Restore" | wc -l) if [ "$ban_count" -gt 1 ]; then for ((i=1; i<ban_count; i++)); do final_bantime=$((final_bantime * factor)) done fi fi
local unban_ts=$((ban_ts + final_bantime)) local remaining_seconds=$((unban_ts - now_ts)) local readable_remaining=$(seconds_to_readable $remaining_seconds) local unban_date=$(date -d @"$unban_ts" "+%Y-%m-%d %H:%M:%S")
echo "$ip → 剩余: $readable_remaining (解封: $unban_date)"}
# --- 菜单功能函数 ---
# 1. 安装并配置 Fail2Baninstall_fail2ban() { detect_system echo "==============================" echo "[INFO] 开始安装 Fail2Ban..." echo "=============================="
if [ "$OS_FAMILY" = "debian" ]; then apt-get update -y && apt-get install -y fail2ban elif [ "$OS_FAMILY" = "rhel" ]; then yum install -y epel-release && yum install -y fail2ban else echo "[ERROR] 未知系统类型,请手动安装 Fail2Ban" exit 1 fi
if [ -f "$JAIL_LOCAL" ]; then cp "$JAIL_LOCAL" "${JAIL_LOCAL}.bak_$(date +%F_%T)" echo "[INFO] 旧配置已备份至 ${JAIL_LOCAL}.bak_..." fi
echo "[INFO] 写入新配置文件..." cat > "$JAIL_LOCAL" <<EOF[sshd]enabled = trueignoreip = 127.0.0.1/8filter = sshdport = sshmaxretry = 6findtime = 300bantime = 31536000bantime.increment = truebantime.factor = 2bantime.rndtime = 300bantime.overalljails = trueaction = %(action_)sbanaction = iptables-multiportlogpath = ${LOG_PATH}EOF
echo "[INFO] 启动并设置 Fail2Ban 开机自启..." systemctl enable fail2ban systemctl restart fail2ban sleep 2 echo "==============================" echo "安装完成!当前状态:" fail2ban-client status "$JAIL_NAME" || echo "[WARN] Fail2Ban 未能成功启动,请检查配置。" echo "=============================="}
# 2. 查看当前 SSH 防护状态view_status() { echo "==============================" echo "[INFO] 当前 SSH 防护状态:" echo "==============================" fail2ban-client status "$JAIL_NAME" 2>/dev/null || echo "[WARN] Fail2Ban 服务未运行或 '$JAIL_NAME' 监狱不存在。"}
# 3. 查看 Fail2Ban 日志尾部view_logs() { echo "==============================" echo "[INFO] 最近 50 行 Fail2Ban 日志:" echo "==============================" if [ -f "$LOG_FILE" ]; then tail -n 50 "$LOG_FILE" else echo "[WARN] 日志文件不存在: $LOG_FILE" fi}
# 4. 重启 Fail2Ban 服务restart_service() { echo "[INFO] 正在重启 Fail2Ban 服务..." systemctl restart fail2ban sleep 2 systemctl status fail2ban --no-pager -l | grep "Active:"}
# 5. 今日攻击统计attack_stats_today() { echo "==============================" echo "[INFO] 今日攻击统计 (基于 Fail2Ban 日志)" echo "=============================="
if [ ! -f "$LOG_FILE" ]; then echo "[WARN] 日志文件不存在:$LOG_FILE" return fi
# 获取今日日期,格式:YYYY-MM-DD local TODAY=$(date +"%Y-%m-%d")
# 统计今日 Found 次数 local FAIL_COUNT=$(grep "$TODAY" "$LOG_FILE" | grep "Found" | wc -l) echo "今日尝试失败次数: ${FAIL_COUNT}" echo "" echo "今日失败 IP 排行 (Top 10):" grep "$TODAY" "$LOG_FILE" | grep "Found" \ | awk '{for(i=1;i<=NF;i++){if($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/){print $i}}}' \ | sort | uniq -c | sort -nr | head -n 10 \ | awk '{printf " %-15s %s 次\n", $2, $1}'}
# 6. 历史累计攻击统计attack_stats_total() { echo "==============================" echo "[INFO] 历史累计攻击统计 (基于 Fail2Ban 日志)" echo "=============================="
# 使用 LOG_FILES 支持压缩归档日志 local TOTAL_COUNT=$(zgrep "Found" $LOG_FILES 2>/dev/null | wc -l) echo "历史尝试失败总次数: ${TOTAL_COUNT}" echo "" echo "历史失败 IP 排行 (Top 10):" zgrep "Found" $LOG_FILES 2>/dev/null \ | awk '{for(i=1;i<=NF;i++){if($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/){print $i}}}' \ | sort | uniq -c | sort -nr | head -n 10 \ | awk '{printf " %-15s %s 次\n", $2, $1}'}
# 辅助函数:读取所有日志文件(包括压缩文件)_read_all_logs() { for logfile in $LOG_FILES; do if [ -f "$logfile" ]; then if [[ "$logfile" =~ \.(gz|bz2|xz)$ ]]; then zcat "$logfile" 2>/dev/null else cat "$logfile" 2>/dev/null fi fi done}
# 7. 查看详细封禁列表view_detailed_ban_list() { echo "==============================" echo "[INFO] 详细封禁列表" echo "==============================" echo "正在分析日志,请稍候..."
mapfile -t banned_ips < <( fail2ban-client status "$JAIL_NAME" 2>/dev/null \ | grep "Banned IP list:" \ | sed 's/.*Banned IP list:[[:space:]]*//' \ | tr ' ' '\n' \ | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' \ | sort -u )
if [ ${#banned_ips[@]} -eq 0 ]; then echo "当前没有被封禁的IP。" return fi
declare -a ip_info_list for ip in "${banned_ips[@]}"; do # 获取用于排序的信息: unban_ts|ban_ts|formatted_output local info_line=$(_get_ip_sortable_info "$ip") if [ -n "$info_line" ]; then ip_info_list+=("$info_line") fi done
echo "" echo "--- 即将解封的IP (Top 10) ---" IFS=$'\n' local sorted_by_unban=($(sort -t'|' -k1,1n <<<"${ip_info_list[*]}")) unset IFS if [ ${#sorted_by_unban[@]} -eq 0 ]; then echo "无" else for ((i=0; i<${#sorted_by_unban[@]} && i<10; i++)); do echo "${sorted_by_unban[i]}" | cut -d'|' -f3 done fi
echo "" echo "--- 最近被封禁的IP (Last 10) ---" IFS=$'\n' local sorted_by_ban=($(sort -t'|' -k2,2nr <<<"${ip_info_list[*]}")) unset IFS if [ ${#sorted_by_ban[@]} -eq 0 ]; then echo "无" else for ((i=0; i<${#sorted_by_ban[@]} && i<10; i++)); do echo "${sorted_by_ban[i]}" | cut -d'|' -f3 done fi}
# 详细列表功能的辅助函数,返回带时间戳的信息用于排序_get_ip_sortable_info() { local ip=$1 local now_ts=$(date +%s)
# 从所有日志文件中搜索最后一条Ban记录 local log_entry=$(_read_all_logs | grep " Ban $ip" | grep -v "Restore" | tail -1) [ -z "$log_entry" ] && return
local ban_datetime=$(echo "$log_entry" | awk '{print $1" "$2}' | cut -d',' -f1) local ban_ts=$(date -d "$ban_datetime" +%s 2>/dev/null) ! [[ "$ban_ts" =~ ^[0-9]+$ ]] && return
local base_bantime=31536000 local increment="false" local factor=2
if [ -f "$JAIL_LOCAL" ]; then local config_bantime=$(grep -E "^\s*bantime\s*=" "$JAIL_LOCAL" | awk '{print $3}' | tail -n 1) [[ "$config_bantime" =~ ^-?[0-9]+$ ]] && base_bantime=$config_bantime local config_increment=$(grep -E "^\s*bantime.increment\s*=" "$JAIL_LOCAL" | awk '{print $3}' | tail -n 1) [[ "$config_increment" == "true" ]] && increment="true" local config_factor=$(grep -E "^\s*bantime.factor\s*=" "$JAIL_LOCAL" | awk '{print $3}' | tail -n 1) [[ "$config_factor" =~ ^[0-9]+$ ]] && factor=$config_factor fi
if [ "$base_bantime" = "-1" ]; then echo "9999999999|$ban_ts|$ip → 剩余: 永久封禁" return fi
local final_bantime=$base_bantime if [ "$increment" == "true" ]; then # 从所有日志文件中统计Ban次数 local ban_count=$(_read_all_logs | grep " Ban $ip" | grep -v "Restore" | wc -l) if [ "$ban_count" -gt 1 ]; then for ((i=1; i<ban_count; i++)); do final_bantime=$((final_bantime * factor)) done fi fi
local unban_ts=$((ban_ts + final_bantime)) local remaining_seconds=$((unban_ts - now_ts)) local readable_remaining=$(seconds_to_readable $remaining_seconds) local unban_date=$(date -d @"$unban_ts" "+%Y-%m-%d %H:%M:%S") local formatted_output="$ip → 剩余: $readable_remaining (解封: $unban_date)" echo "$unban_ts|$ban_ts|$formatted_output"}
# --- 主菜单 ---show_menu() { clear echo "=============================================" echo " Fail2Ban SSH 防护一键管理脚本 (v2.0)" echo "=============================================" echo " 1. 安装并配置 Fail2Ban" echo " 2. 查看 SSH 防护状态" echo " 3. 查看 Fail2Ban 日志尾部" echo " 4. 重启 Fail2Ban 服务" echo " 5. 今日攻击统计" echo " 6. 历史累计攻击统计" echo " 7. 查看详细封禁列表" echo " 8. 退出脚本" echo "---------------------------------------------" read -p "请输入选项 [1-8]: " choice
case "$choice" in 1) install_fail2ban ;; 2) view_status ;; 3) view_logs ;; 4) restart_service ;; 5) attack_stats_today ;; 6) attack_stats_total ;; 7) view_detailed_ban_list ;; 8) echo "退出脚本。"; exit 0 ;; *) echo "无效选项,请输入 1-8 之间的数字。"; sleep 1 ;; esac
echo "" read -p "按 Enter 键返回主菜单..." show_menu}
# --- 脚本入口 ---show_menu616 collapsed lines
#!/bin/bashset -euo pipefail
# =========================================================# TuneTCP - TCP参数优化工具# 作者: Yuju# 功能: 自动检测并优化TCP参数,启用BBR拥塞控制# =========================================================
# 颜色定义readonly RED='\033[1;31m'readonly GREEN='\033[1;32m'readonly YELLOW='\033[1;33m'readonly BLUE='\033[1;34m'readonly PURPLE='\033[1;35m'readonly CYAN='\033[1;36m'readonly WHITE='\033[1;37m'readonly RESET='\033[0m'
# 日志目录readonly LOG_FILE="/var/log/tunetcp.log"
# 输出函数log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $*" >> "$LOG_FILE"; }info() { echo -e "${BLUE}[INFO]${RESET} $*" >&2; log "INFO: $*"; }success() { echo -e "${GREEN}[SUCCESS]${RESET} $*" >&2; log "SUCCESS: $*"; }warning() { echo -e "${YELLOW}[WARNING]${RESET} $*" >&2; log "WARNING: $*"; }error() { echo -e "${RED}[ERROR]${RESET} $*" >&2; log "ERROR: $*"; exit 1; }
# 检查root权限check_root() { [[ $EUID -eq 0 ]] || error "请以root权限运行此脚本"}
# 检测操作系统类型check_os() { if [[ -f /etc/os-release ]]; then . /etc/os-release echo "${ID:-unknown}" elif command -v lsb_release >/dev/null 2>&1; then lsb_release -si | tr '[:upper:]' '[:lower:]' else echo "unknown" fi}
# 检查内核版本check_kernel_version() { local kernel_version kernel_version=$(uname -r | cut -d. -f1-2) local major minor major=$(echo "$kernel_version" | cut -d. -f1) minor=$(echo "$kernel_version" | cut -d. -f2)
if [[ $major -lt 4 ]] || [[ $major -eq 4 && $minor -lt 9 ]]; then warning "内核版本 ${kernel_version} 可能不完全支持BBR,建议升级到4.9+" return 1 fi success "内核版本 ${kernel_version} 支持BBR" return 0}
# 创建备份目录create_backup_dir() { local timestamp=$(date +%Y%m%d-%H%M%S) local backup_base="/etc/tunetcp-backup" local backup_dir="$backup_base/$timestamp"
# 创建基础目录 mkdir -p "$backup_base"
# 返回备份路径,但暂不创建具体目录 echo "$backup_dir"}# 添加实际创建备份目录的函数ensure_backup_dir() { local backup_dir="$1" if [[ ! -d "$backup_dir" ]]; then mkdir -p "$backup_dir" info "创建备份目录: $backup_dir" fi}# 内存检测check_mem() { local mem_bytes if [[ -r /proc/meminfo ]]; then mem_bytes=$(awk '/^MemTotal:/ {print $2 * 1024}' /proc/meminfo) elif command -v free >/dev/null 2>&1; then mem_bytes=$(free -b | awk 'NR==2 {print $2}') elif [[ -r /proc/meminfo ]]; then mem_bytes=$(grep '^MemTotal:' /proc/meminfo | awk '{print $2 * 1024}') else error "无法获取内存信息:系统不支持" return 1 fi if [[ ! "$mem_bytes" =~ ^[0-9]+$ ]] || (( mem_bytes < 134217728 )); then # 最小128MB error "获取的内存信息无效: ${mem_bytes:-"空值"} bytes" return 1 fi printf "%.2f" $((mem_bytes * 100 / 1073741824))e-2}
rtt_test() { local ping_target="" local ping_desc="" local -a dns_servers=("1.1.1.1" "8.8.8.8" "223.5.5.5" "114.114.114.114") local timeout_duration=5 local ping_count=3 local default_rtt=50 validate_ip() { local ip="$1" if [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then local IFS='.' local -a ip_parts=($ip) for part in "${ip_parts[@]}"; do [[ $part -le 255 ]] || return 1 done return 0 fi return 1 } ping_target_host() { local target="$1" local desc="$2"
info "正在测试到 ${desc} 的延迟..." local ping_output if ping_output=$(timeout "$timeout_duration" ping -c "$ping_count" -W 2 -i 0.5 "$target" 2>/dev/null); then local rtt if command -v bc >/dev/null 2>&1; then rtt=$(echo "$ping_output" | awk -F'[=/]' '/rtt|round-trip/ {print $5}' | head -1) else rtt=$(echo "$ping_output" | awk -F'[=/]' '/rtt|round-trip/ {printf "%.0f", $5}' | head -1) fi
if [[ "$rtt" =~ ^[0-9]+(\.[0-9]+)?$ ]] && (( $(echo "$rtt > 0" | bc -l 2>/dev/null || echo "1") )); then success "检测到平均RTT: ${rtt} ms" printf "%.0f" "$rtt" return 0 fi fi
warning "Ping ${target} 失败或结果无效" return 1 } test_multiple_targets() { local -a targets=("$@") local rtt_sum=0 local valid_tests=0 local -a results=() info "使用多个DNS服务器测试网络延迟..."
for target in "${targets[@]}"; do local rtt if rtt=$(timeout "$timeout_duration" ping -c "$ping_count" -W 2 -i 0.5 "$target" 2>/dev/null | \ awk -F'[=/]' '/rtt|round-trip/ {printf "%.1f", $5; exit}'); then
if [[ "$rtt" =~ ^[0-9]+(\.[0-9]+)?$ ]] && (( $(echo "$rtt > 0" | bc -l 2>/dev/null || echo "1") )); then if command -v bc >/dev/null 2>&1; then rtt_sum=$(echo "$rtt_sum + $rtt" | bc -l) else rtt_sum=$(awk -v sum="$rtt_sum" -v rtt="$rtt" 'BEGIN {print sum + rtt}') fi ((valid_tests++)) results+=("DNS ${target}: ${rtt} ms") info "DNS ${target}: ${rtt} ms" else warning "DNS ${target} 测试结果解析失败" fi else warning "DNS ${target} 连接超时或失败" fi done
if [[ $valid_tests -gt 0 ]]; then local avg_rtt if command -v bc >/dev/null 2>&1; then avg_rtt=$(echo "scale=0; $rtt_sum / $valid_tests" | bc -l) else avg_rtt=$(awk -v sum="$rtt_sum" -v count="$valid_tests" 'BEGIN {printf "%.0f", sum / count}') fi
success "平均RTT (${valid_tests}个有效测试): ${avg_rtt} ms" echo "$avg_rtt" return 0 fi
return 1 } if [[ -n "${SSH_CONNECTION:-}" ]]; then ping_target=$(echo "$SSH_CONNECTION" | awk '{print $1}') if validate_ip "$ping_target"; then ping_desc="SSH 客户端 ${ping_target}" info "检测到SSH连接,客户端IP: ${ping_target}" else warning "SSH连接IP格式无效: $ping_target" ping_target="" fi fi if [[ -z "$ping_target" ]]; then info "未检测到有效SSH连接,请提供测试目标" local client_ip read -r -p "请输入客户机IP (回车使用多个公共DNS测试): " client_ip
if [[ -n "$client_ip" ]]; then if validate_ip "$client_ip"; then ping_target="$client_ip" ping_desc="客户机IP ${ping_target}" else warning "输入的IP地址格式无效: $client_ip" ping_target="" fi fi fi if [[ -n "$ping_target" ]]; then if ping_target_host "$ping_target" "$ping_desc"; then return 0 fi warning "目标 ${ping_target} 测试失败,转为使用DNS服务器测试" fi if test_multiple_targets "${dns_servers[@]}"; then return 0 fi warning "所有网络测试失败,使用默认值 ${default_rtt}ms" echo "$default_rtt" return 1}
# 智能带宽检测detect_bandwidth() { local bandwidth=1000 # 默认带宽值 (Mbps) local default_iface default_iface=$(ip -o -4 route show to default 2>/dev/null | awk '{print $5}' | head -1)
if [[ -n "$default_iface" && -r "/sys/class/net/$default_iface/speed" ]]; then local speed speed=$(cat "/sys/class/net/$default_iface/speed" 2>/dev/null)
if [[ "$speed" =~ ^[0-9]+$ && $speed -gt 0 && $speed -ne 4294967295 ]]; then bandwidth=$speed info "检测到网卡 ${default_iface} 速度: ${speed} Mbps" else info "网卡 ${default_iface} 速度检测失败 (值: ${speed:-未知}),使用默认值 ${bandwidth} Mbps" fi else info "无法读取网卡速度信息,使用默认值 ${bandwidth} Mbps" fi
echo "$bandwidth"}
# 验证参数有效性validate_params() { local mem_g="$1" local bw_mbps="$2" local rtt_ms="$3"
# 内存检查 (0.5GB - 1024GB) if ! awk -v m="$mem_g" 'BEGIN {exit (m >= 0.5 && m <= 1024) ? 0 : 1}'; then error "内存参数无效: ${mem_g} GiB (应在 0.5-1024 范围内)" fi
# 带宽检查 (1Mbps - 100Gbps) if ! awk -v b="$bw_mbps" 'BEGIN {exit (b >= 1 && b <= 100000) ? 0 : 1}'; then error "带宽参数无效: ${bw_mbps} Mbps (应在 1-100000 范围内)" fi
# RTT检查 (1ms - 1000ms) if ! awk -v r="$rtt_ms" 'BEGIN {exit (r >= 1 && r <= 1000) ? 0 : 1}'; then error "RTT参数无效: ${rtt_ms} ms (应在 1-1000 范围内)" fi}
# 高级缓冲区计算calculate_buffers() { local mem_g="$1" local bw_mbps="$2" local rtt_ms="$3"
# BDP计算: 带宽 * RTT local bdp_bytes bdp_bytes=$(awk -v bw="$bw_mbps" -v rtt="$rtt_ms" 'BEGIN{ printf "%.0f", bw * 125 * rtt }')
# 内存限制: 总内存的3% local mem_bytes ram_limit mem_bytes=$(awk -v g="$mem_g" 'BEGIN{ printf "%.0f", g * 1024^3 }') ram_limit=$(awk -v m="$mem_bytes" 'BEGIN{ printf "%.0f", m * 0.03 }')
# 系统限制: 64MB (避免过度消耗内存) local sys_limit=$((64 * 1024 * 1024))
# 最终缓冲区大小: min(2*BDP, 3%RAM, 64MB) local max_buffer max_buffer=$(awk -v bdp="$bdp_bytes" -v ram="$ram_limit" -v sys="$sys_limit" ' BEGIN { max_buf = bdp * 2 if (ram < max_buf) max_buf = ram if (sys < max_buf) max_buf = sys printf "%.0f", max_buf }')
# 缓冲区分档 (便于管理) local max_mb buffer_mb max_mb=$((max_buffer / 1024 / 1024))
if [[ $max_mb -ge 64 ]]; then buffer_mb=64 elif [[ $max_mb -ge 32 ]]; then buffer_mb=32 elif [[ $max_mb -ge 16 ]]; then buffer_mb=16 elif [[ $max_mb -ge 8 ]]; then buffer_mb=8 elif [[ $max_mb -ge 4 ]]; then buffer_mb=4 else buffer_mb=4 fi
local final_bytes=$((buffer_mb * 1024 * 1024))
# 返回计算结果 echo "$bdp_bytes $final_bytes $buffer_mb"}
# 优化的冲突处理handle_conflicts() { local backup_dir="$1" local key_regex='^[[:space:]]*net\.(core\.(default_qdisc|rmem_max|wmem_max|rmem_default|wmem_default)|ipv4\.tcp_(rmem|wmem|congestion_control))[[:space:]]*=' local backup_created=false
info "处理配置冲突..."
# 备份并处理 /etc/sysctl.conf if [[ -f "/etc/sysctl.conf" ]]; then if grep -Eq "$key_regex" "/etc/sysctl.conf"; then ensure_backup_dir "$backup_dir" backup_created=true cp "/etc/sysctl.conf" "$backup_dir/sysctl.conf.orig" info "已备份 /etc/sysctl.conf" # ... 其余处理逻辑保持不变 fi fi
# 处理 /etc/sysctl.d/ 中的其他文件 if [[ -d "/etc/sysctl.d" ]]; then local target_file="/etc/sysctl.d/yuju-net-bbr-fq.conf" for conf_file in /etc/sysctl.d/*.conf; do [[ -f "$conf_file" ]] || continue [[ "$(readlink -f "$conf_file" 2>/dev/null)" == "$(readlink -f "$target_file" 2>/dev/null)" ]] && continue
if grep -Eq "$key_regex" "$conf_file"; then if [[ "$backup_created" == false ]]; then ensure_backup_dir "$backup_dir" backup_created=true fi local basename_file=$(basename "$conf_file") cp "$conf_file" "$backup_dir/$basename_file" if mv "$conf_file" "$conf_file.disabled-by-tunetcp"; then info "已禁用冲突文件: $conf_file" else warning "无法禁用文件: $conf_file" fi fi done fi
# 如果没有实际备份,返回空字符串 if [[ "$backup_created" == false ]]; then echo "" else echo "$backup_dir" fi}
# 应用网络优化配置apply_optimization() { local buffer_bytes="$1" local buffer_mb="$2" local mem_g="$3" local bw_mbps="$4" local rtt_ms="$5" local bdp_bytes="$6"
local config_file="/etc/sysctl.d/yuju-net-bbr-fq.conf"
# 根据缓冲区大小设置默认值 local def_rmem def_wmem if [[ $buffer_mb -ge 32 ]]; then def_rmem=262144; def_wmem=524288 elif [[ $buffer_mb -ge 8 ]]; then def_rmem=131072; def_wmem=262144 else def_rmem=131072; def_wmem=131072 fi
# TCP缓冲区参数 local tcp_rmem_min=4096 tcp_rmem_def=87380 tcp_rmem_max=$buffer_bytes local tcp_wmem_min=4096 tcp_wmem_def=65536 tcp_wmem_max=$buffer_bytes
info "生成优化配置..."
# 生成配置文件 cat > "$config_file" <<EOF# TuneTCP Auto-generated Configuration# Generated: $(date)# Parameters: MEM=${mem_g}GiB, BW=${bw_mbps}Mbps, RTT=${rtt_ms}ms# BDP: ${bdp_bytes} bytes (~$(awk -v b="$bdp_bytes" 'BEGIN{ printf "%.2f", b/1024/1024 }') MB)# Buffer Size: ${buffer_mb} MB
# BBR拥塞控制net.core.default_qdisc = fqnet.ipv4.tcp_congestion_control = bbr
# 核心网络缓冲区net.core.rmem_default = ${def_rmem}net.core.wmem_default = ${def_wmem}net.core.rmem_max = ${buffer_bytes}net.core.wmem_max = ${buffer_bytes}
# TCP缓冲区配置net.ipv4.tcp_rmem = ${tcp_rmem_min} ${tcp_rmem_def} ${tcp_rmem_max}net.ipv4.tcp_wmem = ${tcp_wmem_min} ${tcp_wmem_def} ${tcp_wmem_max}
# TCP优化选项net.ipv4.tcp_mtu_probing = 1net.ipv4.tcp_fastopen = 3net.ipv4.tcp_slow_start_after_idle = 0net.ipv4.tcp_notsent_lowat = 16384
# 连接跟踪优化 (适用于高并发)net.netfilter.nf_conntrack_max = 1048576net.netfilter.nf_conntrack_tcp_timeout_established = 1200
# 其他网络优化net.core.netdev_max_backlog = 5000net.ipv4.tcp_max_syn_backlog = 8192net.core.somaxconn = 32768EOF
success "配置文件已生成: $config_file"
# 应用配置 info "应用sysctl配置..." if sysctl --system >/dev/null 2>&1; then success "sysctl配置应用成功" else error "sysctl配置应用失败" fi
# 配置网络接口队列 local default_iface default_iface=$(ip -o -4 route show to default 2>/dev/null | awk '{print $5}' | head -1)
if command -v tc >/dev/null 2>&1 && [[ -n "$default_iface" ]]; then info "配置接口 ${default_iface} 的队列调度..." if tc qdisc replace dev "$default_iface" root fq 2>/dev/null; then success "接口队列配置成功" else warning "接口队列配置失败 (可能需要重启生效)" fi fi}
# 显示优化结果show_results() { local mem_g="$1" local bw_mbps="$2" local rtt_ms="$3" local bdp_bytes="$4" local buffer_mb="$5"
local bdp_mb bdp_mb=$(awk -v b="$bdp_bytes" 'BEGIN{ printf "%.2f", b/1024/1024 }')
echo echo "==== [ TuneTCP 优化结果 ] ====" echo
# 参数摘要 echo -e "${GREEN}[+] 优化参数摘要${RESET}" printf " - %-15s : %s\n" "内存大小" "${mem_g} GiB" printf " - %-15s : %s\n" "网络带宽" "${bw_mbps} Mbps" printf " - %-15s : %s\n" "网络延迟" "${rtt_ms} ms" printf " - %-15s : %s\n" "计算BDP" "${bdp_mb} MB" printf " - %-15s : %s\n" "缓冲区大小" "${buffer_mb} MB" echo
# 当前配置验证 echo -e "${GREEN}[+] 当前配置验证${RESET}" printf " - %-25s : %s\n" "TCP拥塞控制" "$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || echo '未知')" printf " - %-25s : %s\n" "默认队列调度" "$(sysctl -n net.core.default_qdisc 2>/dev/null || echo '未知')" printf " - %-25s : %s\n" "最大接收缓冲区" "$(sysctl -n net.core.rmem_max 2>/dev/null || echo '未知')" printf " - %-25s : %s\n" "最大发送缓冲区" "$(sysctl -n net.core.wmem_max 2>/dev/null || echo '未知')" echo
# 网络接口状态 local default_iface default_iface=$(ip -o -4 route show to default 2>/dev/null | awk '{print $5}' | head -1) if command -v tc >/dev/null 2>&1 && [[ -n "$default_iface" ]]; then echo -e "${GREEN}[+] 网络接口状态${RESET}" printf " - %-15s : %s\n" "默认接口" "$default_iface" local queue_type queue_type=$(tc qdisc show dev "$default_iface" 2>/dev/null | head -1 | awk '{print $2}' || echo "未知") printf " - %-15s : %s\n" "队列类型" "$queue_type" echo fi
echo -e "${CYAN}备份文件位置: ${backup_dir}${RESET}" echo -e "${CYAN}配置文件位置: /etc/sysctl.d/yuju-net-bbr-fq.conf${RESET}" echo -e "${CYAN}日志文件位置: $LOG_FILE${RESET}" echo "=================================="}
# 主函数main() { echo -e "${CYAN}" echo "╔══════════════════════════════════════════════════╗" echo "║ 智能TCP网络参数优化工具 ║" echo "╚══════════════════════════════════════════════════╝" echo -e "${RESET}"
# 权限检查 check_root
# 系统检查 local os_type os_type=$(check_os) info "检测到操作系统: $os_type"
check_kernel_version || warning "建议升级内核以获得更好的BBR支持"
# 创建备份目录 local backup_dir backup_dir=$(create_backup_dir) info "备份目录: $backup_dir"
# 自动检测参数 info "正在自动检测系统参数..." local mem_g bw_mbps rtt_ms mem_g=$(check_mem) bw_mbps=$(detect_bandwidth) rtt_ms=$(rtt_test)
success "自动检测完成"
# 参数确认循环 while true; do clear echo -e "${CYAN}╔══════════════════════════════════════════════════════════════════╗${RESET}" echo -e "${WHITE} 网络参数配置确认 ${RESET}" echo -e "${CYAN}╠══════════════════════════════════════════════════════════════════╣${RESET}" echo -e "${WHITE} 1.${RESET} 内存大小 : ${GREEN}${mem_g} GiB${RESET} ${WHITE}(系统自动检测)${RESET}" echo -e "${WHITE} 2.${RESET} 网络带宽 : ${GREEN}${bw_mbps} Mbps${RESET} ${WHITE}(智能检测)${RESET}" echo -e "${WHITE} 3.${RESET} 网络延迟 : ${GREEN}${rtt_ms} ms${RESET} ${WHITE}(网络测试)${RESET}" echo -e "${CYAN}╚══════════════════════════════════════════════════════════════════╝${RESET}"
local preview_result preview_result=$(calculate_buffers "$mem_g" "$bw_mbps" "$rtt_ms") local bdp_bytes buffer_bytes buffer_mb read -r bdp_bytes buffer_bytes buffer_mb <<< "$preview_result" local bdp_mb bdp_mb=$(awk -v b="$bdp_bytes" 'BEGIN{ printf "%.2f", b/1024/1024 }') echo
read -r -p "按 [Enter] 应用优化, 输入 [1-3] 修改参数, [q] 退出: " choice
case "$choice" in "") validate_params "$mem_g" "$bw_mbps" "$rtt_ms" info "参数验证通过,开始优化..." break ;; 1) read -r -p "请输入内存大小 (GiB) [${mem_g}]: " new_mem [[ -n "$new_mem" ]] && mem_g="$new_mem" ;; 2) read -r -p "请输入网络带宽 (Mbps) [${bw_mbps}]: " new_bw [[ -n "$new_bw" ]] && bw_mbps="$new_bw" ;; 3) read -r -p "请输入网络延迟 (ms) [${rtt_ms}]: " new_rtt [[ -n "$new_rtt" ]] && rtt_ms="$new_rtt" ;; q|Q) info "用户取消操作" exit 0 ;; *) warning "无效输入,请重试" sleep 1 ;; esac done
# 执行优化 local result result=$(calculate_buffers "$mem_g" "$bw_mbps" "$rtt_ms") read -r bdp_bytes buffer_bytes buffer_mb <<< "$result"
# 处理配置冲突 handle_conflicts "$backup_dir"
# 加载BBR模块 if command -v modprobe >/dev/null 2>&1; then modprobe tcp_bbr 2>/dev/null || warning "BBR模块加载失败,可能已内置" fi
# 应用优化配置 apply_optimization "$buffer_bytes" "$buffer_mb" "$mem_g" "$bw_mbps" "$rtt_ms" "$bdp_bytes"
# 显示结果 show_results "$mem_g" "$bw_mbps" "$rtt_ms" "$bdp_bytes" "$buffer_mb"
success "TCP优化配置完成!" info "重启系统后所有优化将完全生效"}
# 执行主函数main "$@"TuneTCP.sh的代码来自此仓库(目前已被删除,原因未知)。
把上面那两段代码分别保存到名为 fail2ban-manager.sh 和 TuneTCP.sh 的文件中
chmod +x ./fail2ban-manager.shchmod +x ./TuneTCP.sh./fail2ban-manager.sh./TuneTCP.sh2. 配置 SSH 密钥登录(可选)
ssh-keygen -t rsa -b 4096 -f ~/.ssh/<你的密钥名字>cd ~/.ssh/cat <你的密钥名字>.pub >> authorized_keys将密钥 <你的密钥名字> 复制到本地机器的 C:\Users\<用户名>\.ssh 目录。
在该目录下的 config 文件末尾添加以下配置:
Host <任意命名> HostName <服务器ip> Port 22 User root IdentityFile C:\Users\<用户名>\.ssh\<你的密钥名字>3. 安装 Docker
bash <(curl -sL 'https://get.docker.com')4. 安装 acme.sh
curl https://get.acme.sh | sh -s email=<你的邮箱>ln -s ~/.acme.sh/acme.sh /usr/local/bin/acme.shacme.sh --version5. 申请域名证书
export CF_Token="xxx"export CF_Account_ID="xxx"acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'
CF_TOKEN和CF_Account_ID的获取可参考acme官方文档
6. 申请自签名证书(openssl)
# 1. 创建存放证书的目录mkdir -p /www/sslcd /www/ssl
# 2. 生成私钥(2048 位 RSA)openssl genrsa -out selfsigned.key.pem 2048
# 3. 生成自签证书(有效期 100 年示例)openssl req -x509 -new -nodes -key selfsigned.key.pem \ -sha256 -days 36500 \ -out selfsigned.cert.pem \ -subj "/C=CN/ST=Shanghai/L=Shanghai/O=MyServer/CN=fake.local"7. 在 Docker 中配置 Nginx
mkdir -p /root/nginx/{log,conf.d,html} /www/ssl /root/certtouch /root/nginx/nginx.conf85 collapsed lines
user www-data;worker_processes auto;worker_cpu_affinity auto;pid /run/nginx.pid;error_log /var/log/nginx/error.log;include /etc/nginx/modules-enabled/*.conf;
events { worker_connections 768; # multi_accept on;}
http {
## # Basic Settings ##
sendfile on; tcp_nopush on; types_hash_max_size 2048; server_tokens build; # Recommended practice is to turn this off
# server_names_hash_bucket_size 64; # server_name_in_redirect off;
include /etc/nginx/mime.types; default_type application/octet-stream;
## # SSL Settings ##
ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1 ssl_prefer_server_ciphers off; # Don't force server cipher order.
## # Logging Settings ##
access_log /var/log/nginx/access.log;
## # Gzip Settings ##
gzip on;
# gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
## # Virtual Host Configs ##
include /etc/nginx/conf.d/*.conf; # include /etc/nginx/sites-enabled/*;
}
#mail {# # See sample authentication script at:# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript## # auth_http localhost/auth.php;# # pop3_capabilities "TOP" "USER";# # imap_capabilities "IMAP4rev1" "UIDPLUS";## server {# listen localhost:110;# protocol pop3;# proxy on;# }## server {# listen localhost:143;# protocol imap;# proxy on;# }#}44 collapsed lines
server { listen 80; listen [::]:80; server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / { root /usr/share/nginx/html; index index.html index.htm; }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }
# proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #}
# deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #}}29 collapsed lines
# =====================# HTTP 重定向到 HTTPS# =====================server { listen 80 default_server; listen [::]:80 default_server; server_name _;
location / { return 301 https://$host$request_uri; # 强制重定向到 HTTPS }}
# =====================# 未知域名返回 404# =====================server { listen 443 ssl default_server; listen [::]:443 ssl default_server; http2 on; server_name _;
ssl_certificate /etc/nginx/ssl/selfsigned.cert.pem; ssl_certificate_key /etc/nginx/ssl/selfsigned.key.pem;
location / { return 404; }}23 collapsed lines
<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>html { color-scheme: light dark; }body { width: 35em; margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif; }</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.</p>
<p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p></body></html>把上面那四段代码分别保存到名为 /root/nginx/nginx.conf、 /root/nginx/conf.d/default.conf、 /root/nginx/conf.d/redirect.conf 和 /root/nginx/html/index.html 的文件中。
运行以下命令启动 Nginx 容器:
docker run --name nginx \ -p 80:80 \ -p 443:443 \ -v /root/nginx/log:/var/log/nginx \ -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /root/nginx/conf.d:/etc/nginx/conf.d:ro \ -v /www/ssl:/etc/nginx/ssl:ro \ -v /root/nginx/html:/usr/share/nginx/html:ro \ -v /root/cert:/etc/nginx/cert:ro \ --add-host=host.docker.internal:host-gateway \ --restart=unless-stopped \ -d nginx8. 配置证书
在获取证书并配置 Nginx 后,使用以下命令配置证书:
acme.sh --install-cert -d example.com \ --key-file /www/ssl/example.com.key.pem \ --fullchain-file /www/ssl/example.com.cert.pem \ --reloadcmd "docker exec nginx nginx -s reload"9. 安装其他子域名证书
创建新目录并安装子域名证书:
mkdir -p ~/certcd ~/certmkdir -p sub.example.comacme.sh --issue --dns dns_cf -d sub.example.comacme.sh --install-cert -d sub.example.com \ --key-file /root/cert/sub.example.com/privkey.pem \ --fullchain-file /root/cert/sub.example.com/fullchain.pem \ --reloadcmd "docker exec nginx nginx -s reload"为第二个子域名执行相同的操作:
acme.sh --issue --dns dns_cf -d sub2.example.commkdir -p sub2.example.comacme.sh --install-cert -d sub2.example.com \ --key-file /root/cert/sub2.example.com/privkey.pem \ --fullchain-file /root/cert/sub2.example.com/fullchain.pem \ --reloadcmd "docker exec nginx nginx -s reload" 新服务器可能需要进行的一些配置
https://ifimi.cn/posts/server-configuration/