-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathscript.sh
More file actions
executable file
·449 lines (409 loc) · 16.6 KB
/
Copy pathscript.sh
File metadata and controls
executable file
·449 lines (409 loc) · 16.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
#!/usr/bin/env bash
# ==============================================================================
# Linux TCP/IP & BBR 智能优化脚本
#
# 版本: v26.08.29
# ==============================================================================
# --- 脚本版本号定义 ---
SCRIPT_VERSION="v26.08.29"
set -euo pipefail
# --- 颜色定义 ---
GREEN=$'\033[0;32m'
RED=$'\033[0;31m'
YELLOW=$'\033[1;33m'
CYAN=$'\033[0;36m'
BLUE=$'\033[0;34m'
NC=$'\033[0m'
BBR_AVAILABLE=false
CONF_WRITE_FILE=""
# --- 统一输出样式 ---
success() { printf '\n%b[✔] %s%b\n\n' "$GREEN" "$1" "$NC" >&2; }
warning() { printf '\n%b[⚠] %s%b\n\n' "$YELLOW" "$1" "$NC" >&2; }
error() { printf '\n%b[✖] %s%b\n\n' "$RED" "$1" "$NC" >&2; }
section() { printf '\n%b>>> %s%b\n' "$CYAN" "$1" "$NC"; }
step() { printf '%b [%s/%s]%b %s\n' "$BLUE" "$1" "$2" "$NC" "$3"; }
# --- 配置文件路径 ---
CONF_FILE="/etc/sysctl.d/99-network-optimization.conf"
LEGACY_CONF_FILE="/etc/sysctl.d/99-bbr.conf"
SWAP_FILE="/swapfile"
# --- 系统信息检测函数 ---
get_system_info() {
TOTAL_MEM=$(free -m | awk '/^Mem:/{print $2}' | tr -d '\r')
CPU_CORES=$(nproc | tr -d '\r')
if command -v systemd-detect-virt >/dev/null 2>&1; then
VIRT_TYPE=$(systemd-detect-virt)
elif grep -q -i "hypervisor" /proc/cpuinfo; then
VIRT_TYPE="KVM/VMware"
else
VIRT_TYPE="Physical/Unknown"
fi
section "系统信息检测"
printf '%b\n' " 内存大小 : ${YELLOW}${TOTAL_MEM}MB${NC}"
printf '%b\n' " CPU 核心数 : ${YELLOW}${CPU_CORES}${NC}"
printf '%b\n' " 虚拟化类型 : ${YELLOW}${VIRT_TYPE}${NC}"
calculate_parameters
printf '%b\n' " 优化档位 : ${YELLOW}${VM_TIER}${NC}"
}
# --- 动态参数计算函数 (针对转发业务调整) ---
calculate_parameters() {
# 基础连接数设置 - 代理服务器需要更多的连接跟踪
if [ "$TOTAL_MEM" -le 512 ]; then
VM_TIER="入门级(≤512MB)"
RMEM_MAX="8388608" # 8MB
WMEM_MAX="8388608"
TCP_MEM_MAX="8388608"
SOMAXCONN="4096"
NETDEV_BACKLOG="4096"
FILE_MAX="131072"
CONNTRACK_MAX="32768"
elif [ "$TOTAL_MEM" -le 1024 ]; then
VM_TIER="基础级(1GB)"
RMEM_MAX="16777216" # 16MB
WMEM_MAX="16777216"
TCP_MEM_MAX="16777216"
SOMAXCONN="8192"
NETDEV_BACKLOG="8192"
FILE_MAX="262144"
CONNTRACK_MAX="65536"
elif [ "$TOTAL_MEM" -le 4096 ]; then
VM_TIER="进阶级(1GB-4GB)"
RMEM_MAX="33554432" # 32MB
WMEM_MAX="33554432"
TCP_MEM_MAX="33554432"
SOMAXCONN="16384"
NETDEV_BACKLOG="16384"
FILE_MAX="524288"
CONNTRACK_MAX="131072"
else
VM_TIER="专业级(>4GB)"
# 限制最大缓冲区,避免单连接吃光内存,注重并发总量
RMEM_MAX="67108864" # 64MB
WMEM_MAX="67108864"
TCP_MEM_MAX="67108864"
SOMAXCONN="32768"
NETDEV_BACKLOG="32768"
FILE_MAX="1048576"
CONNTRACK_MAX="262144"
fi
}
# --- 预检查函数 ---
require_root() {
if [[ $(id -u) -ne 0 ]]; then
error "必须使用 root 权限运行。"
exit 1
fi
}
sysctl_supported() {
[[ -e "/proc/sys/${1//./\/}" ]]
}
pre_flight_checks() {
require_root
# 加载必要的内核模块 (尤其是连接跟踪和BBR)
modprobe nf_conntrack >/dev/null 2>&1 || true
modprobe tcp_bbr >/dev/null 2>&1 || true
if grep -qw bbr /proc/sys/net/ipv4/tcp_available_congestion_control 2>/dev/null; then
BBR_AVAILABLE=true
else
warning "当前内核不支持 BBR,将跳过 BBR 配置。"
fi
}
# --- 配置写入函数 ---
add_conf() {
local key="$1"
local value="$2"
local comment="$3"
local target="${CONF_WRITE_FILE:-$CONF_FILE}"
if ! sysctl_supported "$key"; then
return 0
fi
{
printf '# %s\n' "$comment"
printf '%s = %s\n\n' "$key" "$value"
} >> "$target"
}
# --- 备份管理 ---
manage_backups() {
if [ -f "$CONF_FILE" ]; then
cp "$CONF_FILE" "$CONF_FILE.bak_$(date +%F_%H-%M-%S)"
# 保留最近3个备份
find "$(dirname "$CONF_FILE")" -maxdepth 1 -type f \
-name "$(basename "$CONF_FILE").bak_*" -printf '%T@ %p\n' 2>/dev/null \
| sort -nr | awk 'NR > 3 {sub(/^[^ ]+ /, ""); print}' \
| xargs -r rm -f
fi
}
migrate_legacy_config() {
if [[ -f "$LEGACY_CONF_FILE" ]]; then
local backup
backup="${LEGACY_CONF_FILE}.migrated_$(date +%F_%H-%M-%S)"
cp "$LEGACY_CONF_FILE" "$backup"
rm -f "$LEGACY_CONF_FILE"
warning "已备份并停用旧配置:${LEGACY_CONF_FILE}"
fi
}
configure_swap() {
local swap_mb
if [ "$TOTAL_MEM" -le 512 ]; then
swap_mb=512
elif [ "$TOTAL_MEM" -le 1024 ]; then
swap_mb=1024
else
swap_mb=2048
fi
# 计算当前总 Swap(含分区与 swapfile)
local current_total_mb=0 size_bytes swap_line
while IFS= read -r swap_line; do
[[ -n "$swap_line" ]] || continue
size_bytes=$(awk '{print $2}' <<< "$swap_line")
[[ "$size_bytes" =~ ^[0-9]+$ ]] && current_total_mb=$((current_total_mb + (size_bytes + 524288) / 1048576))
done < <(swapon --show=NAME,SIZE --bytes --noheadings 2>/dev/null)
if [[ "$current_total_mb" -eq "$swap_mb" ]]; then
printf '%b\n' "${GREEN} ✔ 现有 Swap 与目标一致(${current_total_mb}MB),保留。${NC}"
return
fi
if [[ "$current_total_mb" -gt 0 ]]; then
printf '%b\n' "${YELLOW} 现有 Swap ${current_total_mb}MB 与目标 ${swap_mb}MB 不一致,将统一替换为 /swapfile。${NC}"
else
printf '%b\n' "${GREEN} 未检测到 Swap,将创建 ${swap_mb}MB。${NC}"
fi
local available_mb
available_mb=$(df -Pm / | awk 'NR==2 {print $4}')
if [[ -z "$available_mb" || "$available_mb" -lt $((swap_mb + 100)) ]]; then
warning "磁盘空间不足,跳过创建 ${swap_mb}MB Swap。"
return
fi
section "创建 Swap"
step 1 2 "正在准备 ${swap_mb}MB Swap..."
# 保护:/swapfile 存在但未启用时视为用户文件,不覆盖
if [[ -e "$SWAP_FILE" ]] && ! swapon --show=NAME --noheadings 2>/dev/null | grep -Fxq "$SWAP_FILE"; then
warning "${SWAP_FILE} 已存在但未启用,为避免覆盖用户文件,跳过创建。"
return
fi
local new_swap="${SWAP_FILE}.new.$$"
if command -v fallocate >/dev/null 2>&1; then
if ! fallocate -l "${swap_mb}M" "$new_swap"; then
rm -f -- "$new_swap"
error "Swap 文件创建失败。"
return
fi
elif ! dd if=/dev/zero of="$new_swap" bs=1M count="$swap_mb" status=none; then
rm -f -- "$new_swap"
error "Swap 文件创建失败。"
return
fi
if ! chmod 600 "$new_swap"; then
rm -f -- "$new_swap"
error "无法设置 Swap 文件权限,已清理残留文件。"
return
fi
if ! mkswap "$new_swap" >/dev/null; then
rm -f -- "$new_swap"
error "Swap 初始化失败,已清理残留文件。"
return
fi
step 2 2 "替换并启用 Swap..."
# 新文件就绪后,再关闭全部旧 Swap 并移除 fstab 条目(含分区 Swap)
if [[ "$current_total_mb" -gt 0 ]]; then
local active_swap
while IFS= read -r active_swap; do
[[ -n "$active_swap" ]] || continue
if ! swapoff "$active_swap" >/dev/null 2>&1; then
rm -f -- "$new_swap"
error "无法关闭现有 Swap:${active_swap},中止替换。"
return
fi
done < <(swapon --show=NAME --noheadings 2>/dev/null)
sed -i -E '\|^[[:space:]]*[^#[:space:]][^[:space:]]*[[:space:]]+[^[:space:]]+[[:space:]]+swap([[:space:]]|$)|d' /etc/fstab
rm -f -- "$SWAP_FILE"
fi
if ! mv -f "$new_swap" "$SWAP_FILE"; then
rm -f -- "$new_swap"
error "Swap 文件替换失败。"
return
fi
if ! swapon "$SWAP_FILE" >/dev/null; then
rm -f -- "$SWAP_FILE"
error "Swap 启用失败,已清理残留文件。"
return
fi
if ! grep -qF "$SWAP_FILE none swap" /etc/fstab 2>/dev/null; then
if ! printf '%s\n' "$SWAP_FILE none swap sw 0 0" >> /etc/fstab; then
swapoff "$SWAP_FILE" >/dev/null 2>&1 || true
rm -f -- "$SWAP_FILE"
error "无法写入 /etc/fstab,已撤销并清理 Swap。"
return
fi
fi
success "Swap 已启用:${swap_mb}MB"
}
show_optimization_plan() {
local bbr_status="跳过" conntrack_status="跳过" swap_status="按内存配置"
[[ "$BBR_AVAILABLE" = true ]] && bbr_status="启用"
[[ -e /proc/sys/net/netfilter/nf_conntrack_max ]] && conntrack_status="按内存配置"
if swapon --show=NAME --noheadings 2>/dev/null | grep -q .; then
swap_status="将按目标调整"
else
swap_status="将按内存创建"
fi
printf '%b\n' "${CYAN} 优化摘要:${NC}"
printf ' BBR/FQ:%b%s%b,缓冲区上限:%b%s%b\n' \
"$YELLOW" "$bbr_status" "$NC" "$YELLOW" "$RMEM_MAX" "$NC"
printf ' 连接队列:%b%s%b,网卡积压:%b%s%b\n' \
"$YELLOW" "$SOMAXCONN" "$NC" "$YELLOW" "$NETDEV_BACKLOG" "$NC"
printf ' 文件句柄:%b%s%b,Conntrack:%b%s%b\n' \
"$YELLOW" "$FILE_MAX" "$NC" "$YELLOW" "$conntrack_status" "$NC"
printf ' Swap:%b%s%b\n' "$YELLOW" "$swap_status" "$NC"
}
apply_optimizations() {
section "应用网络优化配置:${VM_TIER}"
show_optimization_plan
local tmp_file="${CONF_FILE}.tmp.$$"
trap 'rm -f -- "$tmp_file"' ERR
CONF_WRITE_FILE="$tmp_file"
cat > "$tmp_file" << EOF
# ==========================================================
# Linux Network Tuning (Proxy/Forwarding Optimized)
# 生成时间: $(date)
# 硬件环境: ${TOTAL_MEM}MB RAM, ${CPU_CORES} CPU
# ==========================================================
EOF
# 1. BBR 与 队列算法
add_conf "net.core.default_qdisc" "fq" "FQ 队列算法"
[[ "$BBR_AVAILABLE" = true ]] && add_conf "net.ipv4.tcp_congestion_control" "bbr" "开启 BBR"
# 2. 缓冲区优化 (TCP & UDP) - 这对 Hysteria/QUIC 很重要
add_conf "net.core.rmem_max" "$RMEM_MAX" "系统最大接收缓存"
add_conf "net.core.wmem_max" "$WMEM_MAX" "系统最大发送缓存"
add_conf "net.core.rmem_default" "262144" "默认接收缓存 (256k)"
add_conf "net.core.wmem_default" "262144" "默认发送缓存 (256k)"
# TCP 自动调优窗口
add_conf "net.ipv4.tcp_rmem" "8192 262144 $TCP_MEM_MAX" "TCP读缓存 (min default max)"
add_conf "net.ipv4.tcp_wmem" "8192 262144 $TCP_MEM_MAX" "TCP写缓存 (min default max)"
add_conf "net.ipv4.udp_rmem_min" "16384" "UDP读缓存下限 (优化QUIC)"
add_conf "net.ipv4.udp_wmem_min" "16384" "UDP写缓存下限 (优化QUIC)"
# 3. 连接与队列上限
add_conf "net.core.somaxconn" "$SOMAXCONN" "最大监听队列"
add_conf "net.core.netdev_max_backlog" "$NETDEV_BACKLOG" "网卡积压队列"
add_conf "net.ipv4.tcp_max_syn_backlog" "$SOMAXCONN" "SYN半连接队列"
add_conf "net.ipv4.tcp_notsent_lowat" "16384" "降低缓冲区未发送数据阈值 (降低延迟)"
# 4. TIME_WAIT 与 端口复用 (代理服务器的关键)
add_conf "net.ipv4.tcp_tw_reuse" "1" "开启 TIME_WAIT 复用 (关键优化)"
add_conf "net.ipv4.tcp_timestamps" "1" "开启时间戳 (配合 reuse 必须)"
add_conf "net.ipv4.tcp_fin_timeout" "30" "缩短 FIN_WAIT 时间"
add_conf "net.ipv4.ip_local_port_range" "10000 65535" "扩大本地端口范围"
add_conf "net.ipv4.tcp_max_tw_buckets" "500000" "允许更多 TIME_WAIT socket 存在"
# 5. TCP Keepalive (快速剔除死链)
add_conf "net.ipv4.tcp_keepalive_time" "600" "TCP保活时间 (10分钟)"
add_conf "net.ipv4.tcp_keepalive_intvl" "15" "探测间隔"
add_conf "net.ipv4.tcp_keepalive_probes" "5" "探测次数"
# 6. 连接跟踪 (Conntrack)
# 如果模块未加载,写入配置可能会报错,这里做个判断(但通常文件写入没问题,是sysctl -p报错)
if [[ -f /proc/sys/net/netfilter/nf_conntrack_max ]]; then
add_conf "net.netfilter.nf_conntrack_max" "$CONNTRACK_MAX" "最大连接跟踪数"
fi
if [[ -f /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established ]]; then
add_conf "net.netfilter.nf_conntrack_tcp_timeout_established" "7200" "连接跟踪超时 (2小时)"
fi
if [[ -f /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait ]]; then
add_conf "net.netfilter.nf_conntrack_tcp_timeout_time_wait" "120" "减少 TIME_WAIT 跟踪时间"
fi
if [[ ! -e /proc/sys/net/netfilter/nf_conntrack_max ]]; then
warning "当前内核不支持 conntrack,跳过相关参数。"
fi
# 7. 其他系统级优化
add_conf "fs.file-max" "$FILE_MAX" "最大文件句柄"
add_conf "vm.swappiness" "10" "减少 Swap 使用"
add_conf "net.ipv4.tcp_mtu_probing" "1" "开启 MTU 探测 (解决部分网络卡顿)"
add_conf "net.ipv4.tcp_syncookies" "1" "防 SYN Flood"
CONF_WRITE_FILE=""
mv -f "$tmp_file" "$CONF_FILE"
trap - ERR
}
# --- 应用与验证 ---
apply_and_verify() {
section "应用并验证"
step 1 2 "正在加载 sysctl 配置..."
local sysctl_rc=0
sysctl --system >/dev/null 2>&1 || sysctl_rc=$?
local cc qdisc reuse
cc=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || true)
qdisc=$(sysctl -n net.core.default_qdisc 2>/dev/null || true)
reuse=$(sysctl -n net.ipv4.tcp_tw_reuse 2>/dev/null || true)
if [[ "$sysctl_rc" -ne 0 ]]; then
warning "部分 sysctl 参数应用失败,请检查 ${CONF_FILE}。"
else
success "优化配置已应用。"
fi
printf '%b\n' "${CYAN} 当前生效参数${NC}"
printf '%b\n' " 拥塞控制 : ${YELLOW}${cc:-未知}${NC}"
printf '%b\n' " 队列算法 : ${YELLOW}${qdisc:-未知}${NC}"
if [ "$reuse" = "1" ]; then
printf '%b\n' " TCP 复用 : ${GREEN}已启用${NC}"
else
printf '%b\n' " TCP 复用 : ${RED}未启用${NC}"
fi
return "$sysctl_rc"
}
# --- 主逻辑 ---
usage() {
cat <<EOF
Linux Network Optimizer ${SCRIPT_VERSION}
用法:
$0 应用网络优化
$0 uninstall 删除本脚本配置并重新加载系统参数
$0 restore 恢复最近一次备份
EOF
}
main() {
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then usage; exit 0; fi
if [[ $# -eq 1 && ("${1:-}" == "restore" || "${1:-}" == "uninstall") ]]; then
require_root
local backup
backup=$(ls -t "${CONF_FILE}.bak_"* 2>/dev/null | head -n1 || true)
if [[ "${1:-}" == "restore" && -n "$backup" ]]; then
section "恢复备份"
step 1 2 "正在恢复:$backup"
cp "$backup" "$CONF_FILE"
step 2 2 "正在重新加载 sysctl..."
if sysctl --system >/dev/null 2>&1; then
success "已恢复配置文件并重新加载系统参数:$backup"
else
error "配置文件已恢复,但系统参数重新加载失败。"
exit 1
fi
exit 0
elif [[ "${1:-}" == "restore" ]]; then
warning "未找到可恢复的备份。"
exit 1
fi
section "卸载网络优化"
warning "将删除优化配置并重新加载系统参数。"
step 1 2 "正在删除:$CONF_FILE"
rm -f "$CONF_FILE"
step 2 2 "正在重新加载 sysctl..."
if sysctl --system >/dev/null 2>&1; then
success "网络优化配置已删除并重新加载系统参数。"
else
error "网络优化配置已删除,但系统参数重新加载失败。"
exit 1
fi
exit 0
fi
if [[ $# -gt 0 ]]; then
error "未知参数:$1"
usage
exit 2
fi
printf '%b\n' "${CYAN}╭──────────────────────────────────────────────────────╮${NC}"
printf '%b\n' "${CYAN}│ Linux Network Optimizer ${SCRIPT_VERSION} │${NC}"
printf '%b\n' "${CYAN}│ TCP / BBR / Proxy Edition │${NC}"
printf '%b\n' "${CYAN}╰──────────────────────────────────────────────────────╯${NC}"
echo
pre_flight_checks
get_system_info
configure_swap
migrate_legacy_config
manage_backups
apply_optimizations
apply_and_verify
}
main "$@"