本系列笔记面向有一定 Linux 基础的开发者和运维人员,旨在提供一份可直接复用的实操手册。每一篇都聚焦一个运维主题,内容以命令和配置为主,少废话,多干货。


一、系统信息查看

拿到一台新服务器,第一件事就是摸清它的"家底"。以下是最常用的系统信息查看命令。

1.1 内核与系统版本

# 查看内核版本
uname -r
# 输出示例: 5.15.0-78-generic

# 查看完整内核信息
uname -a

# 查看发行版信息(适用于 Ubuntu/Debian)
lsb_release -a

# 查看发行版信息(通用方法)
cat /etc/os-release

# 使用 hostnamectl 查看系统信息(systemd 系统)
hostnamectl

1.2 硬件资源概览

# CPU 信息
lscpu
# 重点关注: CPU(s)、Thread(s) per core、Model name

# 内存使用情况
free -h
# -h 人类可读格式,关注 available 列

# 磁盘使用情况
df -h
# 查看所有挂载点的使用率

# 磁盘分区信息
lsblk
# 查看磁盘和分区的树形结构

# 查看磁盘详细信息
fdisk -l

# 查看 PCI 设备
lspci

# 查看 USB 设备
lsusb

1.3 系统运行状态

# 系统运行时间和负载
uptime
# 输出: 10:30:00 up 45 days, load average: 0.15, 0.10, 0.05
# 三个数字分别是 1 分钟、5 分钟、15 分钟的平均负载

# 查看系统启动时间
who -b

# 查看当前登录用户
who
w

# 查看系统进程快照
top
# 交互命令: M 按内存排序、P 按 CPU 排序、q 退出

# 更好的 top 替代品
htop

二、用户与权限管理

2.1 用户管理基础

# 创建用户(-m 自动创建家目录,-s 指定 shell)
useradd -m -s /bin/bash deploy

# 设置密码
passwd deploy

# 创建用户并指定附加组
useradd -m -s /bin/bash -G sudo,docker deploy

# 删除用户(-r 同时删除家目录)
userdel -r deploy

# 查看用户信息
id deploy
# 输出: uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo)

# 查看所有用户
cat /etc/passwd | grep -v nologin | grep -v false

# 修改用户 shell
usermod -s /bin/zsh deploy

# 锁定/解锁用户
usermod -L deploy   # 锁定
usermod -U deploy   # 解锁

2.2 用户组管理

# 创建用户组
groupadd devops

# 将用户添加到组(-a 追加,不覆盖已有组)
usermod -aG devops deploy

# 查看用户所属组
groups deploy

# 查看所有组
cat /etc/group

2.3 sudo 配置

# 使用 visudo 编辑 sudo 配置(语法检查,防止锁死系统)
visudo

# 常用配置示例

# 允许用户 deploy 执行所有命令(需要密码)
deploy ALL=(ALL:ALL) ALL

# 允许用户 deploy 免密执行所有命令
deploy ALL=(ALL:ALL) NOPASSWD: ALL

# 允许 devops 组免密执行所有命令
%devops ALL=(ALL:ALL) NOPASSWD: ALL

# 只允许特定命令免密
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/docker

# 推荐:将自定义配置放在 /etc/sudoers.d/ 目录下
echo 'deploy ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/deploy
chmod 440 /etc/sudoers.d/deploy

⚠️ 注意: 永远使用 visudo 编辑 sudo 配置,它会在保存时检查语法。直接编辑 /etc/sudoers 文件可能导致语法错误,进而锁死 sudo 功能。


三、SSH 安全加固

SSH 是服务器的第一道防线,必须加固。

3.1 密钥认证

# 在本地机器生成密钥对(推荐 Ed25519)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 生成文件: ~/.ssh/id_ed25519 (私钥) 和 ~/.ssh/id_ed25519.pub (公钥)

# 将公钥复制到服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip

# 或者手动复制
cat ~/.ssh/id_ed25519.pub | ssh user@server_ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# 设置正确的权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

3.2 SSH 服务端安全配置

编辑 /etc/ssh/sshd_config

# 修改默认端口(减少自动化扫描攻击)
Port 2222

# 禁用 root 登录
PermitRootLogin no

# 禁用密码认证(确保密钥已配置)
PasswordAuthentication no

# 禁用空密码
PermitEmptyPasswords no

# 只允许特定用户登录
AllowUsers deploy admin

# 限制最大尝试次数
MaxAuthTries 3

# 登录超时时间(秒)
LoginGraceTime 60

# 禁用 X11 转发
X11Forwarding no

# 禁用 TCP 转发(按需开启)
AllowTcpForwarding no

# 启用严格模式
StrictModes yes

# 使用 SSH 协议 2
Protocol 2

# 设置日志级别
LogLevel VERBOSE

修改完成后重启 SSH 服务:

systemctl restart sshd
# ⚠️ 先保持当前连接不断开,新开终端测试新配置是否正常

3.3 fail2ban 防暴力破解

# 安装 fail2ban
apt install fail2ban -y       # Debian/Ubuntu
yum install fail2ban -y       # CentOS/RHEL

# 创建本地配置文件(不要直接修改 jail.conf)
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# 封禁时间(秒)
bantime = 3600
# 检测时间窗口(秒)
findtime = 600
# 最大失败次数
maxretry = 5
# 使用 systemd 日志
backend = systemd

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
EOF

# 启动并设置开机自启
systemctl enable --now fail2ban

# 查看 fail2ban 状态
fail2ban-client status sshd

# 手动封禁 IP
fail2ban-client set sshd banip 192.168.1.100

# 手动解封 IP
fail2ban-client set sshd unbanip 192.168.1.100

四、防火墙基础

4.1 UFW(Ubuntu/Debian 推荐)

# 启用防火墙
ufw enable

# 默认策略:拒绝入站,允许出站
ufw default deny incoming
ufw default allow outgoing

# 允许特定端口
ufw allow 2222/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'

# 允许特定 IP 访问特定端口
ufw allow from 192.168.1.0/24 to any port 3306 comment 'MySQL from LAN'

# 允许特定 IP 所有流量
ufw allow from 192.168.1.100

# 删除规则(先查看编号)
ufw status numbered
ufw delete 3

# 查看状态
ufw status verbose

# 重置防火墙
ufw reset

4.2 firewalld(CentOS/RHEL 推荐)

# 查看状态
firewall-cmd --state

# 查看当前规则
firewall-cmd --list-all

# 添加端口(--permanent 永久生效)
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp

# 添加服务
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

# 删除规则
firewall-cmd --permanent --remove-port=2222/tcp

# 重新加载规则
firewall-cmd --reload

# 查看所有可用服务
firewall-cmd --get-services

# 添加富规则(高级)
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'

4.3 iptables 常用规则

# 查看当前规则
iptables -L -n -v

# 允许已建立的连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 允许回环接口
iptables -A INPUT -i lo -j ACCEPT

# 允许 SSH
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 允许 ICMP(ping)
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# 丢弃其他入站流量
iptables -P INPUT DROP

# 保存规则(Ubuntu)
iptables-save > /etc/iptables/rules.v4

# 保存规则(CentOS)
service iptables save

五、系统基础配置

5.1 时区设置

# 查看当前时区
timedatectl

# 列出可用时区
timedatectl list-timezones | grep Asia

# 设置时区
timedatectl set-timezone Asia/Shanghai

# 或者通过软链接设置
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

5.2 主机名设置

# 查看主机名
hostnamectl

# 设置主机名
hostnamectl set-hostname prod-web-01

# 验证
hostname
cat /etc/hostname

5.3 系统语言与 Locale

# 查看当前 locale
locale

# 生成 locale
locale-gen en_US.UTF-8 zh_CN.UTF-8

# 设置默认 locale
update-locale LANG=en_US.UTF-8

# 或编辑 /etc/default/locale
cat > /etc/default/locale << 'EOF'
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
EOF

5.4 NTP 时间同步

# 安装 chrony(推荐,比 ntpd 更现代)
apt install chrony -y       # Debian/Ubuntu
yum install chrony -y       # CentOS/RHEL

# 配置 NTP 服务器
cat > /etc/chrony/chrony.conf << 'EOF'
# 国内 NTP 服务器
server ntp.aliyun.com iburst
server cn.ntp.org.cn iburst
server time.windows.com iburst

# 允许本地网络同步
allow 192.168.0.0/16

# 快速同步(首次启动时偏差较大)
makestep 1.0 3
EOF

# 启动并设置开机自启
systemctl enable --now chronyd

# 查看同步状态
chronyc tracking
chronyc sources -v

5.5 ulimit 调整

# 查看当前限制
ulimit -a

# 查看当前用户的软限制
ulimit -Sn

# 查看当前用户的硬限制
ulimit -Hn

# 临时调整(当前会话)
ulimit -n 65535

# 永久调整:编辑 /etc/security/limits.conf
cat >> /etc/security/limits.conf << 'EOF'
# 提高文件描述符限制
* soft nofile 65535
* hard nofile 65535
root soft nofile 65535
root hard nofile 65535

# 提高进程数限制
* soft nproc 65535
* hard nproc 65535

# 提高 core dump 大小限制
* soft core unlimited
* hard core unlimited
EOF

# 确保 PAM 加载 limits 模块
grep pam_limits.so /etc/pam.d/common-session || echo "session required pam_limits.so" >> /etc/pam.d/common-session

# systemd 服务的限制需要单独配置
mkdir -p /etc/systemd/system/nginx.service.d/
cat > /etc/systemd/system/nginx.service.d/limits.conf << 'EOF'
[Service]
LimitNOFILE=65535
EOF
systemctl daemon-reload

六、包管理

6.1 APT(Debian/Ubuntu)

# 更新包索引
apt update

# 升级所有已安装的包
apt upgrade -y

# 安全更新(只安装安全补丁)
apt list --upgradable
apt upgrade -y -o Dpkg::Options::="--force-confold"

# 安装包
apt install -y nginx curl wget vim htop tree

# 卸载包(保留配置文件)
apt remove nginx

# 卸载包(同时删除配置文件)
apt purge nginx

# 清理不再需要的依赖
apt autoremove -y

# 搜索包
apt search nginx

# 查看包信息
apt show nginx

# 查看已安装的包
dpkg -l | grep nginx

# 添加 PPA 源(Ubuntu)
add-apt-repository ppa:ondrej/php
apt update

# 添加第三方源(以 Docker 为例)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
apt update

6.2 YUM/DNF(CentOS/RHEL)

# 更新所有包
yum update -y
# 或使用 dnf(CentOS 8+/RHEL 8+)
dnf update -y

# 安装包
yum install -y nginx curl wget vim htop

# 卸载包
yum remove nginx

# 搜索包
yum search nginx

# 查看包信息
yum info nginx

# 查看已安装的包
yum list installed | grep nginx

# 清理缓存
yum clean all

# 添加 EPEL 源
yum install -y epel-release

# 添加第三方源(以 Docker 为例)
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

6.3 自动安全更新

Ubuntu/Debian(unattended-upgrades):

# 安装
apt install -y unattended-upgrades

# 启用自动安全更新
dpkg-reconfigure -plow unattended-upgrades

# 或手动配置
cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
EOF

# 配置自动更新频率
cat > /etc/apt/apt.conf.d/20auto-upgrades << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
EOF

CentOS/RHEL(yum-cron):

# 安装
yum install -y yum-cron

# 配置
sed -i 's/update_cmd = default/update_cmd = security/' /etc/yum/yum-cron.conf
sed -i 's/apply_updates = no/apply_updates = yes/' /etc/yum/yum-cron.conf

# 启动
systemctl enable --now yum-cron

七、磁盘与文件系统

7.1 磁盘查看

# 查看所有块设备
lsblk

# 查看磁盘详细信息
fdisk -l

# 查看文件系统类型和使用率
df -Th

# 查看目录大小
du -sh /var/log
du -sh /var/log/*

# 查找大文件
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null

7.2 磁盘分区与格式化

# 使用 fdisk 分区(MBR 格式)
fdisk /dev/sdb
# 交互命令: n(新建) → p(主分区) → 1(分区号) → w(写入)

# 使用 gdisk 分区(GPT 格式,推荐大磁盘)
gdisk /dev/sdb

# 格式化分区
mkfs.ext4 /dev/sdb1
mkfs.xfs /dev/sdb1     # CentOS 推荐

# 创建挂载点并挂载
mkdir -p /data
mount /dev/sdb1 /data

# 写入 fstab 实现开机自动挂载
echo '/dev/sdb1 /data ext4 defaults,noatime 0 2' >> /etc/fstab

# 验证 fstab 配置
mount -a

7.3 LVM 基础

# 创建物理卷(PV)
pvcreate /dev/sdb /dev/sdc

# 查看物理卷
pvs

# 创建卷组(VG)
vgcreate data_vg /dev/sdb /dev/sdc

# 查看卷组
vgs

# 创建逻辑卷(LV)
lvcreate -L 100G -n data_lv data_vg
# 或使用百分比
lvcreate -l 100%FREE -n data_lv data_vg

# 查看逻辑卷
lvs

# 格式化并挂载
mkfs.ext4 /dev/data_vg/data_lv
mkdir -p /data
mount /dev/data_vg/data_lv /data

# 扩容逻辑卷(LVM 的核心优势)
lvextend -L +50G /dev/data_vg/data_lv
resize2fs /dev/data_vg/data_lv   # ext4
xfs_growfs /data                   # xfs

# 一条命令完成扩容+文件系统调整
lvextend -r -L +50G /dev/data_vg/data_lv

7.4 Swap 配置

# 查看当前 swap
swapon --show
free -h

# 创建 swap 文件(推荐这种方式,比分区更灵活)
fallocate -l 4G /swapfile
# 如果 fallocate 不可用
dd if=/dev/zero of=/swapfile bs=1M count=4096

# 设置权限(必须是 600)
chmod 600 /swapfile

# 格式化为 swap
mkswap /swapfile

# 启用 swap
swapon /swapfile

# 写入 fstab 实现开机自动启用
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# 调整 swappiness(控制内核使用 swap 的倾向,值越低越倾向使用内存)
sysctl vm.swappiness=10
echo 'vm.swappiness=10' >> /etc/sysctl.conf

# 调整 vfs_cache_pressure(控制内核回收缓存的倾向)
sysctl vm.vfs_cache_pressure=50
echo 'vm.vfs_cache_pressure=50' >> /etc/sysctl.conf

八、网络基础

8.1 网络接口与 IP

# 查看网络接口和 IP 地址(推荐)
ip addr show
# 简写
ip a

# 查看特定接口
ip addr show eth0

# 查看路由表
ip route show

# 添加路由
ip route add 10.0.0.0/8 via 192.168.1.1

# 查看默认网关
ip route | grep default

# 临时添加 IP
ip addr add 192.168.1.100/24 dev eth0

# 启用/禁用接口
ip link set eth0 up
ip link set eth0 down

8.2 网络连接与端口

# 查看监听端口(推荐 ss,比 netstat 更快)
ss -tlnp
# -t TCP, -l 监听, -n 数字显示, -p 显示进程

# 查看所有连接
ss -tanp

# 查看特定端口
ss -tlnp | grep :80

# 旧版 netstat(需要安装 net-tools)
netstat -tlnp
netstat -anp | grep :80

# 查看端口被哪个进程占用
lsof -i :80
fuser 80/tcp

8.3 网络诊断

# ping 测试连通性
ping -c 4 8.8.8.8

# traceroute 路由追踪
traceroute google.com
# 或使用 mtr(更强大,实时更新)
mtr google.com

# DNS 查询
dig google.com
dig +short google.com
dig @8.8.8.8 google.com

# DNS 反向查询
dig -x 8.8.8.8

# nslookup(简单查询)
nslookup google.com

# TCP 端口测试
nc -zv google.com 443
# 或使用 telnet
telnet google.com 443

8.4 HTTP 工具

# curl 基本用法
curl https://example.com
curl -O https://example.com/file.zip          # 下载文件
curl -I https://example.com                    # 只获取响应头
curl -v https://example.com                    # 详细输出
curl -X POST -d '{"key":"value"}' -H "Content-Type: application/json" https://api.example.com

# curl 带超时
curl --connect-timeout 5 --max-time 30 https://example.com

# wget 下载
wget https://example.com/file.zip
wget -c https://example.com/file.zip           # 断点续传
wget -r -l 2 https://example.com               # 递归下载(深度 2)
wget -q -O file.zip https://example.com/file.zip  # 静默下载

8.5 DNS 配置

# 查看当前 DNS 配置
cat /etc/resolv.conf

# 临时修改 DNS
echo "nameserver 223.5.5.5" > /etc/resolv.conf
echo "nameserver 8.8.8.8" >> /etc/resolv.conf

# 使用 systemd-resolved 配置(推荐)
cat > /etc/systemd/resolved.conf << 'EOF'
[Resolve]
DNS=223.5.5.5 8.8.8.8
FallbackDNS=114.114.114.114
EOF
systemctl restart systemd-resolved

# 本地 hosts 文件
cat >> /etc/hosts << 'EOF'
192.168.1.100 app-server
192.168.1.101 db-server
EOF

九、系统初始化清单

新服务器上线前,请逐项检查以下清单。

9.1 基础安全

  • 修改 SSH 默认端口

  • 创建运维用户,配置 sudo

  • 配置 SSH 密钥认证

  • 禁用 root 远程登录

  • 禁用密码认证

  • 安装并配置 fail2ban

  • 配置防火墙,只开放必要端口

  • 设置登录告警

9.2 系统配置

  • 设置正确的时区

  • 配置 NTP 时间同步

  • 设置主机名

  • 配置系统语言

  • 调整 ulimit 限制

  • 配置 swap(内存不足时)

  • 更新系统内核和软件包

9.3 网络配置

  • 配置 DNS 服务器

  • 配置 hosts 文件(如有需要)

  • 测试外网连通性

  • 测试内网连通性

  • 配置网络带宽监控

9.4 存储配置

  • 检查磁盘分区和挂载

  • 配置 fstab 自动挂载

  • 配置日志轮转(logrotate)

  • 设置磁盘使用率告警

  • 清理不必要的文件

9.5 监控与备份

  • 安装监控 agent(如 Prometheus Node Exporter)

  • 配置系统日志收集

  • 配置关键目录备份

  • 测试备份恢复流程

  • 记录服务器信息到 CMDB


附录:新服务器初始化脚本模板

以下脚本整合了上述所有初始化步骤,可根据实际需求修改后使用。

#!/bin/bash
#============================================================
# 新服务器初始化脚本
# 适用于: Ubuntu 20.04/22.04, Debian 11/12
# 使用方法: sudo bash init-server.sh
#============================================================

set -euo pipefail

#============================================================
# 配置变量(根据实际情况修改)
#============================================================
NEW_USER="deploy"
SSH_PORT="2222"
TIMEZONE="Asia/Shanghai"
HOSTNAME="prod-server-01"
SWAP_SIZE="4G"          # 设置为 0 则不创建 swap
FAIL2BAN_BANTIME="86400"
FAIL2BAN_MAXRETRY="3"

# 允许登录的用户列表(空格分隔)
ALLOW_USERS="deploy"

# 需要安装的软件包列表
PACKAGES="curl wget vim htop tree net-tools lsof unzip git chrony fail2ban ufw"

#============================================================
# 颜色输出
#============================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log_info()  { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

#============================================================
# 前置检查
#============================================================
if [[ $EUID -ne 0 ]]; then
    log_error "请使用 root 用户运行此脚本"
    exit 1
fi

log_info "开始初始化服务器..."
echo "=========================================="
echo "  主机名: ${HOSTNAME}"
echo "  SSH 端口: ${SSH_PORT}"
echo "  时区: ${TIMEZONE}"
echo "  新用户: ${NEW_USER}"
echo "  Swap 大小: ${SWAP_SIZE}"
echo "=========================================="
read -p "确认以上配置?(y/n): " confirm
if [[ "$confirm" != "y" ]]; then
    log_error "用户取消操作"
    exit 1
fi

#============================================================
# 1. 系统基础配置
#============================================================
log_info "[1/8] 配置系统基础设置..."

# 设置主机名
hostnamectl set-hostname "${HOSTNAME}"
echo "127.0.0.1 ${HOSTNAME}" >> /etc/hosts

# 设置时区
timedatectl set-timezone "${TIMEZONE}"

# 配置 locale
locale-gen en_US.UTF-8
update-locale LANG=en_US.UTF-8

# 调整 ulimit
cat >> /etc/security/limits.conf << 'EOF'
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
root soft nofile 65535
root hard nofile 65535
EOF

# 调整内核参数
cat >> /etc/sysctl.conf << 'EOF'
# 网络优化
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30

# 内存优化
vm.swappiness = 10
vm.vfs_cache_pressure = 50

# 安全加固
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
EOF
sysctl -p

#============================================================
# 2. 创建用户
#============================================================
log_info "[2/8] 创建运维用户..."

if id "${NEW_USER}" &>/dev/null; then
    log_warn "用户 ${NEW_USER} 已存在,跳过创建"
else
    useradd -m -s /bin/bash -G sudo "${NEW_USER}"
    log_warn "请手动设置用户密码: passwd ${NEW_USER}"
fi

# 配置免密 sudo
echo "${NEW_USER} ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/${NEW_USER}
chmod 440 /etc/sudoers.d/${NEW_USER}

#============================================================
# 3. 安装软件包
#============================================================
log_info "[3/8] 更新系统并安装软件包..."

apt update
apt upgrade -y
apt install -y ${PACKAGES}

#============================================================
# 4. 配置 Swap
#============================================================
log_info "[4/8] 配置 Swap..."

if [[ "${SWAP_SIZE}" != "0" ]]; then
    if [[ -f /swapfile ]]; then
        log_warn "Swap 文件已存在,跳过创建"
    else
        fallocate -l "${SWAP_SIZE}" /swapfile
        chmod 600 /swapfile
        mkswap /swapfile
        swapon /swapfile
        echo '/swapfile none swap sw 0 0' >> /etc/fstab
        log_info "Swap 已创建: ${SWAP_SIZE}"
    fi
else
    log_info "跳过 Swap 创建"
fi

#============================================================
# 5. 配置 NTP 时间同步
#============================================================
log_info "[5/8] 配置时间同步..."

cat > /etc/chrony/chrony.conf << 'EOF'
server ntp.aliyun.com iburst
server cn.ntp.org.cn iburst
server time.windows.com iburst
makestep 1.0 3
rtcsync
EOF
systemctl enable --now chronyd

#============================================================
# 6. 配置 SSH 安全
#============================================================
log_info "[6/8] 配置 SSH 安全..."

# 备份原始配置
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S)

cat > /etc/ssh/sshd_config.d/hardening.conf << EOF
Port ${SSH_PORT}
PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
AllowUsers ${ALLOW_USERS}
MaxAuthTries 3
LoginGraceTime 60
X11Forwarding no
StrictModes yes
LogLevel VERBOSE
ClientAliveInterval 300
ClientAliveCountMax 2
EOF

systemctl restart sshd
log_warn "SSH 已重启,新端口: ${SSH_PORT}"

#============================================================
# 7. 配置防火墙
#============================================================
log_info "[7/8] 配置防火墙..."

ufw default deny incoming
ufw default allow outgoing
ufw allow "${SSH_PORT}/tcp" comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
echo "y" | ufw enable

#============================================================
# 8. 配置 fail2ban
#============================================================
log_info "[8/8] 配置 fail2ban..."

cat > /etc/fail2ban/jail.local << EOF
[DEFAULT]
bantime = ${FAIL2BAN_BANTIME}
findtime = 600
maxretry = ${FAIL2BAN_MAXRETRY}
backend = systemd

[sshd]
enabled = true
port = ${SSH_PORT}
filter = sshd
maxretry = ${FAIL2BAN_MAXRETRY}
bantime = ${FAIL2BAN_BANTIME}
EOF

systemctl enable --now fail2ban

#============================================================
# 完成
#============================================================
echo ""
echo "=========================================="
log_info "服务器初始化完成!"
echo "=========================================="
echo ""
echo "重要提醒:"
echo "  1. 请确保已配置 SSH 密钥认证后再断开当前连接"
echo "  2. 请手动设置用户密码: passwd ${NEW_USER}"
echo "  3. SSH 新端口: ${SSH_PORT}"
echo "  4. 防火墙已启用,请确认端口配置正确"
echo ""
echo "验证命令:"
echo "  ssh -p ${SSH_PORT} ${NEW_USER}@$(hostname -I | awk '{print $1}')"
echo ""

💡 使用提示: 将此脚本保存为 init-server.sh,根据实际环境修改顶部的配置变量,然后在新服务器上执行 sudo bash init-server.sh。建议先在测试环境验证后再用于生产服务器。