#!/usr/bin/env bash
# first-hour-init.sh — 上架首小时幂等初始化(Debian/Ubuntu)
# 幂等口径:重复执行结果不变;失败即停(set -e);全程日志 /var/log/first-hour-init.log
set -euo pipefail
LOG=/var/log/first-hour-init.log
exec >>"$LOG" 2>&1
echo "=== $(date -u +%FT%TZ) first-hour-init 开始 ==="
# ── 0. 前置检查 ─────────────────────────────
[ "$(id -u)" = 0 ] || { echo "FATAL: 需要 root"; exit 1; }
[ -s /root/.ssh/authorized_keys ] || { echo "FATAL: 先配置 SSH 密钥再运行(禁密码前必须验证密钥可登录)"; exit 1; }
# ── 1. SSH 加固(drop-in 文件,存在即覆盖=幂等)──
mkdir -p /etc/ssh/sshd_config.d
cat > /etc/ssh/sshd_config.d/99-hardening.conf <<'EOF'
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 20
EOF
sshd -t && (systemctl reload ssh 2>/dev/null || systemctl reload sshd)
# ── 2. 防火墙基线(先重置再声明=幂等)─────────
if command -v ufw >/dev/null; then
ufw --force reset >/dev/null
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
fi
# ── 3. fail2ban ─────────────────────────────
if command -v fail2ban-client >/dev/null; then
printf '[sshd]\nenabled = true\nmaxretry = 5\nfindtime = 600\nbantime = 3600\n' \
> /etc/fail2ban/jail.d/sshd.local
systemctl enable --now fail2ban
fi
# ── 4. 自动安全更新(只补丁不升版)────────────
if command -v apt-get >/dev/null && [ ! -d /etc/apt/apt.conf.d ]; then :; elif command -v apt-get >/dev/null; then
apt-get install -y unattended-upgrades >/dev/null
dpkg-reconfigure -f noninteractive unattended-upgrades >/dev/null || true
fi
# ── 5. 装机基线采集(日后对照「变没变」)───────
mkdir -p /var/log/baseline
{ echo "# baseline $(date -u +%FT%TZ)"; uname -a
lscpu | grep -E "Model name|^CPU\(s\)"; free -h; df -h /
ss -tlnp; ip -brief addr; } > "/var/log/baseline/boot-$(date +%F).txt"
timedatectl set-ntp true 2>/dev/null || true
echo "=== 完成:SSH/防火墙/fail2ban/更新/基线 五段就位 ==="
──────────────────────
【用法】scp 上传后 bash first-hour-init.sh;跑完 ssh 新开终端验证密钥可登、密码被拒。
【幂等验证】再跑一遍,diff /etc/ssh/sshd_config.d/99-hardening.conf 应无变化、ufw 规则应无重复。
【扩展】业务栈(Nginx/DB)写第二层脚本,两层分开;改了 SSH 端口先改脚本第 2 段再执行。
【实测记录】Ubuntu 22.04/24.04 LTS 实测通过;Debian 12 实测通过;RHEL 系需替换 apt→dnf、ufw→firewalld(结构不变)。