Apache HTTP Server 完全指南 / 生产最佳实践
生产最佳实践
本章总结 Apache 在生产环境中的安全基线、运维 SOP、备份策略和团队管理规范。
1. 安全基线
1.1 安全配置清单
| 检查项 | 配置 | 优先级 |
|---|
| 隐藏版本信息 | ServerTokens Prod | 高 |
| 关闭签名 | ServerSignature Off | 高 |
| 禁用目录列表 | Options -Indexes | 高 |
| 保护敏感文件 | <FilesMatch "^\."> | 高 |
| 启用 HTTPS | SSLEngine on | 高 |
| 禁用弱协议 | SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 | 高 |
| 启用 HSTS | Header set Strict-Transport-Security | 中 |
| 安全头配置 | X-Frame-Options, X-XSS-Protection 等 | 中 |
| 访问控制 | Require ip / Require user | 中 |
| ModSecurity | WAF 规则 | 中 |
| 日志审计 | 完整的日志记录 | 中 |
| 定期更新 | 安全补丁及时应用 | 高 |
1.2 安全基线配置
# /etc/apache2/conf-available/security-baseline.conf
# 1. 版本信息
ServerTokens Prod
ServerSignature Off
# 2. 目录安全
<Directory />
Options -Indexes -FollowSymLinks -Includes
AllowOverride None
Require all denied
</Directory>
<Directory "/var/www/html">
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# 3. 敏感文件保护
<FilesMatch "^\.">
Require all denied
</FilesMatch>
<FilesMatch "\.(conf|log|bak|sql|sh|env|git|htaccess|htpasswd)$">
Require all denied
</FilesMatch>
# 4. 安全头
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always unset Server
Header always unset X-Powered-By
</IfModule>
# 5. 请求限制
<IfModule mod_reqtimeout.c>
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>
# 6. HTTP 方法限制
<LimitExcept GET POST HEAD OPTIONS>
Require all denied
</LimitExcept>
1.3 SSL 基线
# /etc/apache2/conf-available/ssl-baseline.conf
<IfModule mod_ssl.c>
# 仅允许安全协议
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
# 强密码套件
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
# 会话安全
SSLSessionTickets off
# 压缩
SSLCompression off
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache shmcb:/var/run/ocsp(128000)
</IfModule>
<IfModule mod_headers.c>
# HSTS
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
</IfModule>
2. 运维 SOP
2.1 日常运维检查表
#!/bin/bash
# daily-check.sh - 每日检查脚本
echo "=== Apache 每日检查 $(date +%Y-%m-%d) ==="
# 1. 服务状态
echo "1. 服务状态:"
systemctl is-active apache2
# 2. 配置语法
echo "2. 配置语法:"
apachectl configtest 2>&1
# 3. 进程数
echo "3. 进程数:"
ps aux | grep httpd | wc -l
# 4. 错误日志统计
echo "4. 最近 24 小时错误:"
grep "$(date -d yesterday +%Y-%m-%d)" /var/log/apache2/error.log | wc -l
# 5. 磁盘空间
echo "5. 磁盘空间:"
df -h | grep -E '/$|/var|/tmp'
# 6. SSL 证书到期
echo "6. SSL 证书到期检查:"
for cert in /etc/letsencrypt/live/*/fullchain.pem; do
EXPIRY=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
DAYS_LEFT=$(( ($(date -d "$EXPIRY" +%s) - $(date +%s)) / 86400 ))
echo " $(dirname $cert): $EXPIRY ($DAYS_LEFT 天)"
done
# 7. 内存使用
echo "7. 内存使用:"
free -h
# 8. 负载
echo "8. 系统负载:"
uptime
echo "=== 检查完成 ==="
2.2 变更管理流程
变更请求 → 评审 → 测试 → 备份 → 实施 → 验证 → 记录
#!/bin/bash
# change-apache-config.sh
CONFIG_FILE=$1
CHANGE_DESC=$2
# 1. 备份当前配置
BACKUP_DIR="/backup/apache/$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR
cp /etc/apache2/apache2.conf $BACKUP_DIR/
cp -r /etc/apache2/sites-enabled $BACKUP_DIR/
echo "配置已备份到: $BACKUP_DIR"
# 2. 测试新配置
cp $CONFIG_FILE /etc/apache2/apache2.conf
if ! apachectl configtest; then
echo "配置测试失败,恢复原配置"
cp $BACKUP_DIR/apache2.conf /etc/apache2/
exit 1
fi
# 3. 重新加载配置
systemctl reload apache2
if [ $? -ne 0 ]; then
echo "重载失败,恢复原配置"
cp $BACKUP_DIR/apache2.conf /etc/apache2/
cp -r $BACKUP_DIR/sites-enabled /etc/apache2/
systemctl reload apache2
exit 1
fi
# 4. 验证
sleep 5
if curl -s -o /dev/null -w "%{http_code}" http://localhost/ | grep -q "200\|301\|302"; then
echo "变更成功: $CHANGE_DESC"
else
echo "验证失败,恢复原配置"
cp $BACKUP_DIR/apache2.conf /etc/apache2/
cp -r $BACKUP_DIR/sites-enabled /etc/apache2/
systemctl reload apache2
exit 1
fi
# 5. 记录变更
echo "$(date) - $CHANGE_DESC" >> /var/log/apache2-changes.log
2.3 版本升级流程
#!/bin/bash
# upgrade-apache.sh
# 1. 记录当前版本
echo "当前版本:" > /tmp/upgrade.log
apachectl -v >> /tmp/upgrade.log
apachectl -V >> /tmp/upgrade.log
# 2. 备份配置和网站
BACKUP_DIR="/backup/apache/pre-upgrade-$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/apache-config.tar.gz /etc/apache2/
tar -czf $BACKUP_DIR/apache-www.tar.gz /var/www/
cp /etc/apache2/mods-enabled/*.load $BACKUP_DIR/
cp /etc/apache2/mods-enabled/*.conf $BACKUP_DIR/
# 3. 检查新版本
apt update
apt list --upgradable | grep apache
# 4. 执行升级
apt upgrade apache2
# 5. 测试配置
if ! apachectl configtest; then
echo "升级后配置测试失败"
echo "请检查配置并手动修复"
exit 1
fi
# 6. 重启服务
systemctl restart apache2
# 7. 验证
sleep 5
if curl -s -o /dev/null -w "%{http_code}" http://localhost/ | grep -q "200\|301\|302"; then
echo "升级成功"
apachectl -v >> /tmp/upgrade.log
else
echo "升级后验证失败,请检查"
exit 1
fi
echo "升级完成,详细日志: /tmp/upgrade.log"
3. 备份与恢复
3.1 完整备份脚本
#!/bin/bash
# backup-apache-full.sh
BACKUP_BASE="/backup/apache"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="$BACKUP_BASE/$DATE"
RETENTION_DAYS=30
mkdir -p $BACKUP_DIR
# 1. 配置文件
echo "备份配置文件..."
tar -czf $BACKUP_DIR/apache-config.tar.gz \
/etc/apache2/ \
/etc/php/ \
2>/dev/null
# 2. 网站文件
echo "备份网站文件..."
tar -czf $BACKUP_DIR/apache-www.tar.gz \
/var/www/ \
2>/dev/null
# 3. SSL 证书
echo "备份 SSL 证书..."
tar -czf $BACKUP_DIR/apache-ssl.tar.gz \
/etc/letsencrypt/ \
/etc/ssl/ \
2>/dev/null
# 4. 日志(最近 7 天)
echo "备份日志..."
find /var/log/apache2/ -mtime -7 -type f -exec tar -czf $BACKUP_DIR/apache-logs.tar.gz {} + 2>/dev/null
# 5. 生成清单
echo "生成备份清单..."
{
echo "=== Apache 备份清单 ==="
echo "日期: $DATE"
echo "主机: $(hostname)"
echo "Apache 版本: $(apachectl -v | head -1)"
echo ""
echo "备份内容:"
ls -lh $BACKUP_DIR/
} > $BACKUP_DIR/manifest.txt
# 6. 清理旧备份
echo "清理 ${RETENTION_DAYS} 天前的备份..."
find $BACKUP_BASE -type d -mtime +$RETENTION_DAYS -exec rm -rf {} +
# 7. 计算备份大小
BACKUP_SIZE=$(du -sh $BACKUP_DIR | cut -f1)
echo "备份完成: $BACKUP_DIR ($BACKUP_SIZE)"
3.2 恢复脚本
#!/bin/bash
# restore-apache.sh
BACKUP_DIR=$1
if [ -z "$BACKUP_DIR" ]; then
echo "用法: $0 <backup-directory>"
echo "可用备份:"
ls -d /backup/apache/*/ | tail -10
exit 1
fi
echo "=== 恢复 Apache 配置 ==="
echo "备份目录: $BACKUP_DIR"
echo ""
read -p "确认恢复?这将覆盖当前配置 (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "已取消"
exit 0
fi
# 1. 停止服务
echo "停止 Apache..."
systemctl stop apache2
# 2. 备份当前配置(以防恢复失败)
CURRENT_BACKUP="/backup/apache/before-restore-$(date +%Y%m%d_%H%M%S)"
mkdir -p $CURRENT_BACKUP
cp -r /etc/apache2/ $CURRENT_BACKUP/
# 3. 恢复配置
echo "恢复配置文件..."
tar -xzf $BACKUP_DIR/apache-config.tar.gz -C /
# 4. 恢复网站文件
echo "恢复网站文件..."
tar -xzf $BACKUP_DIR/apache-www.tar.gz -C /
# 5. 测试配置
echo "测试配置..."
if ! apachectl configtest; then
echo "配置测试失败,恢复到恢复前状态"
cp -r $CURRENT_BACKUP/apache2/* /etc/apache2/
systemctl start apache2
exit 1
fi
# 6. 启动服务
echo "启动 Apache..."
systemctl start apache2
# 7. 验证
sleep 5
if curl -s -o /dev/null -w "%{http_code}" http://localhost/ | grep -q "200\|301\|302"; then
echo "恢复成功"
else
echo "恢复后验证失败,请检查"
fi
3.3 定期备份 Cron
# /etc/cron.d/apache-backup
# 每天凌晨 2 点备份
0 2 * * * root /usr/local/bin/backup-apache-full.sh >> /var/log/apache-backup.log 2>&1
# 每周日凌晨 3 点完整备份(包含日志)
0 3 * * 0 root /usr/local/bin/backup-apache-full.sh --include-logs >> /var/log/apache-backup.log 2>&1
# 每月 1 日备份 SSL 证书
0 4 1 * * root tar -czf /backup/apache/ssl-$(date +\%Y\%m\%d).tar.gz /etc/letsencrypt/ /etc/ssl/
4. 监控告警规范
4.1 告警级别
| 级别 | 条件 | 响应时间 | 通知方式 |
|---|
| P0-严重 | 服务不可用 | 5 分钟 | 电话+短信+邮件 |
| P1-紧急 | 性能严重下降 | 15 分钟 | 短信+邮件 |
| P2-警告 | 资源使用偏高 | 1 小时 | 邮件 |
| P3-通知 | 信息性事件 | 下一工作日 | 邮件 |
4.2 告警规则
# Prometheus 告警规则
groups:
- name: apache_alerts
rules:
# P0 - 服务不可用
- alert: ApacheDown
expr: up{job="apache"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Apache 服务停止"
description: "Apache 服务已停止超过 1 分钟"
# P1 - 高错误率
- alert: ApacheHighErrorRate
expr: rate(apache_accesses_total{code=~"5.."}[5m]) > 10
for: 5m
labels:
severity: critical
annotations:
summary: "Apache 5xx 错误率过高"
# P1 - 证书即将过期
- alert: ApacheCertExpiring
expr: (ssl_certificate_expiry - time()) / 86400 < 7
for: 1h
labels:
severity: warning
annotations:
summary: "SSL 证书将在 7 天内过期"
# P2 - 高负载
- alert: ApacheHighLoad
expr: apache_cpu_load > 80
for: 10m
labels:
severity: warning
annotations:
summary: "Apache CPU 负载过高"
# P2 - 磁盘空间
- alert: ApacheDiskSpaceLow
expr: (node_filesystem_avail_bytes{mountpoint="/var/log"} / node_filesystem_size_bytes{mountpoint="/var/log"}) * 100 < 20
for: 5m
labels:
severity: warning
annotations:
summary: "日志分区空间不足"
4.3 Grafana 仪表板
{
"dashboard": {
"title": "Apache 生产监控",
"panels": [
{
"title": "服务状态",
"type": "stat",
"targets": [{
"expr": "up{job='apache'}",
"legendFormat": "状态"
}]
},
{
"title": "每秒请求",
"type": "timeseries",
"targets": [{
"expr": "rate(apache_accesses_total[5m])",
"legendFormat": "RPS"
}]
},
{
"title": "响应时间",
"type": "timeseries",
"targets": [{
"expr": "rate(apache_duration_seconds_sum[5m]) / rate(apache_duration_seconds_count[5m])",
"legendFormat": "平均响应时间"
}]
},
{
"title": "工作线程",
"type": "gauge",
"targets": [{
"expr": "apache_busy_workers / (apache_busy_workers + apache_idle_workers) * 100",
"legendFormat": "使用率 %"
}]
},
{
"title": "错误率",
"type": "timeseries",
"targets": [{
"expr": "rate(apache_accesses_total{code=~'5..'}[5m]) / rate(apache_accesses_total[5m]) * 100",
"legendFormat": "错误率 %"
}]
}
]
}
}
5. 性能优化规范
5.1 环境参数标准
| 参数 | 开发环境 | 测试环境 | 生产环境 |
|---|
| MPM | event | event | event |
| MaxRequestWorkers | 100 | 250 | 400+ |
| KeepAliveTimeout | 15 | 5 | 3 |
| MaxKeepAliveRequests | 100 | 100 | 100 |
| ServerTokens | Full | Prod | Prod |
| LogLevel | debug | warn | warn |
| 错误显示 | On | Off | Off |
5.2 缓存策略标准
| 资源类型 | max-age | 策略 |
|---|
| HTML | 0 | no-cache |
| CSS/JS (带哈希) | 1 年 | immutable |
| CSS/JS (无哈希) | 1 天 | 必须验证 |
| 图片 | 1 年 | public |
| 字体 | 1 年 | immutable |
| API 响应 | 0 | no-store |
| 静态文件 | 1 月 | public |
5.3 压缩配置标准
# 压缩配置
<IfModule mod_deflate.c>
DeflateCompressionLevel 6
# 压缩类型
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE image/svg+xml
# 排除已压缩内容
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|zip|gz|bz2|rar|mp[34]|avi|wmv|flv)$ no-gzip dont-vary
</IfModule>
6. 文档与培训
6.1 运维文档结构
docs/
├── architecture/
│ ├── 系统架构图.md
│ ├── 网络拓扑图.md
│ └── 数据流图.md
├── operations/
│ ├── 日常运维手册.md
│ ├── 变更管理流程.md
│ ├── 故障处理手册.md
│ └── 应急预案.md
├── security/
│ ├── 安全基线文档.md
│ ├── 安全事件响应.md
│ └── 审计报告模板.md
├── deployment/
│ ├── 部署流程.md
│ ├── 回滚流程.md
│ └── 灰度发布.md
└── maintenance/
├── 备份恢复手册.md
├── 性能调优指南.md
└── 升级指南.md
6.2 事故报告模板
# 事故报告
## 基本信息
- **事故编号**: INC-YYYY-MMDD-XXX
- **报告时间**: YYYY-MM-DD HH:MM:SS
- **报告人**:
- **事故等级**: P0/P1/P2/P3
## 事故描述
- **影响范围**:
- **持续时间**:
- **影响用户数**:
- **业务损失**:
## 事故经过
1. YYYY-MM-DD HH:MM:SS - 发现问题
2. YYYY-MM-DD HH:MM:SS - 开始排查
3. YYYY-MM-DD HH:MM:SS - 定位原因
4. YYYY-MM-DD HH:MM:SS - 修复完成
5. YYYY-MM-DD HH:MM:SS - 验证恢复
## 根本原因
- **直接原因**:
- **根本原因**:
## 处理措施
- **临时措施**:
- **永久措施**:
## 改进计划
- [ ]
- [ ]
- [ ]
## 经验教训
-
-
6.3 培训计划
| 主题 | 对象 | 频率 | 方式 |
|---|
| Apache 基础 | 新员工 | 入职培训 | 面授 |
| 安全意识 | 全体运维 | 季度 | 在线 |
| 故障处理 | 运维团队 | 月度 | 演练 |
| 性能调优 | 高级运维 | 季度 | 工作坊 |
| 新版本特性 | 全体运维 | 版本发布时 | 分享会 |
7. 容量规划
7.1 容量评估
#!/bin/bash
# capacity-planning.sh
echo "=== Apache 容量评估 ==="
# 当前使用情况
echo "1. 当前负载:"
echo " CPU: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2}')%"
echo " 内存: $(free | grep Mem | awk '{print $3/$2 * 100.0}')%"
echo " 磁盘: $(df / | tail -1 | awk '{print $5}')"
# 连接数
echo "2. 连接数:"
echo " 当前: $(ss -tlnp | grep ':80 ' | wc -l)"
echo " 最大: $(grep MaxRequestWorkers /etc/apache2/mods-enabled/mpm_*.conf | awk '{print $2}')"
# 请求量
echo "3. 请求量 (最近 24 小时):"
echo " 总请求: $(wc -l < /var/log/apache2/access.log)"
echo " 每秒请求: $(tail -10000 /var/log/apache2/access.log | wc -l | awk '{print $1/86400}')"
# 带宽
echo "4. 带宽使用:"
echo " 日均: $(awk '{sum+=$10} END {print sum/1024/1024 " MB"}' /var/log/apache2/access.log)"
# 预测
echo "5. 建议:"
echo " 根据当前使用情况,建议:"
echo " - MaxRequestWorkers: $(ps aux | grep httpd | wc -l | awk '{print int($1*1.5)}')"
echo " - 内存预留: $(free -m | grep Mem | awk '{print int($2*0.2) " MB"}')"
7.2 扩展策略
负载增加
├── 垂直扩展(Scale Up)
│ ├── 增加 CPU
│ ├── 增加内存
│ └── 优化 MPM 参数
├── 水平扩展(Scale Out)
│ ├── 添加后端服务器
│ ├── 配置负载均衡
│ └── 使用 CDN
└── 架构优化
├── 启用缓存
├── 压缩优化
└── 数据库优化
8. 高可用方案
8.1 主备架构
┌─────────────┐
│ 负载均衡器 │
│ (keepalived)│
└──────┬──────┘
│
┌─────────────┼─────────────┐
│ │
┌────────┴────────┐ ┌────────┴────────┐
│ Apache 主 │ │ Apache 备 │
│ (MASTER) │ │ (BACKUP) │
│ 优先级 100 │ │ 优先级 90 │
└────────┬────────┘ └────────┬────────┘
│ │
└─────────┬─────────────────┘
│
┌───────┴───────┐
│ 共享存储 │
│ (NFS/GlusterFS)│
└───────────────┘
8.2 Keepalived 配置
# /etc/keepalived/keepalived.conf (主)
vrrp_script check_apache {
script "/usr/local/bin/check_apache.sh"
interval 2
weight 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass apache_ha
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_apache
}
notify_master "/usr/local/bin/notify_master.sh"
notify_backup "/usr/local/bin/notify_backup.sh"
}
#!/bin/bash
# check_apache.sh
if ! pgrep -x apache2 > /dev/null; then
exit 1
fi
curl -sf http://localhost/ > /dev/null || exit 1
exit 0
9. 安全合规
9.1 PCI DSS 要求
| 要求 | Apache 配置 |
|---|
| 2.2 配置标准 | 安全基线配置 |
| 4.1 传输加密 | SSL/TLS 配置 |
| 6.2 安全补丁 | 定期更新 |
| 6.5 安全编码 | ModSecurity WAF |
| 10.2 审计日志 | 完整日志记录 |
| 11.2 漏洞扫描 | 定期安全扫描 |
9.2 GDPR 合规
# 日志匿名化(不记录 IP)
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_anon
# 或使用哈希处理
LogFormat "ANONYMIZED %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" gdpr
# Cookie 安全
Header always set Set-Cookie "Path=/; HttpOnly; Secure; SameSite=Strict"
10. 注意事项
- 定期演练:备份恢复、故障处理定期演练
- 文档更新:配置变更后及时更新文档
- 安全审计:定期进行安全审计和漏洞扫描
- 性能测试:定期进行压力测试和性能优化
- 团队协作:建立有效的沟通和协作机制
11. 扩展阅读
12. 总结
生产环境 Apache 运维需要:
- 安全基线:建立和执行安全配置标准
- 运维规范:制定和遵循 SOP 流程
- 备份策略:定期备份,定期验证
- 监控告警:建立完善的监控和告警体系
- 持续改进:定期评估、优化和改进
遵循最佳实践可以确保 Apache 服务稳定、安全、高效运行。