4.13 Linux 服务器初始化标准流程

预计阅读时间:11 分钟

📖 目录

学习目标

学完本章后,你将能够:

  • 理解服务器初始化标准化的必要性——一致性、可审计、自动化基础
  • 按规范设置主机名、时区、系统更新和 swap
  • 配置 UFW 防火墙和 SSH 加固
  • 创建管理员用户并部署 SSH 密钥认证
  • 安装并配置 fail2ban、监控 agent 和备份脚本
  • 编写一份完整的一键初始化脚本

前置知识

核心知识

  • 主机名规范——${角色}-${环境}-${编号}.${域名},如 web-prod-01.example.com
  • 时区与 NTP——timedatectl 设置时区,chrony/systemd-timesyncd 同步时间
  • unattended-upgrades——自动安装安全更新,减少漏洞窗口
  • swap——磁盘模拟内存,防止 OOM;云服务器通常建议关闭或设置固定大小
  • UFW 默认拒绝——白名单防火墙:只放行明确需要的端口
  • SSH 加固——禁用 root 登录、禁用密码认证、仅密钥登录、限 MaxAuthTries
  • 管理员用户——非 root 用户 + sudo 权限 + SSH 公钥部署
  • fail2ban——日志驱动的动态防火墙,自动封禁暴力破解 IP
  • node_exporter——Prometheus 生态的节点指标暴露器(CPU/内存/磁盘/网络)
  • 备份三要素——备份什么(文件/DB)、存哪里(本地/远程)、怎么恢复(验证流程)

知识关联

原理讲解

为什么要标准化

假设团队有 5 个人,每人用自己的方式初始化新服务器:A 用 SSH 默认端口、B 改成了 2222、C 忘了开防火墙、D 的备份只存本地磁盘、E 的 root 密码贴在 Wiki 上。三个月后出故障排查时,每台服务器的配置都不一样,无法快速定位问题。

标准化的价值体现在三个维度:

  • 一致性(Consistency)——每台服务器从诞生起就遵循同一套配置基线,消除"这台和那台不一样"的隐患
  • 审计轨迹(Audit Trail)——初始化过程可记录、可复现。出了问题可以回答"这台机器最初是怎么配的"
  • 自动化基础(Automation Foundation)——有了标准流程,就能写成脚本 -> 做成 Ansible role -> 纳入 CI/CD Pipeline

10 步初始化流程概览

步骤操作目的
Step 1设置主机名标识服务器角色,便于管理
Step 2配置时区与时间同步日志时间一致,避免时间偏差
Step 3系统更新 + 自动安全更新修复已知漏洞
Step 4配置 swap内存压力缓冲
Step 5创建管理员用户 + 部署 SSH 密钥安全远程管理
Step 6SSH 加固缩小攻击面
Step 7配置 UFW 防火墙默认拒绝入站流量
Step 8安装 fail2ban动态防护暴力破解
Step 9安装监控 agent采集性能指标
Step 10配置备份数据恢复能力

示例代码

以下是一个完整的 Ubuntu 24.04 一键初始化脚本。按阶段组织,可直接在 root 用户下执行。建议先逐段理解,再整体运行。

完整初始化脚本

#!/bin/bash
set -euo pipefail

# ==============================================
# Stage 0: 变量定义 & 前置检查
# ==============================================
NEW_HOSTNAME="web-prod-01.example.com"
TIMEZONE="Asia/Shanghai"
ADMIN_USER="ops"
ADMIN_SSH_KEY="ssh-ed25519 AAAAC3... your-public-key-here"
SWAP_SIZE_MB=2048

# 仅在非 root 时提示
if [ "$(id -u)" -ne 0 ]; then
    echo "请以 root 身份运行" >&2
    exit 1
fi

# ==============================================
# Stage 1: 主机名
# ==============================================
echo "[1/10] 设置主机名..."
hostnamectl set-hostname "$NEW_HOSTNAME"
sed -i "/127.0.1.1/d" /etc/hosts
echo "127.0.1.1 $NEW_HOSTNAME" >> /etc/hosts

# ==============================================
# Stage 2: 时区与时间同步
# ==============================================
echo "[2/10] 配置时区与时间同步..."
timedatectl set-timezone "$TIMEZONE"
timedatectl set-ntp true
# 验证
timedatectl status  # 输出: Local time: Wed 2026-07-30 02:00:00 CST

# ==============================================
# Stage 3: 系统更新 & 自动安全更新
# ==============================================
echo "[3/10] 系统更新..."
apt update && apt upgrade -y
apt install -y unattended-upgrades
dpkg-reconfigure -f noninteractive unattended-upgrades

# ==============================================
# Stage 4: Swap 配置
# ==============================================
echo "[4/10] 配置 swap..."
if swapon --show | grep -q .; then
    echo "swap 已存在,跳过"
else
    fallocate -l ${SWAP_SIZE_MB}M /swapfile
    chmod 600 /swapfile
    mkswap /swapfile
    swapon /swapfile
    echo '/swapfile none swap sw 0 0' >> /etc/fstab
    # 降低 swappiness(优先使用内存)
    sysctl vm.swappiness=10  # 输出: vm.swappiness = 10
    echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.conf
fi

# ==============================================
# Stage 5: 创建管理员用户 & SSH 密钥
# ==============================================
echo "[5/10] 创建管理员用户..."
if id "$ADMIN_USER" &>/dev/null; then
    echo "用户 $ADMIN_USER 已存在"
else
    useradd -m -s /bin/bash -G sudo "$ADMIN_USER"
    passwd -l "$ADMIN_USER"   # 锁定密码(仅密钥登录)
fi
mkdir -p /home/$ADMIN_USER/.ssh
echo "$ADMIN_SSH_KEY" > /home/$ADMIN_USER/.ssh/authorized_keys
chmod 700 /home/$ADMIN_USER/.ssh
chmod 600 /home/$ADMIN_USER/.ssh/authorized_keys
chown -R $ADMIN_USER:$ADMIN_USER /home/$ADMIN_USER/.ssh

# ==============================================
# Stage 6: SSH 加固
# ==============================================
echo "[6/10] SSH 加固..."
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sed -i 's/^#\?MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config
sed -i 's/^#\?ClientAliveInterval.*/ClientAliveInterval 300/' /etc/ssh/sshd_config
sed -i 's/^#\?ClientAliveCountMax.*/ClientAliveCountMax 2/' /etc/ssh/sshd_config
# 白名单:仅允许管理员用户登录
echo "AllowUsers $ADMIN_USER" >> /etc/ssh/sshd_config
ssh-keygen -A   # 确保主机密钥存在  # 输出: ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
sshd -t && systemctl reload sshd  # 输出: (无错误则静默成功)

# ==============================================
# Stage 7: UFW 防火墙
# ==============================================
echo "[7/10] 配置 UFW 防火墙..."
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp comment 'SSH'
# 按需放行其他端口,例如:
# ufw allow 80/tcp comment 'HTTP'
# ufw allow 443/tcp comment 'HTTPS'
ufw --force enable
ufw status verbose  # 输出: Status: active\nLogging: on (low)\nDefault: deny (incoming)...

# ==============================================
# Stage 8: fail2ban
# ==============================================
echo "[8/10] 安装 fail2ban..."
apt install -y fail2ban
cat > /etc/fail2ban/jail.local << 'F2BEOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400
F2BEOF
systemctl enable --now fail2ban  # 输出: Created symlink /etc/systemd/system/multi-user.target.wants/fail2ban.service

# ==============================================
# Stage 9: 监控 agent(node_exporter)
# ==============================================
echo "[9/10] 安装 node_exporter..."
NODE_EXPORTER_VER="1.9.0"
wget -q "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VER}/node_exporter-${NODE_EXPORTER_VER}.linux-amd64.tar.gz"
tar xzf "node_exporter-${NODE_EXPORTER_VER}.linux-amd64.tar.gz"
cp "node_exporter-${NODE_EXPORTER_VER}.linux-amd64/node_exporter" /usr/local/bin/
rm -rf "node_exporter-${NODE_EXPORTER_VER}.linux-amd64"*

# 创建 systemd 单元
cat > /etc/systemd/system/node_exporter.service << 'NEEOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target

[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/usr/local/bin/node_exporter
Restart=on-failure

[Install]
WantedBy=multi-user.target
NEEOF
systemctl daemon-reload
systemctl enable --now node_exporter  # 输出: Created symlink /etc/systemd/system/multi-user.target.wants/node_exporter.service

# ==============================================
# Stage 10: 备份配置
# ==============================================
echo "[10/10] 配置备份..."
mkdir -p /var/backups/scripts

cat > /var/backups/scripts/backup.sh << 'BKPEOF'
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/var/backups/daily"
DATE=$(date +%F)
mkdir -p "$BACKUP_DIR"

# 备份关键配置
tar czf "$BACKUP_DIR/etc-$DATE.tar.gz" /etc/ssh/sshd_config /etc/fail2ban /etc/ufw /etc/sysctl.d/

# 备份应用数据(示例)
# tar czf "$BACKUP_DIR/app-$DATE.tar.gz" /var/www /var/lib/mysql

# 保留最近 30 天
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete

# 推送远程(示例:rsync to backup-server)
# rsync -avz "$BACKUP_DIR/" backup@10.0.0.100:/backups/$(hostname)/
BKPEOF
chmod +x /var/backups/scripts/backup.sh

# 写入 cron(每天凌晨 2:00 执行)
echo "0 2 * * * root /var/backups/scripts/backup.sh" > /etc/cron.d/server-backup

# ==============================================
echo "✅ 初始化完成!建议重启服务器以确认所有配置生效。"
echo "⚠️  在断开当前 SSH 前请用另一个终端验证密钥登录:"
echo "   ssh ${ADMIN_USER}@"

常见错误

错误表现根因正确做法
运行初始化脚本后 SSH 断开无法再连接SSH 加固后密钥未部署正确即退出Step 5 和 Step 6 必须先验证新用户密钥登录再 reload sshd;脚本中建议在末尾重置 SSHD 连接前留出验证窗口
ufw enable 后 SSH 被拒UFW 默认 deny incoming 生效,但忘记 allow 22ufw allow 22/tcp 之后再 ufw enable
fail2ban 把自己封了开发机从同一 IP 频繁测试触发规则jail.local 中加入 ignoreip = 你的本机IP
swap 文件权限错误导致无法使用fallocate 生成的文件权限为 644必须 chmod 600 /swapfile,否则 mkswap 会告警或拒绝
node_exporter 无法绑定端口低版本运行 User=nobody 时权限不足使用 CapabilityBoundingSet=CAP_NET_BIND_SERVICE 或允许 nobody 监听非特权端口
时间同步失效,日志时间偏差大仅设了时区,未启用 NTP 或 chrony 未运行timedatectl set-ntp true 或安装 chronysystemctl enable --now chrony

最佳实践

实践原理示例
主机名纳入 CMDB每台服务器的主机名、IP、用途、负责人记录到 CMDB 或 Ansible inventoryweb-prod-01 ansible_host=10.0.0.1 role=web env=prod
初始化脚本版本化管理脚本存入 Git 仓库,变更走 PR 审查git tag v1.2.0 对应某次基线变更
SSH CA 替代手动部署密钥服务器端配置 TrustedUserCAKeys,用户证书集中签发,吊销即时生效TrustedUserCAKeys /etc/ssh/ca.pub
swap 根据内存大小动态计算物理内存 < 2GB → swap = 2x 内存;2-8GB → swap = 1x;> 8GB → swap = 4-8GB脚本中根据 free -m 结果自动计算 SWAP_SIZE_MB
备份必须验证恢复没有验证的备份等于没有备份每月执行一次恢复演练:tar xzf backup.tar.gz -C /tmp/restore-test
初始化日志留存记录首次初始化的完整输出,便于后续排查"基线漂移"bash init.sh | tee /var/log/init-$(date +%F).log

练习题

  1. (概念)标准化初始化的三个核心价值是什么?为什么说没有标准化就无法自动化?
  2. (概念)为什么新服务器要先更新系统再对外开放?如果顺序反过来会有什么风险?
  3. (实操)在一台干净的 Ubuntu 虚拟机上运行本章的初始化脚本。在运行 Step 6(SSH 加固)之前,故意将 ADMIN_SSH_KEY 设为空字符串,然后运行到结束——会出现什么情况?如何修复?
  4. (实操)修改脚本中的 UFW 规则,使其同时放行 HTTP (80) 和 HTTPS (443),并在防火墙状态输出中用 comment 标注每条规则的作用。验证 ufw status numbered 输出。
  5. (🔍 挑战)将本章的 bash 初始化脚本改写成 Ansible playbook(参见 4.1:Ansible 自动化)。要求:使用 hostname module、ufw module、user module,且 SSH 密钥通过 authorized_key module 管理。运行 playbook 实现幂等初始化。
点击查看答案
  1. 一致性(每台服务器配置相同)、审计轨迹(初始化过程可复现)、自动化基础(标准流程才能写成脚本/Ansible)。没有标准化就无法用同一套自动化工具管理所有机器。
  2. 新服务器可能有已知漏洞,先更新再对外开放可缩小被攻击窗口。若顺序反过来——开放后再更新——服务器在更新完成前可能已被扫描和入侵。
  3. SSH 加固(Step 6)会关闭密码认证和 root 登录,但 ADMIN_SSH_KEY 为空,导致无任何有效认证方式,SSH 连接永久断开。修复:通过云控制台 VNC/串口登录,重新设置密钥并修复 sshd_config。
  4. 添加 ufw allow 80/tcp comment 'HTTP'ufw allow 443/tcp comment 'HTTPS'。运行 ufw status numbered 应看到每条规则前有序号和 comment 字段。
  5. Ansible playbook 用 hostname: module、ufw: module、user: module、authorized_key: module、fail2ban: 等。幂等性由各 module 自身的 check mode 保证,多次执行结果一致。

学习检查点

学完本章后,请检验自己是否掌握以下内容:

检查项自测问题验证方法
概念理解能用自己的话解释服务器初始化的目的和关键步骤尝试向他人讲解
命令操作能不查文档完成服务器初始化脚本编写、配置执行在终端实际执行
原理掌握能说出服务器初始化的安全考虑和最佳实践画出流程图
故障排查能独立排查初始化脚本执行失败、配置错误模拟故障并修复
最佳实践能说明为什么需要为服务器初始化配置审计和验证对比不同方案

本章总结

服务器初始化标准化是运维自动化的第一块基石。10 步流程覆盖了从基础配置(主机名、时区、swap)到安全加固(SSH、UFW、fail2ban)再到持续运维(监控、备份)的完整链路。脚本化之后,一台新服务器从"裸机"到"可上线"的时间可以从小时级压缩到分钟级,且每台服务器的配置保持一致。

速查表

命令/操作用途
hostnamectl set-hostname <名>设置主机名
timedatectl set-timezone Asia/Shanghai设置时区
timedatectl set-ntp true启用 NTP 时间同步
ufw default deny incoming防火墙默认拒绝入站
ufw allow 22/tcp放行 SSH 端口
ufw --force enable启用防火墙(非交互)
fail2ban-client status sshd查看 SSH 封禁统计
sshd -t检查 sshd_config 语法
systemctl reload sshd重载 SSH 配置
passwd -l <用户>锁定用户密码(仅密钥登录)
vm.swappiness=10降低 swap 倾向性

学习路径建议

延伸阅读

常见问题

新服务器初始化顺序有最佳实践吗?
推荐顺序:① 更新系统(apt update && apt upgrade -y);② 设置主机名和时区(timedatectl set-timezone Asia/Shanghai);③ 创建管理员用户并添加 SSH 密钥;④ 配置 SSH 加固(端口、PermitRootLogin no、PubkeyAuthentication yes);⑤ 安装和配置防火墙(ufw);⑥ 安装 fail2ban;⑦ 开启自动安全更新;⑧ 配置监控(Prometheus node_exporter)。
服务器开了哪些端口怎么快速检查?
ss -tlnp(TCP 监听)和 ss -ulnp(UDP 监听)显示所有开放端口和对应的进程。nmap localhost 从外部视角扫描本机开放端口。netstat -tulpn 是传统方式(需 apt install net-tools)。建议关闭不需要的服务对应端口,减少攻击面。
Swap 分区设多大合适?
旧规则是 RAM × 2。现代服务器推荐:RAM < 2GB 设 2×RAM,RAM 2-8GB 设等于 RAM,RAM > 8GB 设 4-8GB(或 0 如果不需要休眠)。K8s 节点建议禁用 swap(kubelet 要求)。云服务器可以创建 swap 文件替代分区,方便动态调整大小。
↑ 回到顶部