Files
script/vps_init.sh

758 lines
26 KiB
Bash
Raw Permalink 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初始化一键脚本
# 整合了系统更新、登录安全设置、系统清理、Docker安装、防火墙设置、时区设置、
# 内存优化、Fail2ban安装和BBR加速
# 使用方法: chmod +x vps_init.sh && ./vps_init.sh
#
# ===========================================
# 用户设置区域 - 根据需要修改
# ===========================================
# NEW_PASSWORD 已弃用 - 密码将在交互式设置中由用户输入
NEW_SSH_PORT="4399" # SSH新端口号默认值
TIMEZONE="Asia/Shanghai" # 时区设置
SWAP_SIZE=1024 # 交换分区大小(MB)
# ===========================================
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 恢复默认颜色
# 确保脚本以root权限运行
if [ "$(id -u)" -ne 0 ]; then
echo -e "${RED}错误: 必须以root用户运行此脚本!${NC}"
exit 1
fi
# 显示欢迎信息
echo -e "${GREEN}=============================================${NC}"
echo -e "${BLUE} VPS初始化一键脚本开始执行 ${NC}"
echo -e "${GREEN}=============================================${NC}"
echo ""
# ===========================================
# 交互式设置选项
# ===========================================
echo -e "${BLUE}进行交互式设置...${NC}"
# 询问是否修改SSH端口
echo -e "${YELLOW}1. 是否修改SSH端口? 当前设置为: ${NEW_SSH_PORT}${NC}"
while true; do
read -p "修改SSH端口? (y/n, 默认n): " CHANGE_SSH_PORT
# 设置默认值为否用户按Enter就不修改
CHANGE_SSH_PORT=${CHANGE_SSH_PORT:-n}
if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]] || [[ "$CHANGE_SSH_PORT" =~ ^[Nn]$ ]]; then
break
else
echo -e "${RED}无效的输入,请输入 y 或 n${NC}"
fi
done
if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]]; then
echo -e "${GREEN}SSH端口将被修改为: ${NEW_SSH_PORT}${NC}"
else
echo -e "${GREEN}保持SSH端口不变: $NEW_SSH_PORT${NC}"
fi
# 询问是否修改密码
echo -e "${YELLOW}2. 是否修改root密码?${NC}"
while true; do
read -p "修改root密码? (y/n, 默认n): " CHANGE_PASSWORD
# 设置默认值为否用户按Enter就不修改
CHANGE_PASSWORD=${CHANGE_PASSWORD:-n}
if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]] || [[ "$CHANGE_PASSWORD" =~ ^[Nn]$ ]]; then
break
else
echo -e "${RED}无效的输入,请输入 y 或 n${NC}"
fi
done
if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]]; then
# 让用户输入新密码
while true; do
read -sp "请输入新的root密码: " NEW_PASSWORD
echo ""
if [ -n "$NEW_PASSWORD" ]; then
# 要求用户确认密码
read -sp "请再次输入密码以确认: " NEW_PASSWORD_CONFIRM
echo ""
if [ "$NEW_PASSWORD" = "$NEW_PASSWORD_CONFIRM" ]; then
echo -e "${GREEN}密码已确认,将在后续步骤中修改${NC}"
break
else
echo -e "${RED}两次输入的密码不一致,请重新输入${NC}"
fi
else
echo -e "${RED}密码不能为空,请重新输入${NC}"
fi
done
else
echo -e "${GREEN}保持root密码不变${NC}"
fi
# 询问是否修改主机名
echo -e "${YELLOW}3. 是否修改主机名?${NC}"
while true; do
read -p "修改主机名? (y/n, 默认n): " CHANGE_HOSTNAME
# 设置默认值为否用户按Enter就不修改
CHANGE_HOSTNAME=${CHANGE_HOSTNAME:-n}
if [[ "$CHANGE_HOSTNAME" =~ ^[Yy]$ ]] || [[ "$CHANGE_HOSTNAME" =~ ^[Nn]$ ]]; then
break
else
echo -e "${RED}无效的输入,请输入 y 或 n${NC}"
fi
done
if [[ "$CHANGE_HOSTNAME" =~ ^[Yy]$ ]]; then
# 显示当前主机名
CURRENT_HOSTNAME=$(hostname)
echo -e "${YELLOW}当前主机名: ${CURRENT_HOSTNAME}${NC}"
# 让用户输入新主机名
read -p "请输入新的主机名: " NEW_HOSTNAME
if [ -n "$NEW_HOSTNAME" ]; then
CHANGE_HOSTNAME_FLAG=true
echo -e "${GREEN}主机名将被修改为: ${NEW_HOSTNAME}${NC}"
else
CHANGE_HOSTNAME_FLAG=false
echo -e "${RED}主机名不能为空,将保持不变${NC}"
fi
else
CHANGE_HOSTNAME_FLAG=false
echo -e "${GREEN}保持主机名不变${NC}"
fi
echo -e "${BLUE}交互式设置完成${NC}"
echo ""
# 记录开始时间
START_TIME=$(date +%s)
# 检查系统类型
if [ -f /etc/debian_version ]; then
OS_TYPE="debian"
echo -e "${GREEN}检测到Debian/Ubuntu系统${NC}"
else
echo -e "${YELLOW}警告: 此脚本主要为Debian/Ubuntu系统设计${NC}"
echo -e "${YELLOW}部分功能可能在其他系统上不正常工作${NC}"
OS_TYPE="other"
fi
# 创建日志文件
LOG_FILE="/var/log/vps_init_$(date +%Y%m%d_%H%M%S).log"
touch $LOG_FILE
echo "VPS初始化脚本开始执行: $(date)" > $LOG_FILE
# 创建摘要信息文件
SUMMARY_FILE="/root/vps_init.txt"
TEMP_HISTORY_FILE="/tmp/vps_init_history_$$.txt"
# 如果摘要文件已存在,提取历史端口和密码信息
if [ -f "$SUMMARY_FILE" ]; then
log "${YELLOW}检测到已存在的配置文件,正在提取历史信息...${NC}"
# 创建临时文件保存历史信息
echo "历史配置信息(从上次运行保留)" > $TEMP_HISTORY_FILE
echo "-------------------------------------------------------" >> $TEMP_HISTORY_FILE
# 提取所有SSH端口历史记录
SSH_PORTS=$(grep -E "SSH端口已更改为:" "$SUMMARY_FILE" | sed 's/.*SSH端口已更改为: //' | sed 's/[^0-9]//g' || true)
# 提取所有密码历史记录
PASSWORDS=$(grep -E "实际密码:" "$SUMMARY_FILE" | sed 's/.*实际密码: //' || true)
# 写入历史SSH端口
if [ -n "$SSH_PORTS" ]; then
echo "历史SSH端口:" >> $TEMP_HISTORY_FILE
echo "$SSH_PORTS" | while IFS= read -r port; do
if [ -n "$port" ]; then
echo " - $port" >> $TEMP_HISTORY_FILE
fi
done
fi
# 写入历史密码
if [ -n "$PASSWORDS" ]; then
echo "历史密码:" >> $TEMP_HISTORY_FILE
echo "$PASSWORDS" | while IFS= read -r pwd; do
if [ -n "$pwd" ]; then
echo " - $pwd" >> $TEMP_HISTORY_FILE
fi
done
fi
echo "-------------------------------------------------------" >> $TEMP_HISTORY_FILE
echo "" >> $TEMP_HISTORY_FILE
fi
# 创建新的摘要文件
touch $SUMMARY_FILE
echo "VPS初始化摘要信息" > $SUMMARY_FILE
echo "本次生成时间: $(date)" >> $SUMMARY_FILE
echo "=======================================================" >> $SUMMARY_FILE
echo "" >> $SUMMARY_FILE
# 如果有历史信息文件,追加到摘要文件
if [ -f "$TEMP_HISTORY_FILE" ]; then
cat $TEMP_HISTORY_FILE >> $SUMMARY_FILE
rm -f $TEMP_HISTORY_FILE
fi
# 定义日志函数
log() {
echo -e "$1" | tee -a $LOG_FILE
}
# 定义摘要信息函数(同时输出到屏幕、日志文件和摘要文件)
log_summary() {
echo -e "$1" | tee -a $LOG_FILE | sed 's/\x1b\[[0-9;]*m//g' >> $SUMMARY_FILE
}
# 定义错误处理函数
handle_error() {
local exit_code=$?
local line_no=$1
if [ $exit_code -ne 0 ]; then
log "${RED}错误: 在第 $line_no 行发生错误,退出代码: $exit_code${NC}"
log "${RED}请检查日志文件: $LOG_FILE${NC}"
fi
}
# 设置错误跟踪
trap 'handle_error $LINENO' ERR
# ===========================================
# 1. 系统更新
# ===========================================
log "${BLUE}[1/10] 系统更新开始...${NC}"
# 保存当前的sources.list作为备份
if [ -f "/etc/apt/sources.list" ]; then
cp /etc/apt/sources.list /etc/apt/sources.list.bak
log "${GREEN}备份了软件源配置文件${NC}"
fi
# 更新系统包
if [ "$OS_TYPE" = "debian" ]; then
apt update -y || log "${RED}更新软件源失败${NC}"
DEBIAN_FRONTEND=noninteractive apt full-upgrade -y || log "${RED}系统升级失败${NC}"
apt install -y wget curl sudo vim git ufw net-tools htop iftop || log "${RED}安装基础软件包失败${NC}"
log "${GREEN}系统更新完成,安装了常用工具${NC}"
else
log "${YELLOW}非Debian系统跳过标准更新流程${NC}"
fi
# ===========================================
# 2. 主机名设置(如果用户选择了修改)
# ===========================================
if [ "$CHANGE_HOSTNAME_FLAG" = true ]; then
log "${BLUE}[2/10] 设置主机名...${NC}"
# 备份当前主机名配置
cp /etc/hostname /etc/hostname.bak
cp /etc/hosts /etc/hosts.bak
# 修改主机名
echo "$NEW_HOSTNAME" > /etc/hostname
hostname "$NEW_HOSTNAME"
# 更新hosts文件
sed -i "s/127.0.1.1.*/127.0.1.1\t$NEW_HOSTNAME/g" /etc/hosts
# 检查是否修改成功
CURRENT_HOSTNAME=$(hostname)
if [ "$CURRENT_HOSTNAME" = "$NEW_HOSTNAME" ]; then
log "${GREEN}主机名已成功修改为: $NEW_HOSTNAME${NC}"
else
log "${RED}主机名修改失败,当前名称: $CURRENT_HOSTNAME${NC}"
fi
log "${GREEN}主机名设置完成${NC}"
else
log "${YELLOW}[2/10] 跳过主机名设置...${NC}"
fi
# ===========================================
# 3. 登录安全设置
# ===========================================
log "${BLUE}[3/10] 设置登录安全...${NC}"
# 根据用户选择修改root密码
if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]]; then
echo "root:$NEW_PASSWORD" | chpasswd
if [ $? -eq 0 ]; then
log "${GREEN}Root密码修改成功${NC}"
else
log "${RED}Root密码修改失败${NC}"
fi
else
log "${YELLOW}根据用户选择保持root密码不变${NC}"
fi
# 根据用户选择修改SSH端口
if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]]; then
# 备份SSH配置文件
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
log "${GREEN}SSH配置已备份${NC}"
# 修改SSH配置
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/#Port/Port/' /etc/ssh/sshd_config
sed -i "s/Port [0-9]\+/Port $NEW_SSH_PORT/g" /etc/ssh/sshd_config
# 读取修改后的SSH端口以确认更改
NEW_PORT_CONFIGURED=$(grep -P "^Port\s+\d+" /etc/ssh/sshd_config | awk '{print $2}')
if [ "$NEW_PORT_CONFIGURED" = "$NEW_SSH_PORT" ]; then
log "${GREEN}SSH端口已修改为: $NEW_SSH_PORT${NC}"
else
log "${RED}SSH端口修改失败当前设置: $NEW_PORT_CONFIGURED${NC}"
# 尝试使用另一种方法修改
echo "Port $NEW_SSH_PORT" >> /etc/ssh/sshd_config
log "${YELLOW}尝试使用备选方法添加端口设置${NC}"
fi
# 重启SSH服务
systemctl restart sshd
if [ $? -eq 0 ]; then
log "${GREEN}SSH服务重启成功${NC}"
else
log "${RED}SSH服务重启失败${NC}"
# 尝试使用service命令
service sshd restart || service ssh restart
fi
# 检查SSH服务状态
systemctl status sshd --no-pager || service sshd status || service ssh status
log "${GREEN}SSH配置更改完成${NC}"
log "${YELLOW}注意新的SSH连接端口为 $NEW_SSH_PORT${NC}"
else
log "${YELLOW}根据用户选择保持SSH端口不变${NC}"
# 即使不修改端口仍然应该确保其他SSH安全设置
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config
log "${GREEN}SSH基本安全设置完成${NC}"
fi
# ===========================================
# 4. 系统清理
# ===========================================
log "${BLUE}[4/10] 系统清理开始...${NC}"
# 清理不需要的软件包
if [ "$OS_TYPE" = "debian" ]; then
apt autoremove --purge -y
apt clean -y
apt autoclean -y
apt remove --purge $(dpkg -l | awk '/^rc/ {print $2}') -y 2>/dev/null || log "${YELLOW}没有需要清理的软件包配置${NC}"
# 清理日志
journalctl --rotate
journalctl --vacuum-time=1d
journalctl --vacuum-size=50M
log "${GREEN}系统日志已清理${NC}"
# 清理旧内核(保留当前运行的内核)
apt remove --purge $(dpkg -l | awk '/^ii linux-(image|headers)-[^ ]+/{print $2}' | grep -v $(uname -r | sed 's/-.*//') | xargs) -y 2>/dev/null || log "${YELLOW}没有可清理的旧内核${NC}"
log "${GREEN}系统清理完成${NC}"
else
log "${YELLOW}非Debian系统跳过系统清理流程${NC}"
fi
# ===========================================
# 5. Docker安装
# ===========================================
log "${BLUE}[5/10] Docker安装开始...${NC}"
# 检查Docker是否已安装
if command -v docker &> /dev/null; then
log "${GREEN}Docker已经安装版本信息:${NC}"
docker --version
else
# 安装Docker
if [ "$OS_TYPE" = "debian" ]; then
# 使用官方安装脚本
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
rm get-docker.sh
systemctl enable docker
# 安装Docker Compose
if ! command -v docker-compose &> /dev/null; then
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
log "${GREEN}Docker Compose 安装完成${NC}"
fi
log "${GREEN}Docker安装完成版本信息:${NC}"
docker --version
docker-compose --version
else
log "${YELLOW}非Debian系统请手动安装Docker${NC}"
fi
fi
# ===========================================
# 6. 防火墙设置
# ===========================================
log "${BLUE}[6/10] 防火墙设置开始...${NC}"
# 安装UFW
if [ "$OS_TYPE" = "debian" ]; then
apt update -y && apt install -y ufw net-tools lsof
# 确保防火墙默认策略
ufw default deny incoming
ufw default allow outgoing
# 获取当前SSH端口如果有多个SSH端口获取所有
CURRENT_SSH_PORT=$(grep -P "^Port\s+\d+" /etc/ssh/sshd_config | awk '{print $2}')
if [ -z "$CURRENT_SSH_PORT" ]; then
# 如果没找到使用默认端口22
CURRENT_SSH_PORT="22"
fi
# 总是添加新配置的SSH端口防止被锁在系统之外
log "${GREEN}允许SSH端口 $NEW_SSH_PORT${NC}"
ufw allow $NEW_SSH_PORT/tcp comment 'New SSH Port'
# 如果当前SSH端口与新端口不同添加当前SSH端口作为备份
if [ "$CURRENT_SSH_PORT" != "$NEW_SSH_PORT" ]; then
log "${GREEN}允许当前SSH端口 $CURRENT_SSH_PORT (备份)${NC}"
ufw allow $CURRENT_SSH_PORT/tcp comment 'Current SSH Port (Backup)'
fi
# 添加基本Web服务端口
log "${GREEN}允许HTTP/HTTPS端口${NC}"
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
# 检测活跃的网络连接和正在监听的端口
log "${YELLOW}检测当前活跃的服务端口...${NC}"
# 使用netstat查找监听的TCP端口
LISTENING_PORTS=$(netstat -tlnp 2>/dev/null | grep "LISTEN" | awk '{print $4}' | awk -F: '{print $NF}' | sort -n | uniq)
# 使用lsof作为备选方法
if [ -z "$LISTENING_PORTS" ]; then
LISTENING_PORTS=$(lsof -i -P -n | grep LISTEN | awk '{print $9}' | awk -F: '{print $NF}' | sort -n | uniq)
fi
# 如果仍然为空,提示手动检查
if [ -z "$LISTENING_PORTS" ]; then
log "${YELLOW}未检测到活跃端口只开放SSH、HTTP和HTTPS端口${NC}"
else
log "${GREEN}检测到以下活跃端口:${NC}"
for PORT in $LISTENING_PORTS; do
# 跳过SSH端口(已经添加过),以及常见的本地服务端口
if [[ "$PORT" != "$NEW_SSH_PORT" && "$PORT" != "$CURRENT_SSH_PORT" &&
"$PORT" != "80" && "$PORT" != "443" &&
"$PORT" -lt "65535" && "$PORT" -gt "1024" ]]; then
# 尝试找出服务名称
SERVICE=$(lsof -i:$PORT -sTCP:LISTEN | grep -v "COMMAND" | awk '{print $1}' | head -1)
if [ -z "$SERVICE" ]; then
SERVICE=$(netstat -tlnp 2>/dev/null | grep ":$PORT" | awk '{print $7}' | cut -d"/" -f2 | head -1)
fi
if [ -n "$SERVICE" ]; then
COMMENT="Service: $SERVICE"
else
COMMENT="Unknown Service"
fi
log "${GREEN}允许端口 $PORT/tcp ($COMMENT)${NC}"
ufw allow $PORT/tcp comment "$COMMENT"
fi
done
fi
# 删除询问用户是否手动开放端口的部分
log "${GREEN}已自动开放SSH、HTTP、HTTPS端口和检测到的活跃服务端口${NC}"
# 启用防火墙
if ! ufw status | grep -q "Status: active"; then
log "${YELLOW}启用UFW防火墙...${NC}"
echo "y" | ufw enable || log "${RED}UFW启用失败${NC}"
else
log "${GREEN}UFW防火墙已启用${NC}"
fi
# 显示防火墙状态
ufw status numbered | tee -a $LOG_FILE
log "${GREEN}防火墙设置完成,已使用最小化原则开放端口${NC}"
else
log "${YELLOW}非Debian系统请手动配置防火墙${NC}"
fi
# ===========================================
# 7. 时区设置
# ===========================================
log "${BLUE}[7/10] 时区设置开始...${NC}"
# 设置时区
timedatectl set-timezone $TIMEZONE
if [ $? -eq 0 ]; then
CURRENT_TZ=$(timedatectl show --property=Timezone --value)
log "${GREEN}时区设置为: $CURRENT_TZ${NC}"
else
log "${RED}时区设置失败${NC}"
fi
# ===========================================
# 8. 内存优化 - 添加交换空间
# ===========================================
log "${BLUE}[8/10] 内存优化开始...${NC}"
# 获取当前所有交换空间信息
CURRENT_SWAP_TOTAL=$(free -m | grep "Swap:" | awk '{print $2}')
log "${YELLOW}当前系统交换空间总大小: ${CURRENT_SWAP_TOTAL}MB${NC}"
# 检查是否存在交换空间且大小与设定值相同
if [ "$CURRENT_SWAP_TOTAL" -eq "$SWAP_SIZE" ]; then
log "${GREEN}当前交换空间大小(${CURRENT_SWAP_TOTAL}MB)与设定值一致,无需修改${NC}"
# 显示交换空间信息
free -h | tee -a $LOG_FILE
else
# 如果不存在交换空间或大小不同,则进行处理
if [ "$CURRENT_SWAP_TOTAL" -gt "0" ]; then
log "${YELLOW}系统已有交换空间但大小不符(${CURRENT_SWAP_TOTAL}MB),准备清理现有交换空间...${NC}"
# 获取所有交换设备
SWAP_DEVICES=$(swapon --show=NAME --noheadings)
# 清理所有活跃的交换空间
for DEVICE in $SWAP_DEVICES; do
log "${YELLOW}关闭交换空间: $DEVICE${NC}"
swapoff "$DEVICE"
done
# 从fstab中移除所有交换空间条目(保留备份)
cp /etc/fstab /etc/fstab.bak
log "${GREEN}备份了/etc/fstab文件${NC}"
sed -i '/swap/d' /etc/fstab
# 删除交换文件
if [ -f /swapfile ]; then
log "${YELLOW}删除现有交换文件...${NC}"
rm -f /swapfile
fi
log "${GREEN}所有现有交换空间已清理${NC}"
else
log "${YELLOW}系统未配置交换空间,准备创建...${NC}"
fi
# 创建新的交换文件
log "${GREEN}创建${SWAP_SIZE}MB大小的交换文件...${NC}"
dd if=/dev/zero of=/swapfile bs=1M count=$SWAP_SIZE status=progress
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# 设置开机自动挂载
if ! grep -q "/swapfile" /etc/fstab; then
echo "/swapfile swap swap defaults 0 0" >> /etc/fstab
log "${GREEN}已添加到fstab开机将自动挂载${NC}"
fi
# 调整swappiness参数(控制系统对交换空间的使用倾向)
echo "vm.swappiness=10" > /etc/sysctl.d/99-swappiness.conf
sysctl -p /etc/sysctl.d/99-swappiness.conf
# 显示交换空间信息
log "${GREEN}交换分区配置完成,当前内存和交换空间状态:${NC}"
free -h | tee -a $LOG_FILE
fi
# ===========================================
# 9. Fail2ban安装和配置
# ===========================================
log "${BLUE}[9/10] Fail2ban安装开始...${NC}"
if [ "$OS_TYPE" = "debian" ]; then
# 安装Fail2ban
apt update -y && apt install -y fail2ban
systemctl start fail2ban
systemctl enable fail2ban
# 配置Fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# 清理任何现有配置
rm -rf /etc/fail2ban/jail.d/* 2>/dev/null || true
# 创建SSH防护配置
cat <<EOF > /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
mode = normal
port = $NEW_SSH_PORT
logpath = %(sshd_log)s
backend = systemd
maxretry = 5
bantime = 1h
findtime = 10m
EOF
# 重启Fail2ban
log "${YELLOW}重启Fail2ban服务...${NC}"
systemctl restart fail2ban
# 等待服务启动完成
log "${YELLOW}等待Fail2ban服务完全启动...${NC}"
sleep 5
# 检查服务状态
if systemctl is-active --quiet fail2ban; then
log "${GREEN}Fail2ban服务已成功启动${NC}"
# 显示Fail2ban状态使用错误处理避免脚本终止
log "${YELLOW}获取Fail2ban状态信息...${NC}"
# 尝试获取fail2ban状态忽略可能的错误
fail2ban-client status >/dev/null 2>&1 || log "${YELLOW}无法获取fail2ban综合状态但这不影响功能${NC}"
# 尝试获取sshd监狱状态
if fail2ban-client status sshd >/dev/null 2>&1; then
log "${GREEN}SSH防护已成功配置${NC}"
# 只有在前面成功的情况下才显示详细信息
fail2ban-client status sshd
else
log "${YELLOW}无法获取SSH监狱状态这可能是因为服务刚刚启动或配置需要更多时间生效${NC}"
log "${YELLOW}如果在重启后仍有问题,请检查 /var/log/fail2ban.log${NC}"
fi
# 显示服务状态
systemctl status fail2ban --no-pager || true
else
log "${RED}Fail2ban服务启动失败请检查错误日志${NC}"
log "${YELLOW}尝试查看Fail2ban日志获取错误详情:${NC}"
tail -n 20 /var/log/fail2ban.log 2>/dev/null || log "${RED}无法读取Fail2ban日志${NC}"
fi
log "${GREEN}Fail2ban安装和配置完成${NC}"
log "${YELLOW}如果出现临时错误,服务器重启后通常会正常工作${NC}"
else
log "${YELLOW}非Debian系统请手动安装Fail2ban${NC}"
fi
# ===========================================
# 10. BBR加速配置
# ===========================================
log "${BLUE}[10/10] BBR配置开始...${NC}"
# 检查BBR是否已启用
if sysctl net.ipv4.tcp_congestion_control | grep -q "bbr"; then
log "${GREEN}BBR已经启用${NC}"
else
log "${YELLOW}配置BBR...${NC}"
# 添加BBR配置
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
# 应用设置
sysctl -p
# 验证设置
if sysctl net.ipv4.tcp_congestion_control | grep -q "bbr"; then
log "${GREEN}BBR启用成功${NC}"
else
log "${RED}BBR启用失败${NC}"
fi
fi
# 显示可用的拥塞控制算法
log "${GREEN}当前系统支持的TCP拥塞控制算法:${NC}"
sysctl net.ipv4.tcp_available_congestion_control
# 验证模块是否加载
lsmod | grep bbr
# ===========================================
# 完成处理
# ===========================================
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
MINUTES=$((DURATION / 60))
SECONDS=$((DURATION % 60))
log_summary ""
log_summary "本次配置信息"
log_summary "======================================================="
log_summary "${GREEN}VPS初始化完成用时: ${MINUTES}${SECONDS}${NC}"
log_summary "${GREEN}=======================================================${NC}"
log_summary "${YELLOW}重要提示:${NC}"
# 根据用户选择显示相应的提示信息
TIP_COUNT=1
# 如果用户选择了修改SSH端口显示端口信息
if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]]; then
log_summary "${YELLOW}$TIP_COUNT. SSH端口已更改为: ${NEW_SSH_PORT}${NC}"
TIP_COUNT=$((TIP_COUNT + 1))
fi
# 如果用户选择了修改root密码显示密码信息
if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]]; then
log_summary "${YELLOW}$TIP_COUNT. root密码已更改 (长度: ${#NEW_PASSWORD} 字符)${NC}"
# 将实际密码单独写入摘要文件(不输出到屏幕)
echo " 实际密码: ${NEW_PASSWORD}" | sed 's/\x1b\[[0-9;]*m//g' >> $SUMMARY_FILE
TIP_COUNT=$((TIP_COUNT + 1))
fi
# 如果用户选择了修改主机名,显示主机名信息
if [ "$CHANGE_HOSTNAME_FLAG" = true ]; then
log_summary "${YELLOW}$TIP_COUNT. 主机名已更改为: ${NEW_HOSTNAME}${NC}"
TIP_COUNT=$((TIP_COUNT + 1))
fi
# 始终显示防火墙和日志文件信息
log_summary "${YELLOW}$TIP_COUNT. 防火墙已启用,只开放了必要端口${NC}"
TIP_COUNT=$((TIP_COUNT + 1))
log_summary "${YELLOW}$TIP_COUNT. 日志文件保存在: ${LOG_FILE}${NC}"
# 如果已启用BBR显示BBR信息
if sysctl net.ipv4.tcp_congestion_control 2>/dev/null | grep -q "bbr"; then
TIP_COUNT=$((TIP_COUNT + 1))
log_summary "${YELLOW}$TIP_COUNT. BBR加速已成功启用${NC}"
fi
# 如果配置了交换空间,显示交换空间信息
if [ "$CURRENT_SWAP_TOTAL" -gt "0" ]; then
TIP_COUNT=$((TIP_COUNT + 1))
log_summary "${YELLOW}$TIP_COUNT. 交换空间大小: $(free -m | grep "Swap:" | awk '{print $2}')MB${NC}"
fi
log_summary "${GREEN}=======================================================${NC}"
log_summary "${BLUE}建议您现在重启服务器以应用所有更改${NC}"
log_summary "${GREEN}=======================================================${NC}"
log_summary ""
log_summary "摘要信息已保存到: ${SUMMARY_FILE}"
# 提示用户是否立即重启
while true; do
read -p "是否立即重启服务器?(y/n, 默认n): " REBOOT_NOW
# 设置默认值为否
REBOOT_NOW=${REBOOT_NOW:-n}
if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]] || [[ "$REBOOT_NOW" =~ ^[Nn]$ ]]; then
break
else
echo -e "${RED}无效的输入,请输入 y 或 n${NC}"
fi
done
if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]]; then
log "${GREEN}服务器将在5秒后重启...${NC}"
sleep 5
reboot
else
log "${YELLOW}请稍后手动重启服务器以应用所有更改${NC}"
fi