运维脚本示例:安全、告警与系统初始化
侧重思路说明与可运行示例;生产环境务必替换路径、账号与策略。
一、访问频率异常与自动封禁 IP(iptables)
思路:从 Nginx 访问日志中截取最近一段时间内的请求,统计同一 IP 出现次数超过阈值则认为是异常,若 iptables 中尚未丢弃该 IP,则添加 DROP 并记录日志。
shell
#!/bin/bash
DATE=$(date +%d/%b/%Y:%H:%M)
LOG_FILE=/usr/local/nginx/logs/demo2.access.log
ABNORMAL_IP=$(tail -n5000 $LOG_FILE |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>10)print i}')
for IP in $ABNORMAL_IP; do
if [ "$(iptables -vnL | grep -c -- "$IP")" -eq 0 ]; then
iptables -I INPUT -s "$IP" -j DROP
echo "$(date +'%F_%T') $IP" >> /tmp/drop_ip.log
fi
done补充说明
DATE与日志里的时间格式必须一致,否则grep筛不出数据。- 阈值 10、tail 5000 仅为示例,误封真实用户的风险始终存在;更稳妥的做法是结合业务告警、人工复核或使用 fail2ban 等成熟方案。
- 云主机往往还有安全组;本机
iptables与云端策略需一致考虑。 - IPv6、CDN、反向代理场景下「第一层看到的 IP」可能是代理 IP,需配合
X-Forwarded-For与可信代理列表(脚本未涵盖)。
二、邮件告警(mailx)
示例通过配置 mailx 使用 SMTP 发信。以下为示意配置,切勿把真实密码写入仓库。
shell
# yum install mailx
# vi /etc/mail.rc
set from=alert@example.com smtp=smtp.example.com
set smtp-auth-user=alert@example.com smtp-auth-password=YOUR_SMTP_AUTH_CODE
set smtp-auth=login补充
- 多数邮箱要求 客户端专用密码 或 授权码,不是网页登录密码。
- 更安全的做法:用环境变量或独立权限只有 root 可读的配置文件注入密码,并限制文件权限。
- 其他告警通道:企业微信/钉钉 Webhook、PagerDuty、自建 Prometheus Alertmanager 等,Shell 往往只负责调用
curlPOST JSON。
三、新装机初始化(时区、安全、内核与工具)
下列脚本摘自教程示例,面向 RHEL/CentOS 系(yum、/etc/redhat-release)。在其他发行版上需改包管理器与路径。
shell
#!/bin/bash
# 设置时区(优先 timedatectl;失败时再回退到软链)
timedatectl set-timezone Asia/Shanghai 2>/dev/null || {
rm -f /etc/localtime
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
}
# 时间同步:示例仍用 ntpdate;新系统请优先 chrony(systemctl enable --now chronyd)
if ! crontab -l 2>/dev/null | grep -q ntpdate; then
(echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1"; crontab -l 2>/dev/null) | crontab -
fi
# 禁用 SELinux(重启后完全生效;请按当前值核对,勿盲目执行)
sed -i.bak 's/^SELINUX=enforcing/SELINUX=disabled/; s/^SELINUX=permissive/SELINUX=disabled/' /etc/selinux/config
# 关闭防火墙
if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then
systemctl stop firewalld
systemctl disable firewalld
elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then
service iptables stop
chkconfig iptables off
fi
# 历史命令显示操作时间
if ! grep -q HISTTIMEFORMAT /etc/bashrc; then
echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc
fi
# SSH超时时间
if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
echo "export TMOUT=600" >> /etc/profile
fi
# 禁止root远程登录
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# 禁止定时任务向发送邮件
sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab
# 设置最大打开文件数
if ! grep -Fq "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then
cat >> /etc/security/limits.conf << EOF
* soft nofile 65535
* hard nofile 65535
EOF
fi
# 系统内核优化
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_tw_buckets = 20480
net.ipv4.tcp_max_syn_backlog = 20480
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_fin_timeout = 20
EOF
# 减少SWAP使用
echo "0" > /proc/sys/vm/swappiness
# 安装系统性能分析工具及其他
yum install -y gcc make autoconf vim sysstat net-tools iostat iftop iotop lrzsz补充说明
- 版号判断脚本里用
egrep "7.[0-9]"/6.[0-9]"仅为示例;AlmaLinux / Rocky 8、9 等不会命中,需改为VERSION_ID(/etc/os-release)或systemctl判断 firewalld 是否存在。 - PermitRootLogin:若
sshd_config已是prohibit-password等,需人工核对,勿依赖单行sed万能替换。 - SELinux 改为
disabled需重启才完全生效;也可先permissive排查。 - 禁止 root SSH:请先确认已有 sudo 用户可登录,避免把自己锁在外面。
- ntpdate 已逐渐被 chrony(
chronyd)取代,新项目建议调研发行版默认时间同步方案。 - 正文中包名已写为
iotop;若仓库无某包,删除对应名称即可。 grep "* soft nofile":已改为grep -F匹配字面量*;若仍失败请直接人工检查limits.conf。
四、与本系列其他文档的关系
- 批量 SSH、数据库备份、Nginx 日志等见同目录下后续章节。
- Shell 语言基础见上级目录
01~06合并文档。
