Linux 常用脚本教程
在 VPS 或云服务器上搭建网站,脚本化操作不仅能提高效率,还能保证一致性和可重复性。本文将全面介绍 Linux 环境下各阶段所需的 Bash 脚本、Ansible 自动化、CI/CD 脚本等,从服务器初始化、安全加固、软件安装、网站部署到运维监控,覆盖网站全生命周期管理。
📑 目录
| 序号 | 章节 | 核心内容 |
|---|---|---|
| 1 | 服务器初始化脚本 | 时区、系统更新、用户创建、SSH 配置 |
| 2 | 安全加固脚本 | UFW 防火墙、Fail2ban、SSH 加固 |
| 3 | 环境安装脚本 | LAMP/LEMP、Node.js/PM2 |
| 4 | 网站自动化部署脚本 | Git 部署、Ansible 剧本 |
| 5 | SSL 证书自动续期 | Certbot + Crontab 定时续期 |
| 6 | 备份与恢复脚本 | 数据库备份、文件同步 |
| 7 | 日志管理与切割 | logrotate 日志轮转 |
| 8 | 监控与告警脚本 | 磁盘告警、服务状态检查 |
| 9 | 定时任务示例 | Crontab 实战配置 |
| 10 | 常见优化建议 | 错误处理、参数化、权限控制 |
| 11 | Docker 容器部署 | 一键构建运行容器 |
| 12 | Kubernetes 部署 | kubectl 滚动更新 |
| 13 | 性能优化脚本 | 内核调优、Nginx 性能优化 |
| 14 | 高级监控脚本 | 容器资源监控、网络连接监控 |
| 15 | 自动化测试脚本 | 单元测试、API 测试、负载测试 |
| 16 | 灾难恢复脚本 | 数据库+文件一键恢复 |
| 17 | 多服务器管理 | 批量 SSH 操作多节点 |
| 18 | 证书管理脚本 | 多格式证书生成与分发 |
| 19 | 零停机部署 | 蓝绿部署策略 |
| 20 | 自动化安全扫描 | Lynis + ClamAV + Nikto |
| 21 | 网络调试命令 | ss/netstat/tcpdump/mtr |
1. 服务器初始化脚本
首次购买 VPS 后的第一步:更新系统、设置时区、创建新用户并配置 SSH 公钥登录、关闭 root 直连。
#!/usr/bin/env bash
# server_init.sh — 服务器初始化
set -euo pipefail
# 1. 设置时区
timedatectl set-timezone Asia/Shanghai
echo "✅ 时区已设置为 Asia/Shanghai"
# 2. 更新系统
apt update && apt -y upgrade # Debian/Ubuntu
# yum update -y # RHEL/CentOS
echo "✅ 系统已更新"
# 3. 安装基本工具
apt install -y vim wget curl git ufw
echo "✅ 基本工具已安装"
# 4. 创建新用户
read -p "请输入新用户名: " USERNAME
groupadd sudo
useradd -m -s /bin/bash -G sudo $USERNAME
echo "✅ 用户 $USERNAME 已创建"
# 5. 配置 SSH 公钥登录
mkdir -p /home/$USERNAME/.ssh
read -p "请输入公钥内容: " PUBKEY
echo $PUBKEY > /home/$USERNAME/.ssh/authorized_keys
chmod 700 /home/$USERNAME/.ssh
chmod 600 /home/$USERNAME/.ssh/authorized_keys
chown -R $USERNAME:$USERNAME /home/$USERNAME/.ssh
echo "✅ SSH 公钥已配置"
# 6. 禁用 root 密码登录
sed -i 's/^PermitRootLogin .*/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart sshd
echo "✅ root 密码登录已禁用"
echo ""
echo "🎉 初始化完成!用户 $USERNAME 已创建并配置 SSH 登录。"
💡 此脚本完成了基础环境准备,接下来可在同一脚本中添加防火墙规则。
2. 安全加固脚本
安全加固主要包含防火墙(UFW/iptables)、Fail2ban、SSH 限制等。
#!/usr/bin/env bash
# security_hardening.sh — 安全加固
set -euo pipefail
# 1. 配置 UFW 防火墙
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw --force enable
echo "✅ UFW 防火墙已启用"
# 2. 安装并配置 Fail2ban
apt install -y fail2ban
cat > /etc/fail2ban/jail.local <<'EOF'
[sshd]
enabled = true
port = 22
filter = sshd
action = iptables[name=SSH, port=22, protocol=tcp]
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 600
EOF
systemctl enable --now fail2ban
systemctl restart fail2ban
echo "✅ Fail2ban 已配置(5 次失败封禁 1 小时)"
# 3. 修改 SSH 默认端口
NEW_PORT=2222
sed -i "s/#Port 22/Port $NEW_PORT/" /etc/ssh/sshd_config
ufw allow $NEW_PORT/tcp
systemctl restart sshd
echo "✅ SSH 端口已修改为 $NEW_PORT"
echo ""
echo "🔒 安全加固完成!请手动验证 SSH 新端口是否可正常连接。"
安全加固检查清单
| 项目 | 说明 | 状态 |
|---|---|---|
| UFW 防火墙 | 仅开放必要端口 | ✅ |
| Fail2ban | 防暴力破解 | ✅ |
| SSH 端口修改 | 降低被扫描风险 | ✅ |
| Root 禁止密码登录 | 强制密钥认证 | ✅ |
3. 环境安装脚本
3.1 LAMP 环境(Linux + Apache + MariaDB + PHP)
#!/usr/bin/env bash
# install_lamp.sh — LAMP 环境一键安装
set -euo pipefail
apt update
# 安装 Apache, MariaDB, PHP
apt install -y apache2 mariadb-server php \
php-mysql libapache2-mod-php \
php-curl php-gd php-mbstring php-xml php-zip
# 启动并开机自启
systemctl enable --now apache2 mariadb
# 初始化数据库安全(自动设置 root 密码)
mysql_secure_installation <<EOF
Y
root_password
root_password
Y
Y
Y
Y
EOF
# 测试 PHP
cat > /var/www/html/info.php <<'PHPEOF'
<?php phpinfo(); ?>
PHPEOF
echo ""
echo "🎉 LAMP 环境安装完成!"
echo " 访问 http://$(curl -s ifconfig.me)/info.php 查看 PHP 信息"
LEMP 环境(Nginx + MariaDB + PHP-FPM)
#!/usr/bin/env bash
# install_lemp.sh — LEMP 环境一键安装
set -euo pipefail
apt update
apt install -y nginx mariadb-server php-fpm php-mysql \
php-curl php-gd php-mbstring php-xml php-zip
# 启动并开机自启
systemctl enable --now nginx mariadb php*-fpm
# 配置 Nginx 站点
cat > /etc/nginx/sites-available/default <<'NGINXEOF'
server {
listen 80 default_server;
server_name _;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php*-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
NGINXEOF
nginx -t && systemctl reload nginx
echo ""
echo "🎉 LEMP 环境安装完成!请将网站文件放入 /var/www/html"
3.2 Node.js & PM2 环境
#!/usr/bin/env bash
# install_node_pm2.sh — Node.js + PM2 环境
set -euo pipefail
apt update
# 安装 Node.js LTS (20.x)
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
# 验证版本
echo "Node.js 版本: $(node -v)"
echo "npm 版本: $(npm -v)"
# 安装 PM2 进程管理器
npm install -g pm2
# 配置 PM2 开机自启
pm2 startup systemd -u $(whoami) --hp $(eval echo ~$(whoami)) >> /tmp/pm2_startup.log 2>&1 || true
env PATH=$PATH:/usr/bin pm2 save
echo ""
echo "🎉 Node.js & PM2 环境配置完成!"
echo " 使用 'pm2 start app.js --name my-app' 启动应用"
echo " 使用 'pm2 status' 查看进程状态"
4. 网站自动化部署脚本
4.1 Git 部署脚本
简单的拉取代码 → 安装依赖 → 重启服务流程:
#!/usr/bin/env bash
# deploy.sh — Git 自动化部署
set -euo pipefail
APP_DIR=/var/www/html/your-app
BRANCH=main
LOG_FILE="/var/log/deploy_$(date +%Y%m%d_%H%M%S).log"
exec > >(tee "$LOG_FILE") 2>&1
echo "========================================="
echo " 开始部署 — $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================="
cd $APP_DIR
# 1. 拉取最新代码
echo "[1/4] 拉取最新代码..."
git fetch origin
git reset --hard origin/$BRANCH
# 2. 依赖安装 & 构建
echo "[2/4] 安装依赖..."
if [ -f package.json ]; then
npm ci --production=false && npm run build
elif [ -f composer.json ]; then
composer install --no-dev --optimize-autoloader
elif [ -f requirements.txt ]; then
pip install -r requirements.txt
fi
# 3. 数据库迁移(可选)
echo "[3/4] 数据库迁移..."
if [ -f artisan ]; then
php artisan migrate --force
fi
# 4. 重启服务
echo "[4/4] 重启服务..."
pm2 restart my-app 2>/dev/null || true # Node.js 服务
systemctl restart php*-fpm 2>/dev/null || true # PHP-FPM
systemctl reload nginx 2>/dev/null || true # Nginx
echo ""
echo "✅ 部署完成!分支 $BRANCH 的最新代码已上线"
echo " 日志文件: $LOG_FILE"
4.2 Ansible 自动化剧本
Ansible 剧本将多台服务器统一管理,可定义安装、配置、部署流程。
# site.yml — Ansible 主剧本
---
- hosts: webservers
become: yes
vars:
app_repo: 'git@github.com:your/repo.git'
app_path: '/var/www/html/your-app'
domain: 'example.com'
tasks:
- name: 更新 apt 缓存
apt: update_cache=yes cache_valid_time=86400
- name: 安装必要软件
apt:
name:
- nginx
- git
- php-fpm
- nodejs
- npm
state: present
- name: 拉取应用代码
git:
repo: '{{ app_repo }}'
dest: '{{ app_path }}'
version: 'main'
force: yes
- name: 安装 Node.js 依赖
npm:
path: '{{ app_path }}'
production: false
- name: 构建前端资源
command: npm run build
args:
chdir: '{{ app_path }}'
- name: 配置 Nginx 站点
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/{{ domain }}
notify: reload nginx
- name: 启用站点
file:
src: /etc/nginx/sites-available/{{ domain }}
dest: /etc/nginx/sites-enabled/{{ domain }}
state: link
- name: 启动 PM2 应用
command: pm2 restart all
args:
chdir: '{{ app_path }}'
handlers:
- name: reload nginx
service: name=nginx state=reloaded
# 使用方式:
ansible-playbook -i inventory site.yml
5. SSL 证书自动续期脚本
使用 Certbot 获取并续期 Let's Encrypt 免费证书。
#!/usr/bin/env bash
# ssl_renew.sh — SSL 证书自动续期
set -euo pipefail
DOMAIN="example.com"
EMAIL="admin@example.com"
echo "开始证书续期 — $(date '+%Y-%m-%d %H:%M:%S')"
# 1. 停止 Nginx(释放 80 端口给 standalone)
systemctl stop nginx
# 2. 获取或续期证书
certbot certonly --standalone \
-d $DOMAIN -d www.$DOMAIN \
-m $EMAIL --agree-tos --non-interactive
# 3. 合并证书(可选,用于某些场景)
CERT_DIR="/etc/letsencrypt/live/$DOMAIN"
cat "$CERT_DIR/fullchain.pem" "$CERT_DIR/privkey.pem" \
> "/etc/nginx/ssl/${DOMAIN}.pem"
# 4. 启动 Nginx
systemctl start nginx
echo "✅ 证书续期完成!时间: $(date '+%F %T')"
# 添加到 Crontab(每 60 天凌晨 3 点执行):
0 3 */60 * * /path/to/ssl_renew.sh >> /var/log/ssl_renew.log 2>&1
6. 备份与恢复脚本
6.1 数据库自动备份
#!/usr/bin/env bash
# db_backup.sh — MySQL/MariaDB 自动备份
set -euo pipefail
DB_USER=root
DB_PASS=your_password
DB_NAME=your_db
BACKUP_ROOT=/backup/mysql
DATE=$(date +"%F")
BACKUP_DIR="$BACKUP_ROOT/$DATE"
RETENTION_DAYS=7
mkdir -p $BACKUP_DIR
# 执行备份(带压缩)
mysqldump -u$DB_USER -p$DB_PASS \
--single-transaction \
--routines \
--triggers \
$DB_NAME | gzip > "$BACKUP_DIR/${DB_NAME}_$(date +"%H%M").sql.gz"
echo "✅ 数据库备份完成: $BACKUP_DIR"
# 清理过期备份
find $BACKUP_ROOT -type f -mtime +$RETENTION_DAYS -exec rm {} \;
# 可选:同步到远程服务器
# rsync -az --delete $BACKUP_DIR user@backup-server:/remote/backup/mysql/
echo "🗂️ 过期备份已清理(保留最近 $RETENTION_DAYS 天)"
6.2 文件同步备份
#!/usr/bin/env bash
# file_backup.sh — 文件增量同步备份
set -euo pipefail
SOURCE_DIR=/var/www/html
DEST_USER=backup
DEST_HOST=backup.example.com
DEST_DIR=/remote/backup/www
LOG_FILE="/var/log/file_backup_$(date +%Y%m%d).log"
rsync -avz \
--delete \
--exclude='node_modules/' \
--exclude='.git/' \
--exclude='*.log' \
--progress \
$SOURCE_DIR $DEST_USER@$DEST_HOST:$DEST_DIR \
| tee "$LOG_FILE"
echo "✅ 文件同步完成: $SOURCE_DIR -> $DEST_HOST:$DEST_DIR"
7. 日志管理与日志切割脚本
使用
logrotate管理日志,防止磁盘空间耗尽。
# /etc/logrotate.d/nginx — Nginx 日志轮转配置
/var/log/nginx/*.log {
daily # 每天轮转
rotate 14 # 保留 14 个历史文件
missingok # 文件不存在不报错
compress # 压缩旧日志
delaycompress # 延迟压缩(当前一个不解压)
notifempty # 空文件不轮转
create 0640 www-data adm
sharedscripts
postrotate
systemctl reload nginx > /dev/null
endscript
}
# 自定义应用日志轮转示例
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0644 www-data www-data
postrotate
# 发送信号让应用重新打开日志文件
kill -USR1 $(cat /var/run/myapp.pid 2>/dev/null) 2>/dev/null || true
endscript
}
⚠️ 对于自定义日志,在
/etc/logrotate.d/中添加对应配置文件即可生效。可用logrotate -df /etc/logrotate.d/myapp测试配置。
8. 监控与告警脚本
8.1 磁盘使用率监控
#!/usr/bin/env bash
# disk_alert.sh — 磁盘使用率告警
THRESHOLD=80
ALERT_EMAIL="admin@example.com"
df -H | grep -vE '^Filesystem|tmpfs|cdrom' \
| awk '{ print $5 " " $1 }' \
| while read output; do
usep=$(echo $output | awk '{ print $1}' | sed 's/%//')
partition=$(echo $output | awk '{ print $2 }')
if [ $usep -ge $THRESHOLD ]; then
echo "⚠️ Warning: Partition $partition usage is at ${usep}%!" \
| mail -s "🚨 Disk Alert: ${usep}% used on $partition" $ALERT_EMAIL
fi
done
8.2 服务状态检查
#!/usr/bin/env bash
# service_check.sh — 关键服务健康检查
ALERT_EMAIL="admin@example.com"
SERVICES=(nginx mariadb php*-fpm pm2)
for SERVICE in "${SERVICES[@]}"; do
if ! systemctl is-active --quiet $SERVICE; then
echo "❌ 服务 $SERVICE 已停止于 $(date '+%Y-%m-%d %H:%M:%S')" \
| mail -s "🚨 Service Down: $SERVICE" $ALERT_EMAIL
# 尝试自动重启
systemctl restart $SERVICE 2>/dev/null || true
else
echo "✅ $SERVICE: running"
fi
done
🔔 将以上脚本放入 Cron 定时执行即可实现基础告警。
9. 定时任务(Crontab)示例
# 编辑 crontab: crontab -e
# 格式: 分 时 日 月 周 命令
# ──── 系统维护 ────
0 2 * * * /usr/bin/apt update && /usr/bin/apt -y upgrade # 每日凌晨 2 点系统更新
0 3 * * 0 /usr/bin/apt autoremove -y # 每周日凌晨 3 点清理无用包
# ──── 监控告警 ────
0 * * * * /path/to/disk_alert.sh # 每小时磁盘检查
*/15 * * * * /path/to/service_check.sh # 每 15 分钟服务检查
# ──── 备份任务 ────
0 1 * * * /path/to/db_backup.sh # 每日 1 点数据库备份
30 2 * * * /path/to/file_backup.sh # 每日 2:30 文件同步
# ──── 证书 & 部署 ────
30 3 */60 * * /path/to/ssl_renew.sh # 每 60 天续期证书
0 4 * * 1-5 /path/to/deploy.sh # 工作日早上 4 点自动部署
Cron 快速参考表
| 字段 | 取值范围 | 说明 |
|---|---|---|
| 分 | 0-59 | 分钟 |
| 时 | 0-23 | 小时 |
| 日 | 1-31 | 日期 |
| 月 | 1-12 | 月份 |
| 周 | 0-7 | 星期(0 和 7 都代表周日) |
10. 常见脚本优化建议
| 建议 | 说明 | 示例 |
|---|---|---|
| 错误处理 | 关键命令后加 || exit 1 或 set -e | set -euo pipefail |
| 日志输出 | 统一输出到日志文件 | exec >> /var/log/script.log 2>&1 |
| 参数化 | 可变参数提取为变量或命令行传入 | ./deploy.sh --branch main --env prod |
| 注释文档 | 包含用途说明、参数说明及运行示例 | 脚本头部写清楚用途和用法 |
| 权限控制 | 谨慎使用 sudo,文件权限建议 700 | chmod 700 deploy.sh |
| 幂等性 | 脚本可重复执行且结果一致 | 先判断再操作,避免重复安装 |
| 回滚机制 | 部署失败时能快速回退 | 保留上一版本的备份 |
11. Docker 容器部署脚本
#!/usr/bin/env bash
# deploy_docker.sh — Docker 容器一键部署
set -euo pipefail
IMAGE_NAME=your-app
CONTAINER_NAME=your-app-container
HOST_PORT=80
CONTAINER_PORT=8000
VOLUME_MOUNT="/host/path:/container/path"
echo "========================================="
echo " Docker 容器部署 — $(date)"
echo "========================================="
# 1. 停止并删除旧容器
docker rm -f $CONTAINER_NAME 2>/dev/null || true
# 2. 清理悬空镜像
docker image prune -f 2>/dev/null || true
# 3. 构建新镜像
docker build -t $IMAGE_NAME .
# 4. 运行容器
docker run -d \
--name $CONTAINER_NAME \
--restart=unless-stopped \
-p $HOST_PORT:$CONTAINER_PORT \
-v $VOLUME_MOUNT \
--env-file .env \
--memory="512m" \
--cpus="1.0" \
$IMAGE_NAME
# 5. 健康检查
sleep 3
echo ""
echo "📊 容器状态:"
docker ps -f name=$CONTAINER_NAME --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo "📋 最近日志:"
docker logs --tail 20 $CONTAINER_NAME
echo ""
echo "🎉 Docker 容器部署完成!访问 http://$(hostname -I | awk '{print $1}'):$HOST_PORT"
12. Kubernetes 部署脚本
#!/usr/bin/env bash
# deploy_k8s.sh — K8s 滚动更新部署
set -euo pipefail
NAMESPACE=production
DEPLOYMENT=web-app
echo "========================================="
echo " Kubernetes 部署 — $(date)"
echo "========================================="
# 1. 应用配置
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/deployment.yaml --namespace=$NAMESPACE
kubectl apply -f k8s/service.yaml --namespace=$NAMESPACE
# 2. 滚动更新
kubectl rollout restart deployment/$DEPLOYMENT --namespace=$NAMESPACE
# 3. 监控更新状态(超时 300 秒)
kubectl rollout status deployment/$DEPLOYMENT \
--namespace=$NAMESPACE \
--timeout=300s
# 4. 输出状态信息
echo ""
echo "🌐 Service 信息:"
kubectl get svc -n $NAMESPACE -l app=$DEPLOYMENT
echo ""
echo "📦 Pod 状态:"
kubectl get pods -n $NAMESPACE -l app=$DEPLOYMENT \
--sort-by='.status.containerStatuses[0].restartCount'
echo ""
echo "🎉 Kubernetes 部署完成!"
13. 性能优化脚本
13.1 内核参数优化
#!/usr/bin/env bash
# tune_kernel.sh — Linux 内核性能调优
set -euo pipefail
# 备份当前配置
cp /etc/sysctl.conf /etc/sysctl.conf.bak_$(date +%F)
cat <<EOF | tee -a /etc/sysctl.conf
# ========== 网络性能优化 ==========
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 4096
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.ip_local_port_range = 1024 65535
# ========== 内存优化 ==========
vm.swappiness = 10
vm.overcommit_memory = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
# ========== 文件系统优化 ==========
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288
EOF
# 应用配置
sysctl -p
echo "✅ 内核参数优化完成!"
13.2 Nginx 性能调优
#!/usr/bin/env bash
# tune_nginx.sh — Nginx 性能优化
set -euo pipefail
NGINX_CONF="/etc/nginx/nginx.conf"
# 备份原始配置
cp $NGINX_CONF "${NGINX_CONF}.bak_$(date +%F)"
# Worker 进程数设为 CPU 核心数
sed -i '/worker_processes/c\worker_processes auto;' $NGINX_CONF
# Events 区块优化
sed -i '/events {/a\ worker_connections 4096;\n use epoll;\n multi_accept on;' $NGINX_CONF
# HTTP 区块追加 TCP 优化
cat <<EOF >> $NGINX_CONF
# TCP 优化
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 10000;
sendfile on;
# 上传限制
client_max_body_size 100m;
client_body_buffer_size 128k;
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
EOF
# 测试并重载配置
nginx -t && systemctl reload nginx
echo "✅ Nginx 性能优化完成!"
14. 高级监控脚本
14.1 Docker 容器资源监控
#!/usr/bin/env bash
# container_monitor.sh — 容器资源使用监控
set -euo pipefail
ALERT_CPU=80.0
ALERT_MEM="1GiB"
ALERT_EMAIL="admin@example.com"
REPORT_FILE="/tmp/docker_stats_$(date +%Y%m%d_%H%M).txt"
# 收集所有容器资源数据
docker stats --no-stream \
--format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}" \
> "$REPORT_FILE"
echo "📊 容器资源报告:"
cat "$REPORT_FILE"
# 检查异常容器(CPU 或内存超标)
ALERT_CONTAINERS=$(awk -v cpu="$ALERT_CPU" -v mem="$ALERT_MEM" '
NR>1 && ($2+0 > cpu || $3 ~ mem) {print $1}' "$REPORT_FILE")
if [ -n "$ALERT_CONTAINERS" ]; then
echo "" | mail -s "🚨 容器资源告警 — $(date)" $ALERT_EMAIL < "$REPORT_FILE"
echo "⚠️ 已发送告警邮件!"
else
echo "✅ 所有容器资源使用正常"
fi
14.2 网络连接监控
#!/usr/bin/env bash
# network_monitor.sh — 异常网络连接检测
set -euo pipefail
SYN_THRESHOLD=100
ALERT_EMAIL="admin@example.com"
echo "🌐 网络连接监控报告 — $(date)"
echo ""
# Top 10 高频连接 IP
echo "=== Top 10 连接 IP ==="
ABNORMAL_CONNS=$(ss -antp state established \
| awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -10)
echo "$ABNORMAL_CONNS"
# SYN Flood 攻击检测
SYN_COUNT=$(netstat -n -p tcp 2>/dev/null | grep SYN_RECV | wc -l)
echo ""
echo "=== SYN_RECV 连接数: $SYN_COUNT ==="
if [ $SYN_COUNT -gt $SYN_THRESHOLD ]; then
echo "🚨 检测到可能的 SYN Flood 攻击! SYN_RECV: $SYN_COUNT" \
| mail -s "🚨 网络攻击告警 — SYN Flood" $ALERT_EMAIL
fi
# 连接总数统计
echo ""
echo "=== 连接统计摘要 ==="
ss -s | head -10
15. 自动化测试脚本
#!/usr/bin/env bash
# run_tests.sh — 全栈测试套件
set -euo pipefail
APP_URL="http://localhost:8000"
TEST_REPORT="/reports/test_$(date +%Y%m%d_%H%M).html"
mkdir -p /reports
echo "========================================="
echo " 自动化测试套件 — $(date)"
echo "========================================="
# 1. 单元测试
echo ""
echo "[1/4] 运行单元测试..."
pytest tests/unit_tests -v --html=$TEST_REPORT --self-contained-html || true
# 2. API 接口测试
echo ""
echo "[2/4] 运行 API 测试..."
newman run tests/api_tests.postman_collection.json \
--env-var "baseUrl=$APP_URL" \
--reporter-html-export reports/api_report.html || true
# 3. 负载测试
echo ""
echo "[3/4] 运行负载测试..."
k6 run tests/load_test.js --summary export=reports/k6_summary.json || true
# 4. 安全扫描
echo ""
echo "[4/4] 运行安全扫描..."
zap-cli quick-scan -s all $APP_URL || true
echo ""
echo "🎉 测试套件执行完成!"
echo " 报告目录: /reports/"
16. 灾难恢复脚本
#!/usr/bin/env bash
# disaster_recovery.sh — 一键灾难恢复
set -euo pipefail
BACKUP_BASE=/backups
LOG_FILE="/var/log/disaster_recovery_$(date +%Y%m%d_%H%M%S).log"
exec > >(tee "$LOG_FILE") 2>&1
echo "========================================="
echo " ⚠️ 灾难恢复程序 — $(date)"
echo "========================================="
echo ""
read -p "确认要执行恢复操作吗?(yes/no): " CONFIRM
[ "$CONFIRM" != "yes" ] && echo "已取消" && exit 0
# 1. 恢复数据库
echo "[1/5] 恢复数据库..."
mysql -u root -p < $BACKUP_BASE/db/latest_full.sql
# 2. 恢复网站文件
echo "[2/5] 恢复网站文件..."
rsync -avz $BACKUP_BASE/files/latest/ /var/www/html/
chown -R www-data:www-data /var/www/html
# 3. 恢复配置文件
echo "[3/5] 恢复配置..."
cp $BACKUP_BASE/configs/nginx.conf /etc/nginx/nginx.conf
cp $BACKUP_BASE/configs/my.cnf /etc/mysql/my.cnf
# 4. 重启所有服务
echo "[4/5] 重启服务..."
systemctl restart mysql nginx php*-fpm
# 5. 验证恢复结果
echo "[5/5] 验证服务状态..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost)
if [ "$HTTP_CODE" == "200" ]; then
echo "✅ 服务已恢复正常 (HTTP $HTTP_CODE)"
else
echo "❌ 服务可能未完全恢复 (HTTP $HTTP_CODE),请手动检查"
fi
echo ""
echo "🔄 灾难恢复完成!日志: $LOG_FILE"
17. 多服务器管理脚本
#!/usr/bin/env bash
# multi_server_ops.sh — 多服务器批量操作
set -euo pipefail
SERVERS=("web1.example.com" "web2.example.com" "db.example.com")
ADMIN_USER="opsadmin"
SSH_KEY="$HOME/.ssh/id_rsa"
LOG_DIR="/var/log/server_ops"
mkdir -p $LOG_DIR
echo "========================================="
echo " 多服务器批量操作 — $(date)"
echo "========================================="
for server in "${SERVERS[@]}"; do
LOG_FILE="$LOG_DIR/${server}_$(date +%Y%m%d_%H%M).log"
echo ""
echo "===== 🖥️ 操作服务器: $server ====="
# 安全更新
echo "[1/3] 执行安全更新..."
ssh -i $SSH_KEY $ADMIN_USER@$server \
"sudo apt update && sudo apt upgrade -y" | tee "$LOG_FILE"
# 检查磁盘空间
echo "[2/3] 检查磁盘空间..."
ssh -i $SSH_KEY $ADMIN_USER@$server "df -h /" | tee -a "$LOG_FILE"
# 重启关键服务
echo "[3/3] 重启服务..."
ssh -i $SSH_KEY $ADMIN_USER@$server \
"sudo systemctl restart nginx mysql php*-fpm && sudo systemctl status nginx mysql --no-pager" \
| tee -a "$LOG_FILE"
echo "===== $server 完成 ====="
done
echo ""
echo "🎉 所有服务器操作完成!日志目录: $LOG_DIR"
18. 证书管理脚本
#!/usr/bin/env bash
# cert_manager.sh — 多格式证书管理与分发
set -euo pipefail
DOMAIN="example.com"
EMAIL="admin@example.com"
CERT_DIR="/etc/letsencrypt/live/$DOMAIN"
echo "========================================="
echo " 证书管理 — $(date)"
echo "========================================="
# 1. 申请/续期证书
echo "[1/4] 申请/续期证书..."
certbot certonly --nginx \
-d $DOMAIN -d www.$DOMAIN \
--non-interactive --agree-tos -m $EMAIL
# 2. 生成 PFX 格式(Windows/IIS 用)
echo "[2/4] 生成 PFX 证书..."
openssl pkcs12 -export \
-out "$CERT_DIR/cert.pfx" \
-inkey "$CERT_DIR/privkey.pem" \
-in "$CERT_DIR/cert.pem" \
-certfile "$CERT_DIR/fullchain.pem" \
-passout pass:
# 3. 生成 HAProxy 合并证书
echo "[3/4] 生成 HAProxy 证书..."
cat "$CERT_DIR/fullchain.pem" "$CERT_DIR/privkey.pem" \
> "/etc/haproxy/certs/${DOMAIN}.pem"
# 4. 重载相关服务
echo "[4/4] 重载服务..."
systemctl reload nginx haproxy 2>/dev/null || true
echo ""
echo "✅ 证书管理操作完成!"
echo " PEM 证书: $CERT_DIR/"
echo " PFX 证书: $CERT_DIR/cert.pfx"
echo " HAProxy: /etc/haproxy/certs/${DOMAIN}.pem"
19. 零停机部署脚本
#!/usr/bin/env bash
# zero_downtime_deploy.sh — 蓝绿部署实现零停机
set -euo pipefail
BLUE_PORT=8080
GREEN_PORT=8081
PROXY_PORT=80
echo "========================================="
echo " 零停机部署(蓝绿策略)— $(date)"
echo "========================================="
# 判断当前活跃环境
CURRENT_COLOR=$(curl -s http://localhost/color 2>/dev/null || echo "none")
echo "当前活跃环境: $CURRENT_COLOR"
if [ "$CURRENT_COLOR" == "blue" ]; then
TARGET_COLOR="green"; TARGET_PORT=$GREEN_PORT; OLD_PORT=$BLUE_PORT
else
TARGET_COLOR="blue"; TARGET_PORT=$BLUE_PORT; OLD_PORT=$GREEN_PORT
fi
echo "目标部署环境: $TARGET_COLOR (端口: $TARGET_PORT)"
# 1. 部署新版本到目标环境
echo "[1/4] 部署新版本到 $TARGET_COLOR 环境..."
docker stop app-$TARGET_COLOR 2>/dev/null || true
docker rm app-$TARGET_COLOR 2>/dev/null || true
docker run -d --name app-$TARGET_COLOR -p $TARGET_PORT:8000 your-app:new-version
# 2. 等待新实例就绪
echo "[2/4] 等待新实例就绪..."
RETRIES=0
while ! nc -z localhost $TARGET_PORT; do
sleep 2
RETRIES=$((RETRIES + 1))
if [ $RETRIES -gt 30 ]; then
echo "❌ 新实例启动超时!" && exit 1
fi
done
echo "✅ 新实例已就绪"
# 3. 切换流量(通过 HAProxy/Nginx upstream)
echo "[3/4] 切换流量到 $TARGET_COLOR ..."
# HAProxy 示例:
sed -i "s/default_backend.*/default_backend app-${TARGET_COLOR}/" /etc/haproxy/haproxy.cfg
systemctl reload haproxy
# 4. 停止旧实例
echo "[4/4] 停止旧环境..."
OLD_COLOR=$([ "$TARGET_COLOR" == "green" ] && echo "blue" || echo "green")
docker stop app-$OLD_COLOR 2>/dev/null || true
docker rm app-$OLD_COLOR 2>/dev/null || true
echo ""
echo "🎉 零停机部署完成!当前运行版本: $TARGET_COLOR"
蓝绿部署架构图
┌──────────────┐
│ 用户请求 │
└──────┬───────┘
│ :80
┌──────▼───────┐
│ HAProxy / │
│ Nginx 反向代理│
└──┬────────┬──┘
│ │
:8080│ │:8081
┌────────▼──┐ ┌───▼────────┐
│ Blue 环境 │ │ Green 环境 │
│ (当前版本) │ │ (新版本) │
└────────────┘ └────────────┘
20. 自动化安全扫描脚本
#!/usr/bin/env bash
# security_scan.sh — 全方位安全扫描
set -euo pipefail
SCAN_DIR="/var/www/html"
REPORT_DIR="/reports/security/$(date +%Y%m%d_%H%M%S)"
mkdir -p $REPORT_DIR
echo "========================================="
echo " 🔒 安全扫描 — $(date)"
echo "========================================="
# 1. Lynis 系统审计
echo "[1/5] Lynis 系统审计..."
lynis audit system --cronjob > "$REPORT_DIR/lynis.log" 2>&1 || true
# 2. ClamAV 病毒扫描
echo "[2/5] ClamAV 病毒扫描..."
freshclam --quiet
clamscan -r -i $SCAN_DIR > "$REPORT_DIR/clamav.log" 2>&1 || true
# 3. Rkhunter 后门检测
echo "[3/5] Rkhunter 后门检测..."
rkhunter --check --sk > "$REPORT_DIR/rkhunter.log" 2>&1 || true
# 4. Web 漏洞扫描
echo "[4/5] Web 漏洞扫描 (Nikto)..."
nikto -h localhost -output "$REPORT_DIR/nikto.html" 2>&1 || true
# 5. 打包并发送报告
echo "[5/5] 生成报告..."
tar -czf "$REPORT_DIR/security_reports.tar.gz" -C "$REPORT_DIR" . 2>/dev/null || true
echo ""
echo "🔒 安全扫描完成!"
echo " 报告目录: $REPORT_DIR"
echo " 报告归档: $REPORT_DIR/security_reports.tar.gz"
21. 常用网络调试命令
| 命令 | 说明 | 示例 |
|---|---|---|
ss -tulwn | 列出所有监听端口 | 查看 TCP/UDP 监听状态 |
ss -s | 网络连接摘要统计 | 快速了解连接分布 |
netstat -anp | 查看网络连接与进程 | 需安装 net-tools |
tcpdump -i eth0 port 80 | 抓包指定端口流量 | tcpdump -i eth0 port 80 -w http.pcap |
traceroute example.com | 跟踪路由路径 | 排查网络延迟节点 |
mtr -rw example.com | 实时路由追踪(更直观) | 结合 traceroute + ping |
iperf3 -s / -c | 网络带宽测试 | 服务端 -s,客户端 -c server_ip |
dig example.com | DNS 查询 | 排查 DNS 解析问题 |
curl -I https://example.com | HTTP 响应头检查 | 检查 HTTPS/缓存/Server 信息 |
nc -zv host port | 端口连通性测试 | 快速检查某端口是否可达 |
iftop | 实时流量监控 | 按 Ctrl+C 退出 |
💡 最佳实践建议
:::info 最佳实践
- 执行前备份:运行任何脚本前先创建系统快照或备份重要数据
- 理解脚本逻辑:不要盲目执行,先阅读代码了解功能和风险
- 测试环境验证:在生产环境使用前,先在测试机验证兼容性
- 记录操作日志:使用
script命令记录执行过程便于排查问题 - 定期更新维护:关注依赖更新,及时修复已知漏洞和 bug
:::
❓ 常见问题 FAQ
Q: 如何给脚本添加执行权限?
使用 chmod 命令赋予执行权限:
chmod +x script_name.sh
./script_name.sh
如果遇到权限错误,检查文件所有者并使用 sudo 提权。建议先用 cat script_name.sh 查看内容确认安全性后再执行。
Q: 脚本执行失败如何排查?
排查步骤:
- 语法检查:
bash -n script.sh - 开启调试模式:
bash -x script.sh(查看详细执行过程) - 检查依赖:
which command(确认命令是否存在) - 查看系统日志:
journalctl -xe或/var/log/syslog - 确认权限和资源:
ls -la、df -h、free -h
Q: 如何设置脚本开机自动执行?
三种方法:
| 方法 | 适用场景 | 推荐度 |
|---|---|---|
| Systemd Service | 生产环境推荐 | ⭐⭐⭐⭐⭐ |
/etc/rc.local | 简单场景 | ⭐⭐ |
Cron @reboot | 定时重启执行 | ⭐⭐⭐ |
Systemd 方式示例(最推荐):
# /etc/systemd/system/my-script.service
[Unit]
Description=My Startup Script
After=network.target
[Service]
Type=simple
ExecStart=/path/to/script.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl enable my-script.service
Q: 如何编写可复用的 Shell 函数库?
将常用功能封装成函数,放入独立文件中:
# functions.sh — 公共函数库
log_info() { echo "[$(date '+%H:%M:%S')] [INFO] $*"; }
log_error() { echo "[$(date '+%H:%M:%S')] [ERROR] $*" >&2; }
check_cmd() { command -v "$1" >/dev/null 2>&1; }
confirm() {
read -p "$1 (yes/no): " ans
[ "$ans" = "yes" ]
}
# 在其他脚本中使用
source /path/to/functions.sh
log_info "开始执行..."
优点:提高代码复用性和可维护性,统一日志格式和错误处理。
📝 本文持续更新中,如有补充或修正欢迎反馈。


评论区