You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1315 lines
38 KiB
Bash

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/bin/bash
################################################################################
# Linux 系统初始化脚本 v1.1
# 功能: 镜像源切换 | 基础工具安装 | 系统优化配置
# 支持: Ubuntu/Debian, CentOS/RHEL, Rocky Linux, AlmaLinux
# 作者: 自动化运维工具
# 使用: sudo ./init_system.sh [--auto] [--mirror=aliyun] [--non-interactive]
################################################################################
set -euo pipefail
# 颜色定义 - 用于终端彩色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
# 日志文件定义
LOG_FILE="/var/log/system-init-$(date +%Y%m%d-%H%M%S).log"
# 输出函数定义
print_info() {
echo -e "${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
echo "详细日志请查看: $LOG_FILE" >&2
}
# 错误处理函数
error_exit() {
print_error "$1"
exit 1
}
# 检查命令是否存在
check_command() {
if ! command -v "$1" &> /dev/null; then
print_warning "命令 $1 未找到,正在安装..."
case $OS in
ubuntu|debian)
sudo apt-get update && sudo apt-get install -y "$1" || {
print_error "安装 $1 失败"
return 1
}
;;
centos|rhel|rocky|almalinux)
sudo yum install -y "$1" || {
print_error "安装 $1 失败"
return 1
}
;;
esac
fi
return 0
}
# 脚本横幅显示
print_banner() {
clear
echo -e "${PURPLE}"
echo "=================================================="
echo " Linux 系统初始化脚本 v1.1"
echo "=================================================="
echo "功能: 镜像源切换 | 基础工具安装 | 系统优化配置"
echo "支持: Ubuntu/Debian, CentOS/RHEL, Rocky, AlmaLinux"
echo "=================================================="
echo -e "${NC}"
echo "日志文件: $LOG_FILE" | tee -a "$LOG_FILE"
echo "开始时间: $(date)" | tee -a "$LOG_FILE"
echo "==================================================" | tee -a "$LOG_FILE"
}
# 检查脚本运行权限
check_permissions() {
if [[ $EUID -ne 0 ]] && ! sudo -n true 2>/dev/null; then
error_exit "此脚本需要 root 权限或 sudo 权限\n请使用: sudo $0"
fi
print_success "权限检查通过"
}
# 检测操作系统类型和版本
detect_os() {
print_info "正在检测操作系统..."
# 检查 /etc/os-release 文件是否存在
if [[ ! -f /etc/os-release ]]; then
error_exit "无法检测操作系统: /etc/os-release 文件不存在"
fi
# 加载操作系统信息
. /etc/os-release
# 设置全局变量
OS="$ID"
OS_NAME="$NAME"
OS_VERSION="${VERSION_ID:-unknown}"
# 显示检测结果
print_success "操作系统: $OS_NAME $OS_VERSION"
# 检测网络环境
detect_network
}
# 检测网络环境(国内/国际)
detect_network() {
print_info "正在检测网络环境..."
# 测试多个网站,增加检测准确性
local test_sites=(
"www.baidu.com"
"www.google.com"
"github.com"
"mirrors.aliyun.com"
)
local china_count=0
local international_count=0
for site in "${test_sites[@]}"; do
if timeout 3 curl -s --head "$site" > /dev/null 2>&1; then
case "$site" in
*baidu.com*|*aliyun.com*)
((china_count++))
;;
*google.com*|*github.com*)
((international_count++))
;;
esac
fi
done
# 根据检测结果判断网络环境
if [[ $china_count -gt $international_count ]]; then
NETWORK_ENV="china"
print_info "检测到国内网络环境,建议使用国内镜像源"
elif [[ $international_count -gt 0 ]]; then
NETWORK_ENV="international"
print_info "检测到国际网络环境"
else
NETWORK_ENV="unknown"
print_warning "网络环境检测失败,请检查网络连接"
fi
}
# 备份原始软件源
backup_sources() {
print_info "正在备份原始软件源..."
local backup_dir="/etc/apt/backup-$(date +%Y%m%d)"
case $OS in
ubuntu|debian)
# 创建备份目录
sudo mkdir -p "$backup_dir"
# 备份 sources.list
if [[ -f /etc/apt/sources.list ]]; then
sudo cp /etc/apt/sources.list "$backup_dir/sources.list.bak"
print_success "已备份到 $backup_dir/sources.list.bak"
fi
# 备份 sources.list.d 目录
if [[ -d /etc/apt/sources.list.d ]]; then
sudo cp -r /etc/apt/sources.list.d "$backup_dir/"
print_success "已备份 sources.list.d 目录"
fi
;;
centos|rhel|rocky|almalinux)
backup_dir="/etc/yum.repos.d/backup-$(date +%Y%m%d)"
sudo mkdir -p "$backup_dir"
# 备份所有 .repo 文件
if ls /etc/yum.repos.d/*.repo &> /dev/null; then
sudo cp /etc/yum.repos.d/*.repo "$backup_dir/"
print_success "已备份到 $backup_dir/"
else
print_warning "未找到 .repo 文件,跳过备份"
fi
;;
*)
print_warning "不支持的操作系统,跳过备份"
;;
esac
}
# 配置 Ubuntu/Debian 镜像源
configure_ubuntu_mirrors() {
print_info "正在配置 Ubuntu/Debian 镜像源..."
# 获取 Ubuntu 版本代号
local ubuntu_codename
if command -v lsb_release &> /dev/null; then
ubuntu_codename=$(lsb_release -cs)
else
# 根据版本号推测代号
case "$OS_VERSION" in
"22.04") ubuntu_codename="jammy" ;;
"20.04") ubuntu_codename="focal" ;;
"18.04") ubuntu_codename="bionic" ;;
"16.04") ubuntu_codename="xenial" ;;
*) ubuntu_codename="jammy" ;; # 默认使用最新 LTS
esac
fi
# 如果指定了镜像源参数,直接使用
local mirror_url=""
local mirror_name=""
if [[ -n "${MIRROR_ARG:-}" ]]; then
case "${MIRROR_ARG}" in
aliyun)
mirror_url="http://mirrors.aliyun.com"
mirror_name="阿里云"
;;
tsinghua)
mirror_url="https://mirrors.tuna.tsinghua.edu.cn"
mirror_name="清华大学"
;;
ustc)
mirror_url="https://mirrors.ustc.edu.cn"
mirror_name="中国科技大学"
;;
huawei)
mirror_url="https://repo.huaweicloud.com"
mirror_name="华为云"
;;
nju)
mirror_url="https://mirrors.nju.edu.cn"
mirror_name="南京大学"
;;
*)
print_warning "未知的镜像源参数,使用交互式选择"
MIRROR_ARG=""
;;
esac
fi
# 如果没有通过参数指定镜像源,则进行交互式选择
if [[ -z "$mirror_url" ]]; then
echo ""
echo "请选择镜像源:"
echo "1) 阿里云 (推荐国内用户)"
echo "2) 清华大学"
echo "3) 中国科技大学"
echo "4) 华为云"
echo "5) 南京大学"
echo "6) 官方源 (推荐国际用户)"
echo ""
read -rp "请选择 [1-6, 默认: 1]: " mirror_choice
mirror_choice=${mirror_choice:-1}
case $mirror_choice in
1)
mirror_url="http://mirrors.aliyun.com"
mirror_name="阿里云"
;;
2)
mirror_url="https://mirrors.tuna.tsinghua.edu.cn"
mirror_name="清华大学"
;;
3)
mirror_url="https://mirrors.ustc.edu.cn"
mirror_name="中国科技大学"
;;
4)
mirror_url="https://repo.huaweicloud.com"
mirror_name="华为云"
;;
5)
mirror_url="https://mirrors.nju.edu.cn"
mirror_name="南京大学"
;;
6)
print_info "使用官方源"
mirror_url="http://archive.ubuntu.com"
mirror_name="官方源"
;;
*)
print_warning "无效选择,使用阿里云镜像"
mirror_url="http://mirrors.aliyun.com"
mirror_name="阿里云"
;;
esac
fi
print_info "正在配置 $mirror_name 镜像源..."
# 生成新的 sources.list
if [[ "$mirror_url" == "http://archive.ubuntu.com" ]]; then
# 官方源配置
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# Ubuntu 官方源
deb http://archive.ubuntu.com/ubuntu/ $ubuntu_codename main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ $ubuntu_codename-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ $ubuntu_codename-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ $ubuntu_codename-security main restricted universe multiverse
EOF
else
# 国内镜像源配置
sudo tee /etc/apt/sources.list > /dev/null <<EOF
# $mirror_name 镜像源
deb $mirror_url/ubuntu/ $ubuntu_codename main restricted universe multiverse
deb $mirror_url/ubuntu/ $ubuntu_codename-updates main restricted universe multiverse
deb $mirror_url/ubuntu/ $ubuntu_codename-backports main restricted universe multiverse
deb $mirror_url/ubuntu/ $ubuntu_codename-security main restricted universe multiverse
# 源码仓库
# deb-src $mirror_url/ubuntu/ $ubuntu_codename main restricted universe multiverse
# deb-src $mirror_url/ubuntu/ $ubuntu_codename-updates main restricted universe multiverse
# deb-src $mirror_url/ubuntu/ $ubuntu_codename-backports main restricted universe multiverse
# deb-src $mirror_url/ubuntu/ $ubuntu_codename-security main restricted universe multiverse
EOF
fi
print_success "$mirror_name 镜像源配置完成"
# 更新软件包索引
print_info "正在更新软件包索引..."
if sudo apt-get update; then
print_success "软件包索引更新完成"
else
print_warning "软件包索引更新失败,请检查网络连接"
return 1
fi
return 0
}
# 配置 CentOS/RHEL/Rocky/AlmaLinux 镜像源
configure_centos_mirrors() {
print_info "正在配置 CentOS/RHEL/Rocky/AlmaLinux 镜像源..."
local mirror_url=""
local mirror_name=""
# 如果指定了镜像源参数,直接使用
if [[ -n "${MIRROR_ARG:-}" ]]; then
case "${MIRROR_ARG}" in
aliyun)
mirror_url="https://mirrors.aliyun.com"
mirror_name="阿里云"
;;
tsinghua)
mirror_url="https://mirrors.tuna.tsinghua.edu.cn"
mirror_name="清华大学"
;;
ustc)
mirror_url="https://mirrors.ustc.edu.cn"
mirror_name="中国科技大学"
;;
huawei)
mirror_url="https://repo.huaweicloud.com"
mirror_name="华为云"
;;
*)
print_warning "未知的镜像源参数,使用交互式选择"
MIRROR_ARG=""
;;
esac
fi
# 交互式选择镜像源
if [[ -z "$mirror_url" ]]; then
echo ""
echo "请选择镜像源:"
echo "1) 阿里云 (推荐)"
echo "2) 清华大学"
echo "3) 中国科技大学"
echo "4) 华为云"
echo "5) 官方源"
echo ""
read -rp "请选择 [1-5, 默认: 1]: " mirror_choice
mirror_choice=${mirror_choice:-1}
case $mirror_choice in
1)
mirror_url="https://mirrors.aliyun.com"
mirror_name="阿里云"
;;
2)
mirror_url="https://mirrors.tuna.tsinghua.edu.cn"
mirror_name="清华大学"
;;
3)
mirror_url="https://mirrors.ustc.edu.cn"
mirror_name="中国科技大学"
;;
4)
mirror_url="https://repo.huaweicloud.com"
mirror_name="华为云"
;;
5)
print_info "使用官方源"
mirror_name="官方源"
;;
*)
print_warning "无效选择,使用阿里云镜像"
mirror_url="https://mirrors.aliyun.com"
mirror_name="阿里云"
;;
esac
fi
print_info "正在配置 $mirror_name 镜像源..."
# 根据不同的发行版和版本进行配置
case $OS in
centos)
configure_centos_mirror "$mirror_url" "$mirror_name"
;;
rocky|almalinux)
configure_rocky_mirror "$mirror_url" "$mirror_name"
;;
rhel)
print_warning "RHEL 系统需要订阅,建议使用官方源或配置本地源"
;;
esac
# 清理缓存并更新
print_info "清理缓存并更新..."
sudo yum clean all
sudo yum makecache
print_success "镜像源配置完成"
}
# 配置 CentOS 镜像源
configure_centos_mirror() {
local mirror_url="$1"
local mirror_name="$2"
# 禁用所有官方仓库
sudo sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/CentOS-*.repo
# 根据 CentOS 版本配置镜像源
case $OS_VERSION in
7)
sudo tee /etc/yum.repos.d/centos7.repo > /dev/null <<EOF
[base]
name=CentOS-\$releasever - Base
baseurl=$mirror_url/centos/\$releasever/os/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=1
[updates]
name=CentOS-\$releasever - Updates
baseurl=$mirror_url/centos/\$releasever/updates/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=1
[extras]
name=CentOS-\$releasever - Extras
baseurl=$mirror_url/centos/\$releasever/extras/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=1
[centosplus]
name=CentOS-\$releasever - Plus
baseurl=$mirror_url/centos/\$releasever/centosplus/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=0
EOF
;;
8|8.*)
sudo tee /etc/yum.repos.d/centos8.repo > /dev/null <<EOF
[BaseOS]
name=CentOS-\$releasever - Base
baseurl=$mirror_url/centos/\$releasever/BaseOS/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
enabled=1
[AppStream]
name=CentOS-\$releasever - AppStream
baseurl=$mirror_url/centos/\$releasever/AppStream/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
enabled=1
[extras]
name=CentOS-\$releasever - Extras
baseurl=$mirror_url/centos/\$releasever/extras/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
enabled=1
[PowerTools]
name=CentOS-\$releasever - PowerTools
baseurl=$mirror_url/centos/\$releasever/PowerTools/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
enabled=0
EOF
;;
*)
print_warning "CentOS $OS_VERSION 版本可能不受完全支持"
;;
esac
}
# 配置 Rocky Linux 镜像源
configure_rocky_mirror() {
local mirror_url="$1"
local mirror_name="$2"
# Rocky Linux 9+ 使用新的仓库结构
if [[ $OS_VERSION == 9* ]]; then
sudo tee /etc/yum.repos.d/rocky.repo > /dev/null <<EOF
[baseos]
name=Rocky Linux \$releasever - BaseOS
baseurl=$mirror_url/rocky/\$releasever/BaseOS/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
[appstream]
name=Rocky Linux \$releasever - AppStream
baseurl=$mirror_url/rocky/\$releasever/AppStream/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
[extras]
name=Rocky Linux \$releasever - Extras
baseurl=$mirror_url/rocky/\$releasever/extras/\$basearch/os/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
EOF
else
print_warning "Rocky Linux $OS_VERSION 版本使用默认配置"
fi
}
# 安装基础工具
install_basic_tools() {
print_info "正在安装基础工具..."
# 工具列表定义
local ubuntu_tools=(
curl wget git
vim nano
htop screen tmux
net-tools iputils-ping dnsutils
unzip zip tar gzip bzip2
build-essential
software-properties-common
apt-transport-https ca-certificates
gnupg lsb-release
tree ncdu
jq
python3 python3-pip
)
local centos_tools=(
curl wget git
vim nano
htop screen tmux
net-tools iproute
unzip zip tar gzip bzip2
gcc gcc-c++ make
epel-release
tree ncdu
jq
python3 python3-pip
)
# 询问用户是否自定义工具列表
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
echo ""
echo "默认安装以下工具:"
case $OS in
ubuntu|debian)
printf '%s\n' "${ubuntu_tools[@]}"
;;
centos|rhel|rocky|almalinux)
printf '%s\n' "${centos_tools[@]}"
;;
esac
echo ""
read -rp "是否安装这些工具? [Y/n]: " install_tools
install_tools=${install_tools:-Y}
if [[ ! $install_tools =~ ^[Yy]$ ]]; then
print_info "跳过基础工具安装"
return
fi
fi
# 安装工具
case $OS in
ubuntu|debian)
print_info "更新软件包列表..."
sudo apt-get update
print_info "安装 Ubuntu/Debian 工具包..."
sudo apt-get install -y "${ubuntu_tools[@]}" || {
print_warning "部分工具安装失败,继续执行..."
}
;;
centos|rhel|rocky|almalinux)
print_info "安装 EPEL 仓库..."
sudo yum install -y epel-release || true
print_info "安装 CentOS/RHEL 工具包..."
sudo yum install -y "${centos_tools[@]}" || {
print_warning "部分工具安装失败,继续执行..."
}
;;
esac
print_success "基础工具安装完成"
}
# 配置 SSH 服务
configure_ssh() {
print_info "正在配置 SSH 服务..."
# 检查是否安装 SSH 服务
if ! systemctl is-active sshd &> /dev/null && ! systemctl is-active ssh &> /dev/null; then
print_warning "SSH 服务未安装,正在安装..."
case $OS in
ubuntu|debian)
sudo apt-get install -y openssh-server
;;
centos|rhel|rocky|almalinux)
sudo yum install -y openssh-server
;;
esac
fi
# 询问是否配置 SSH
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
read -rp "是否优化 SSH 配置? [y/N]: " config_ssh
config_ssh=${config_ssh:-N}
if [[ ! $config_ssh =~ ^[Yy]$ ]]; then
print_info "跳过 SSH 配置"
return
fi
fi
# 备份 SSH 配置
local ssh_config_backup="/etc/ssh/sshd_config.backup-$(date +%Y%m%d)"
sudo cp /etc/ssh/sshd_config "$ssh_config_backup"
print_success "SSH 配置已备份到 $ssh_config_backup"
# SSH 优化配置参数
local ssh_config_changes=(
"# 优化 SSH 配置 - 修改于 $(date)"
"UseDNS no"
"GSSAPIAuthentication no"
"ClientAliveInterval 60"
"ClientAliveCountMax 3"
"MaxAuthTries 3"
"LoginGraceTime 60"
"PermitRootLogin prohibit-password"
"PasswordAuthentication yes"
"PubkeyAuthentication yes"
"AllowTcpForwarding yes"
"X11Forwarding no"
"PrintMotd no"
"PrintLastLog yes"
)
# 应用 SSH 配置
print_info "应用 SSH 优化配置..."
# 删除旧配置并添加新配置
for config_line in "${ssh_config_changes[@]}"; do
if [[ $config_line =~ ^[^#] ]]; then
local config_key=$(echo "$config_line" | awk '{print $1}')
sudo sed -i "/^$config_key/d" /etc/ssh/sshd_config
fi
done
# 添加新配置
for config_line in "${ssh_config_changes[@]}"; do
echo "$config_line" | sudo tee -a /etc/ssh/sshd_config > /dev/null
done
# 重启 SSH 服务
print_info "重启 SSH 服务..."
if command -v systemctl &> /dev/null; then
sudo systemctl daemon-reload
sudo systemctl restart sshd 2>/dev/null || sudo systemctl restart ssh 2>/dev/null
sudo systemctl enable sshd 2>/dev/null || sudo systemctl enable ssh 2>/dev/null
else
sudo service sshd restart 2>/dev/null || sudo service ssh restart 2>/dev/null
fi
print_success "SSH 配置优化完成"
}
# 配置时区
configure_timezone() {
print_info "正在配置时区..."
local current_tz=""
# 获取当前时区
if command -v timedatectl &> /dev/null; then
current_tz=$(timedatectl | grep "Time zone" | awk '{print $3}')
fi
print_info "当前时区: ${current_tz:-未知}"
# 询问是否设置时区
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
read -rp "是否设置为中国时区 (Asia/Shanghai)? [Y/n]: " set_tz
set_tz=${set_tz:-Y}
else
set_tz="Y"
fi
if [[ $set_tz =~ ^[Yy]$ ]]; then
# 尝试使用 timedatectl
if command -v timedatectl &> /dev/null; then
sudo timedatectl set-timezone Asia/Shanghai
else
# 备选方案:直接链接时区文件
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
if [[ -f /etc/redhat-release ]]; then
echo "ZONE=\"Asia/Shanghai\"" | sudo tee /etc/sysconfig/clock > /dev/null
fi
fi
# 同步硬件时钟
sudo hwclock --systohc 2>/dev/null || true
print_success "时区已设置为 Asia/Shanghai"
fi
}
# 配置语言环境
configure_locale() {
print_info "正在配置语言环境..."
# 询问是否配置中文语言环境
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
read -rp "是否配置中文语言环境? [y/N]: " set_locale
set_locale=${set_locale:-N}
if [[ ! $set_locale =~ ^[Yy]$ ]]; then
print_info "跳过语言环境配置"
return
fi
fi
case $OS in
ubuntu|debian)
# 安装中文语言包
sudo apt-get install -y language-pack-zh-hans
# 生成语言环境
sudo locale-gen zh_CN.UTF-8
sudo locale-gen zh_CN.GBK
sudo locale-gen zh_CN.GB2312
# 设置系统语言环境
sudo update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8
;;
centos|rhel|rocky|almalinux)
# 安装中文语言包
sudo yum install -y glibc-langpack-zh
# 设置语言环境
local lang_conf="/etc/locale.conf"
if [[ -f "$lang_conf" ]]; then
sudo sed -i 's/^LANG=.*/LANG="zh_CN.UTF-8"/' "$lang_conf"
else
echo 'LANG="zh_CN.UTF-8"' | sudo tee "$lang_conf" > /dev/null
fi
;;
esac
# 设置临时环境变量
export LANG=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8
print_success "中文语言环境配置完成"
}
# 系统优化配置
optimize_system() {
print_info "正在应用系统优化配置..."
# 询问是否进行系统优化
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
read -rp "是否应用系统优化配置? [Y/n]: " do_optimize
do_optimize=${do_optimize:-Y}
if [[ ! $do_optimize =~ ^[Yy]$ ]]; then
print_info "跳过系统优化"
return
fi
fi
# 1. 优化文件描述符限制
optimize_file_descriptors
# 2. 优化内核参数
optimize_kernel_params
# 3. 优化系统服务
optimize_services
# 4. 优化交换分区
optimize_swap
print_success "系统优化配置完成"
}
# 优化文件描述符限制
optimize_file_descriptors() {
print_info "优化文件描述符限制..."
local limits_conf="/etc/security/limits.conf"
# 备份原配置
sudo cp "$limits_conf" "${limits_conf}.backup-$(date +%Y%m%d)"
# 设置文件描述符限制
if ! grep -q "^\* soft nofile" "$limits_conf"; then
echo "* soft nofile 65535" | sudo tee -a "$limits_conf" > /dev/null
echo "* hard nofile 65535" | sudo tee -a "$limits_conf" > /dev/null
echo "root soft nofile 65535" | sudo tee -a "$limits_conf" > /dev/null
echo "root hard nofile 65535" | sudo tee -a "$limits_conf" > /dev/null
print_success "文件描述符限制已优化"
else
print_info "文件描述符限制已经配置"
fi
# 对于 systemd 系统
if [[ -d /etc/systemd/system ]]; then
local systemd_conf="/etc/systemd/system.conf"
sudo sed -i 's/^#DefaultLimitNOFILE=.*/DefaultLimitNOFILE=65535/' "$systemd_conf"
sudo sed -i 's/^#DefaultLimitNPROC=.*/DefaultLimitNPROC=65535/' "$systemd_conf"
fi
}
# 优化内核参数
optimize_kernel_params() {
print_info "优化内核参数..."
local sysctl_conf="/etc/sysctl.d/99-custom.conf"
# 创建优化配置文件
sudo tee "$sysctl_conf" > /dev/null <<'EOF'
# ========================
# 系统内核优化配置
# 生成时间: $(date)
# ========================
# 网络优化
# 最大连接数
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
# 缓冲区大小
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# TCP 优化
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_tw_buckets = 2000000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 30
# 连接跟踪
net.netfilter.nf_conntrack_max = 655350
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
# 文件系统优化
fs.file-max = 6553500
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 256
# 内存优化
vm.swappiness = 10
vm.vfs_cache_pressure = 50
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.overcommit_memory = 1
# IPv6 配置 (如果不需要可以禁用)
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
# 安全设置
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
EOF
# 重新加载 sysctl 配置
sudo sysctl -p "$sysctl_conf" > /dev/null 2>&1 || {
print_warning "部分内核参数优化失败,可能需要在重启后生效"
}
print_success "内核参数优化完成"
}
# 优化系统服务
optimize_services() {
print_info "优化系统服务..."
# 禁用不必要的服务(根据实际情况调整)
local services_to_disable=(
"postfix" # 邮件服务,如果不是邮件服务器
"avahi-daemon" # mDNS 服务
)
for service in "${services_to_disable[@]}"; do
if systemctl is-enabled "$service" &> /dev/null; then
sudo systemctl disable "$service" 2>/dev/null || true
sudo systemctl stop "$service" 2>/dev/null || true
print_info "已禁用服务: $service"
fi
done
}
# 优化交换分区
optimize_swap() {
print_info "优化交换分区..."
# 检查交换分区是否存在
if [[ $(swapon --show | wc -l) -eq 0 ]]; then
print_warning "未找到交换分区,如需创建请运行: sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile"
return
fi
# 调整 swappiness 值(如果已经在内核参数中设置过,这里不会重复设置)
local current_swappiness=$(cat /proc/sys/vm/swappiness 2>/dev/null || echo "60")
print_info "当前 swappiness 值: $current_swappiness"
}
# 清理系统
clean_system() {
print_info "正在清理系统..."
# 询问是否清理系统
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
read -rp "是否清理系统缓存和无用包? [Y/n]: " do_clean
do_clean=${do_clean:-Y}
if [[ ! $do_clean =~ ^[Yy]$ ]]; then
print_info "跳过系统清理"
return
fi
fi
case $OS in
ubuntu|debian)
print_info "清理 APT 缓存..."
sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo apt-get clean
# 清理旧内核
sudo apt-get purge -y $(dpkg -l | awk '/^ii linux-image-*/ && $2 !~ /'$(uname -r)'/ {print $2}') 2>/dev/null || true
# 清理日志文件保留最近7天
sudo find /var/log -type f -name "*.log" -mtime +7 -delete 2>/dev/null || true
;;
centos|rhel|rocky|almalinux)
print_info "清理 YUM 缓存..."
sudo yum autoremove -y
sudo yum clean all
# 清理旧内核保留最近2个
sudo package-cleanup --oldkernels --count=2 -y 2>/dev/null || true
# 清理日志文件
sudo journalctl --vacuum-time=7d 2>/dev/null || true
;;
esac
# 清理临时文件
print_info "清理临时文件..."
sudo rm -rf /tmp/* 2>/dev/null || true
sudo rm -rf /var/tmp/* 2>/dev/null || true
print_success "系统清理完成"
}
# 显示系统信息
show_system_info() {
echo ""
print_success "==================== 系统信息 ===================="
echo ""
# 操作系统信息
if [[ -f /etc/os-release ]]; then
echo "操作系统: $(grep PRETTY_NAME /etc/os-release | cut -d'"' -f2)"
fi
# 内核信息
echo "内核版本: $(uname -r)"
echo "系统架构: $(uname -m)"
# CPU 信息
if command -v nproc &> /dev/null; then
echo "CPU 核心: $(nproc)"
fi
# 内存信息
if command -v free &> /dev/null; then
echo "内存大小: $(free -h | awk '/^Mem:/ {print $2}')"
echo "可用内存: $(free -h | awk '/^Mem:/ {print $7}')"
fi
# 磁盘信息
if command -v df &> /dev/null; then
echo "根目录空间: $(df -h / | awk 'NR==2 {print $2 " 已用: " $3 " (" $5 ")"}')"
fi
# 系统负载
if [[ -f /proc/loadavg ]]; then
load=$(cat /proc/loadavg)
echo "系统负载: ${load:0:16}"
fi
# 运行时间
if command -v uptime &> /dev/null; then
echo "运行时间: $(uptime -p | sed 's/up //')"
fi
# 用户信息
echo "当前用户: $(whoami)"
echo "主机名称: $(hostname)"
# IP 地址信息
if command -v ip &> /dev/null; then
echo "IP 地址: $(ip route get 1 | awk '{print $7; exit}')"
elif command -v hostname &> /dev/null; then
echo "主机名: $(hostname -I 2>/dev/null | awk '{print $1}')"
fi
# 时区信息
if command -v timedatectl &> /dev/null; then
echo "时区设置: $(timedatectl | grep "Time zone" | awk '{print $3}')"
echo "NTP 同步: $(timedatectl | grep "NTP synchronized" | awk '{print $3}')"
fi
echo ""
print_success "=================================================="
echo ""
}
# 显示主菜单
show_menu() {
echo ""
echo "请选择要执行的操作:"
echo ""
echo "1) 完整初始化 (推荐)"
echo " - 更换镜像源"
echo " - 安装基础工具"
echo " - 系统优化"
echo " - SSH 配置"
echo " - 时区设置"
echo " - 系统清理"
echo ""
echo "2) 仅更换镜像源"
echo "3) 仅安装基础工具"
echo "4) 仅系统优化"
echo "5) 仅配置 SSH"
echo "6) 显示系统信息"
echo "7) 查看日志文件"
echo "8) 退出脚本"
echo ""
}
# 完整初始化流程
full_initialization() {
print_info "开始完整系统初始化..."
# 1. 备份原始配置
backup_sources
# 2. 配置镜像源
case $OS in
ubuntu|debian)
configure_ubuntu_mirrors || {
print_warning "镜像源配置失败,继续其他步骤..."
}
;;
centos|rhel|rocky|almalinux)
configure_centos_mirrors || {
print_warning "镜像源配置失败,继续其他步骤..."
}
;;
*)
print_warning "暂不支持该系统的镜像源配置"
;;
esac
# 3. 安装基础工具
install_basic_tools
# 4. 配置时区
configure_timezone
# 5. 配置语言环境(可选)
if [[ -z "${NON_INTERACTIVE:-}" ]]; then
configure_locale
fi
# 6. 配置 SSH
configure_ssh
# 7. 系统优化
optimize_system
# 8. 系统清理
clean_system
print_success "系统初始化完成!"
# 显示系统信息
show_system_info
# 显示后续建议
echo ""
print_info "建议执行以下操作:"
echo "1. 重启系统使所有配置生效: sudo reboot"
echo "2. 检查系统更新: sudo apt-get upgrade 或 sudo yum update"
echo "3. 查看详细日志: cat $LOG_FILE"
echo ""
}
# 查看日志文件
view_log_file() {
echo ""
print_info "日志文件内容 (最后50行):"
echo "=================================================="
tail -50 "$LOG_FILE"
echo "=================================================="
echo ""
print_info "完整日志文件路径: $LOG_FILE"
}
# 显示帮助信息
show_help() {
echo ""
echo "Linux 系统初始化脚本 v1.1"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " --auto 自动模式 (非交互式,使用默认配置)"
echo " --mirror=SOURCE 指定镜像源 (aliyun, tsinghua, ustc, huawei)"
echo " --non-interactive 非交互模式 (跳过所有确认)"
echo " --help 显示此帮助信息"
echo ""
echo "示例:"
echo " sudo $0 --auto"
echo " sudo $0 --mirror=aliyun --non-interactive"
echo ""
}
# 解析命令行参数
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
--auto)
AUTO_MODE=1
NON_INTERACTIVE=1
MIRROR_ARG="aliyun"
shift
;;
--mirror=*)
MIRROR_ARG="${1#*=}"
shift
;;
--non-interactive)
NON_INTERACTIVE=1
shift
;;
--help|-h)
show_help
exit 0
;;
*)
print_error "未知参数: $1"
show_help
exit 1
;;
esac
done
}
# 主函数
main() {
# 解析命令行参数
parse_arguments "$@"
# 显示横幅
print_banner
# 检查权限
check_permissions
# 检测操作系统
detect_os
# 检查必要命令
check_command "curl" || error_exit "curl 安装失败"
check_command "wget" || print_warning "wget 安装失败,部分功能可能受限"
# 自动模式直接执行完整初始化
if [[ -n "${AUTO_MODE:-}" ]]; then
full_initialization
exit 0
fi
# 交互式菜单
while true; do
show_menu
read -rp "请选择操作 [1-8]: " choice
case $choice in
1)
full_initialization
break
;;
2)
backup_sources
case $OS in
ubuntu|debian)
configure_ubuntu_mirrors
;;
centos|rhel|rocky|almalinux)
configure_centos_mirrors
;;
esac
;;
3)
install_basic_tools
;;
4)
optimize_system
;;
5)
configure_ssh
;;
6)
show_system_info
;;
7)
view_log_file
;;
8)
print_info "退出脚本"
echo "详细日志请查看: $LOG_FILE"
exit 0
;;
*)
print_warning "无效选择,请重新输入"
;;
esac
# 询问是否继续
if [[ $choice -ne 8 ]]; then
echo ""
read -rp "是否继续其他操作? [Y/n]: " continue_choice
continue_choice=${continue_choice:-Y}
if [[ ! $continue_choice =~ ^[Yy]$ ]]; then
print_info "退出脚本"
echo "详细日志请查看: $LOG_FILE"
exit 0
fi
fi
done
}
# 脚本入口点
main "$@"