5770 字
29 分钟
新服务器可能需要进行的一些配置

服务器配置#

1. 配置 Fail2ban 和 TuneTCP#

fail2ban-manager.sh
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 1
fi
# --- 核心工具函数 ---
# 检测系统类型并设置 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. 安装并配置 Fail2Ban
install_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 = true
ignoreip = 127.0.0.1/8
filter = sshd
port = ssh
maxretry = 6
findtime = 300
bantime = 31536000
bantime.increment = true
bantime.factor = 2
bantime.rndtime = 300
bantime.overalljails = true
action = %(action_)s
banaction = iptables-multiport
logpath = ${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_menu
TuneTCP.sh
616 collapsed lines
#!/bin/bash
set -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 = fq
net.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 = 1
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_notsent_lowat = 16384
# 连接跟踪优化 (适用于高并发)
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
# 其他网络优化
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 32768
EOF
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.shTuneTCP.sh 的文件中

Terminal window
chmod +x ./fail2ban-manager.sh
chmod +x ./TuneTCP.sh
./fail2ban-manager.sh
./TuneTCP.sh

2. 配置 SSH 密钥登录(可选)#

Terminal window
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#

Terminal window
bash <(curl -sL 'https://get.docker.com')

4. 安装 acme.sh#

Terminal window
curl https://get.acme.sh | sh -s email=<你的邮箱>
ln -s ~/.acme.sh/acme.sh /usr/local/bin/acme.sh
acme.sh --version

5. 申请域名证书#

Terminal window
export CF_Token="xxx"
export CF_Account_ID="xxx"
acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'

CF_TOKENCF_Account_ID 的获取可参考acme官方文档

6. 申请自签名证书(openssl)#

Terminal window
# 1. 创建存放证书的目录
mkdir -p /www/ssl
cd /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#

Terminal window
mkdir -p /root/nginx/{log,conf.d,html} /www/ssl /root/cert
touch /root/nginx/nginx.conf
nginx.conf
85 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;
# }
#}
default.conf
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;
#}
}
redirect.conf
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;
}
}
index.html
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 and
working. 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 容器:

Terminal window
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 nginx

8. 配置证书#

在获取证书并配置 Nginx 后,使用以下命令配置证书:

Terminal window
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. 安装其他子域名证书#

创建新目录并安装子域名证书:

Terminal window
mkdir -p ~/cert
cd ~/cert
mkdir -p sub.example.com
acme.sh --issue --dns dns_cf -d sub.example.com
acme.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"

为第二个子域名执行相同的操作:

Terminal window
acme.sh --issue --dns dns_cf -d sub2.example.com
mkdir -p sub2.example.com
acme.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/
作者
花花
发布于
2025-11-12
许可协议
CC BY-NC-SA 4.0