🔒 第五课:生产环境安全加固与运维

预计阅读时间:15 分钟  |  难度:进阶 ⭐⭐⭐

📋 本课目标:完成本课后,你应该能对一台生产服务器做完整的安全基线检查,知道如何配置防火墙、HSTS、自动备份、基础监控,并制定灾难恢复计划。

1 安全不是可选项

很多开发者觉得"我的网站又没用户,没人会攻击的"——事实是:互联网上存在大量的自动化扫描脚本,它们无差别地扫描每个公网 IP。你的服务器在连上网的第一小时内就会收到 SSH 爆破尝试。

安全不是"等网站做大了再考虑"的事,而是从部署第一天起就要做的事。这节课会把之前各课提到的安全要点汇总,并深入覆盖你没注意到的关键领域。

2 防火墙深度配置

🔴 2.1 云安全组 + 服务器防火墙 = 双重防护

很多人的误区是只配了云安全组或只配了 UFW。正确做法是两者都配——云安全组做第一道防线,服务器内部防火墙做第二道。

云安全组建议规则(以阿里云为例):

# 阿里云安全组规则配置建议

# 入站规则(Inbound)
协议: TCP, 端口: 22, 源: 你的家庭/公司 IP(或 VPN IP)# SSH 不要对全世界开放
协议: TCP, 端口: 80, 源: 0.0.0.0/0 # HTTP
协议: TCP, 端口: 443, 源: 0.0.0.0/0 # HTTPS

# 如果不需要直接 SSH,可用阿里云 ECS 的"会话管理"代替 SSH

服务器内部 UFW 配置:

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

# 只放行必要的端口
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS

# 启用防火墙
sudo ufw enable
sudo ufw status verbose # 查看完整规则

🟡 2.2 Fail2ban:自动封禁恶意 IP

即使你禁用了密码登录,SSH 端口仍然会被扫描。Fail2ban 监控日志文件,检测到多次失败尝试后自动封禁 IP:

sudo apt install -y fail2ban

# 创建本地配置文件(不要直接改 /etc/fail2ban/jail.conf)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# 编辑 jail.local,找到 [sshd] 部分
# 确保以下设置:
[sshd]
enabled = true
maxretry = 5 # 5 次失败后封禁
bantime = 3600 # 封禁 1 小时(默认 600 秒)
findtime = 600 # 10 分钟内的失败计数

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd # 查看封禁状态
⚠️ 常见误区:只配了 UFW 但没配安全组,或者反过来。攻击者只要突破一层就能进来。云安全组和 UFW 是互补关系
参考:阿里云安全组文档 | UFW 文档 | Fail2ban GitHub

3 HTTPS 深度指南

🟢 3.1 HSTS:强制浏览器走 HTTPS

配置了 Certbot 后,用户如果输入 http:// 仍然会被重定向到 HTTPS。但更好的做法是告诉浏览器"以后只走 HTTPS":

# 在 Nginx 的 server block 中添加(certbot 配置的 443 区块里)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

# max-age=63072000 秒(2 年)
# includeSubDomains 对所有子域名生效
# ⚠️ 确认所有子域名都支持 HTTPS 后再加 includeSubDomains

🟢 3.2 其他安全响应头

# /etc/nginx/conf.d/security-headers.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

这些头信息帮助浏览器防范点击劫持、MIME 嗅探等常见攻击。

🟡 3.3 证书到期监控

证书到期后网站会直接崩掉。设置一个简单的定时检查脚本:

# 写一个简单的证书到期检查脚本
cat > ~/check-cert.sh << 'EOF'
#!/bin/bash
DOMAIN="example.com"
EXPIRY=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
echo "Certificate for $DOMAIN expires in $DAYS_LEFT days"
if [ $DAYS_LEFT -lt 7 ]; then echo "WARNING: Certificate expiring soon!"; fi
EOF
chmod +x ~/check-cert.sh
./check-cert.sh

4 数据库安全

数据库是网站的核心资产——用户数据、订单、内容都在里面。数据库被攻破 = 灾难性的数据泄露。

🔴 数据库安全检查清单

  1. 绑定到 127.0.0.1 —— 在 MySQL 的 /etc/mysql/mysql.conf.d/mysqld.cnf 中设置 bind-address = 127.0.0.1,禁止远程连接
  2. 使用强密码 —— 至少 16 位,大小写字母 + 数字 + 符号
  3. 创建专用用户 —— 不要用 root 连接应用。每个应用创建独立的数据库用户,只赋予该应用所需的最小权限
  4. 删除测试数据库 —— sudo mysql -e "DROP DATABASE IF EXISTS test;"
  5. 启用日志 —— 开启 MySQL 的 general log 或 slow query log 用于排查
  6. 定期备份 —— 见下一节
# MySQL 安全初始化(生产环境必须跑)
sudo mysql_secure_installation

# 创建专用用户(示例)
CREATE USER 'myapp'@'localhost' IDENTIFIED BY 'your-strong-password-here';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'myapp'@'localhost';
FLUSH PRIVILEGES;
🔴 高危操作:数据库端口(3306/5432/27017)对公网开放。如果为了开发便利必须远程连接,使用 SSH 隧道(端口转发)而不是直接开放数据库端口。
ssh -L 3306:127.0.0.1:3306 ubuntu@你的服务器

5 备份策略:3-2-1 原则实战

"我的数据不重要的,丢了也没关系"——几乎所有说过这句话的人最后都后悔了。

🗄️ 5.1 数据库自动备份脚本

# /usr/local/bin/backup-db.sh
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/mysql"
DB_NAME="myapp_db"
DB_USER="backup_user"
DB_PASSWORD="your-backup-password"
RETENTION_DAYS=7

mkdir -p $BACKUP_DIR

# 使用 mysqldump 备份
mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME | gzip > $BACKUP_DIR/${DB_NAME}_${TIMESTAMP}.sql.gz

# 删除 7 天前的旧备份
find $BACKUP_DIR -name "${DB_NAME}_*.sql.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed: ${DB_NAME}_${TIMESTAMP}.sql.gz"
# 添加到 crontab 每天凌晨 3 点执行
sudo crontab -e

# 添加这一行
0 3 * * * /usr/local/bin/backup-db.sh

☁️ 5.2 异地备份:备份文件上传到对象存储

仅在服务器上的备份不算真正的备份——服务器硬盘坏了或整台机器被攻击了,备份也跟着没了。你需要异地备份

# 使用 aws-cli 将备份同步到 S3 / 阿里云 OSS
# (需要先安装和配置 aws-cli 或 ossutil)
aws s3 sync /backups/ s3://myapp-backups/production/

# 或者使用 rclone(支持几乎所有云存储)
rclone sync /backups/ remote:myapp-backups
⚠️ 常见误区:备份脚本写好了但从来没有测试过恢复。定期(至少每季度一次)做恢复演练——在测试服务器上把备份还原,确认数据是完整的、可用的。
参考:MySQL 备份与恢复文档

6 日志管理

📋 6.1 日志轮转(Logrotate)

日志文件会无限增长,占满磁盘空间。Linux 的 logrotate 自动按天/大小轮转日志:

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
    daily # 每天轮转
    rotate 30 # 保留 30 天的日志
    compress # 轮转后压缩
    delaycompress
    missingok
    notifempty
    create 0640 ubuntu ubuntu
    sharedscripts
    postrotate
        systemctl reload myapp
    endscript
}

🔍 6.2 关键日志位置速查

日志文件查看什么
/var/log/nginx/access.logNginx 访问日志——谁在什么时间访问了什么路径
/var/log/nginx/error.logNginx 错误日志——502/504 等错误的线索
/var/log/auth.logSSH 登录日志——有没有人尝试登录失败
/var/log/syslog系统通用日志
journalctl -u myapp应用(Systemd 服务)日志
journalctl -u dockerDocker 守护进程日志

7 基础监控告警

不需要复杂的 Prometheus + Grafana 体系。对于单台或几台服务器,最简单有效的监控方案是:

📊 7.1 Netdata(一键安装,可视化监控)

Netdata 是一个开源的实时监控工具,一条命令安装完就能看到 CPU、内存、磁盘、网络、进程等所有指标:

# 一条命令安装 Netdata
bash <(curl -Ss https://my-netdata.io/kickstart.sh)

# 安装完成后访问 http://你的服务器:19999
# ⚠️ 记得在安全组中限制 19999 端口只能由你的 IP 访问

📧 7.2 磁盘空间监控(简单脚本)

# 一个简单的磁盘告警脚本
#!/bin/bash
THRESHOLD=80
USAGE=$(df -h / | awk 'NR==2 {print $5}' | cut -d% -f1)
if [ $USAGE -gt $THRESHOLD ]; then
  echo "Disk usage is at ${USAGE}% on $(hostname)" | mail -s "Disk Alert" your-email@example.com
fi

📡 7.3 Uptime 监控(外部服务)

外部监控你的网站是否在线(内部监控看不出来网络层面或 DNS 问题):

8 灾难恢复计划

当最坏的情况发生时(服务器被入侵、数据被删除、硬盘故障),你需要一个文档化的恢复流程,而不是临时想该怎么办。

🟡 灾难恢复步骤:
  1. 评估损害——哪些服务挂了?数据是否丢失?入侵影响范围?
  2. 隔离——如果被入侵,立即从网络断开服务器
  3. 恢复数据——从最近的异地备份还原数据到新服务器
  4. 重建服务——用你记录的部署文档在新服务器上重建环境
  5. 恢复上线——更新 DNS 指向新服务器 IP
  6. 事后复盘——记录根因、修复漏洞、更新恢复流程

你能做的最好准备:

9 安全基线检查清单

✅ 生产环境上线前逐项检查:

☐ SSH 禁用密码登录,仅使用密钥
☐ SSH 禁用 root 直接登录(PermitRootLogin no)
☐ UFW 防火墙已启用,只放行 22/80/443
☐ 云安全组规则最小化,SSH 仅允许你的 IP
☐ Nginx 配置了 HSTS 和其他安全头
☐ HTTPS 证书已配置并验证自动续期
☐ 数据库绑定到 127.0.0.1,不暴露到公网
☐ 数据库使用专用用户和应用特定授权
☐ 自动备份已配置(数据库 + 文件),且已测试恢复
☐ 异地备份已配置(3-2-1 原则)
☐ Fail2ban 已安装和配置
☐ 日志轮转已配置
☐ 磁盘空间监控已配置(或安装了 Netdata)
☐ 外部 uptime 监控已设置
☐ 灾难恢复文档已编写

10 小测验

Q1: 一个安全的数据库应该绑定到哪个地址?

Q2: 以下哪个是正确的备份策略?

Q3: 你的网站仅支持 HTTPS。用户通过 http:// 访问时应如何正确配置?

🎓 课程结语

恭喜你完成了全部 5 节课!🎉

你走过的学习路径:

  1. 🌐 部署全景图 —— 理解"从代码到用户"的完整链路
  2. 🖥️ 手工部署 —— SSH、Nginx、Systemd、HTTPS —— 掌握底层
  3. 🐳 Docker 容器化 —— 一次构建,到处运行
  4. ⚙️ CI/CD 自动化 —— git push 即部署
  5. 🔒 安全运维 —— 防火墙、备份、监控、灾备

接下来的实践建议:

📖 推荐官方文档(全课汇总)