3ce31d3178
ci/woodpecker/push/woodpecker Pipeline failed
- 创建轻量级工具镜像(novalon/tools:1.0.0)避免重复安装工具 - 修复Docker TLS handshake timeout问题 - 更新CI配置使用registry.f.novalon.cn/novalon/tools:1.0.0 - 添加自动清理脚本用于磁盘和镜像管理
524 lines
14 KiB
Bash
524 lines
14 KiB
Bash
#!/bin/bash
|
||
|
||
# 生产环境安全加固自动化脚本
|
||
# 作者:张翔
|
||
# 日期:2026-03-31
|
||
|
||
echo "🚀 开始执行生产环境安全加固..."
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m'
|
||
|
||
# 配置参数
|
||
PROD_DIR="/home/novalon/docker-app"
|
||
NGINX_DIR="$PROD_DIR/novalon-nginx"
|
||
APP_DIR="$PROD_DIR/novalon-website"
|
||
|
||
echo "📁 检查生产环境目录..."
|
||
if [ ! -d "$PROD_DIR" ]; then
|
||
echo "❌ 生产环境目录不存在:$PROD_DIR"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ 生产环境目录存在"
|
||
|
||
# 1. 创建安全的Nginx配置
|
||
echo "⚙️ 创建安全的Nginx配置..."
|
||
|
||
mkdir -p "$NGINX_DIR"
|
||
|
||
cat > "$NGINX_DIR/nginx.conf" << 'NGINX_EOF'
|
||
# ============================================================
|
||
# 安全的Nginx配置 - Next.js生产环境
|
||
# 作者:张翔
|
||
# 日期:2026-03-31
|
||
# ============================================================
|
||
|
||
worker_processes auto;
|
||
error_log /var/log/nginx/error.log warn;
|
||
pid /var/run/nginx.pid;
|
||
|
||
events {
|
||
worker_connections 1024;
|
||
use epoll;
|
||
multi_accept on;
|
||
}
|
||
|
||
http {
|
||
# ============================================================
|
||
# 基础配置
|
||
# ============================================================
|
||
include /etc/nginx/mime.types;
|
||
default_type application/octet-stream;
|
||
|
||
# 日志格式
|
||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||
'$status $body_bytes_sent "$http_referer" '
|
||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||
'rt=$request_time uct="$upstream_connect_time" '
|
||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||
|
||
access_log /var/log/nginx/access.log main;
|
||
|
||
# 性能优化
|
||
sendfile on;
|
||
tcp_nopush on;
|
||
tcp_nodelay on;
|
||
keepalive_timeout 65;
|
||
types_hash_max_size 2048;
|
||
|
||
# ============================================================
|
||
# 安全配置
|
||
# ============================================================
|
||
|
||
# 隐藏Nginx版本号
|
||
server_tokens off;
|
||
|
||
# 安全响应头
|
||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||
add_header X-Content-Type-Options "nosniff" always;
|
||
add_header X-XSS-Protection "1; mode=block" always;
|
||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
|
||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
||
|
||
# 限制请求大小
|
||
client_max_body_size 10m;
|
||
client_body_timeout 10s;
|
||
client_header_timeout 10s;
|
||
send_timeout 10s;
|
||
|
||
# ============================================================
|
||
# 防止DDoS攻击
|
||
# ============================================================
|
||
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
|
||
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
|
||
limit_conn conn_limit 10;
|
||
|
||
# ============================================================
|
||
# Gzip压缩
|
||
# ============================================================
|
||
gzip on;
|
||
gzip_vary on;
|
||
gzip_proxied any;
|
||
gzip_comp_level 6;
|
||
gzip_min_length 1000;
|
||
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
|
||
|
||
# ============================================================
|
||
# 上游服务器配置
|
||
# ============================================================
|
||
upstream nextjs_backend {
|
||
server 127.0.0.1:3000;
|
||
keepalive 64;
|
||
}
|
||
|
||
# ============================================================
|
||
# HTTP到HTTPS重定向
|
||
# ============================================================
|
||
server {
|
||
listen 80;
|
||
listen [::]:80;
|
||
server_name your-domain.com www.your-domain.com;
|
||
|
||
# 重定向到HTTPS
|
||
return 301 https://$server_name$request_uri;
|
||
}
|
||
|
||
# ============================================================
|
||
# HTTPS服务器
|
||
# ============================================================
|
||
server {
|
||
listen 443 ssl http2;
|
||
listen [::]:443 ssl http2;
|
||
server_name your-domain.com www.your-domain.com;
|
||
|
||
# SSL证书配置
|
||
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
||
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||
|
||
# SSL配置
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||
ssl_prefer_server_ciphers off;
|
||
ssl_session_cache shared:SSL:10m;
|
||
ssl_session_timeout 1d;
|
||
ssl_session_tickets off;
|
||
|
||
# OCSP Stapling
|
||
ssl_stapling on;
|
||
ssl_stapling_verify on;
|
||
|
||
# ========================================================
|
||
# 位置块配置
|
||
# ========================================================
|
||
|
||
# Next.js静态文件
|
||
location /_next/ {
|
||
proxy_pass http://nextjs_backend;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_cache_valid 200 302 10m;
|
||
proxy_cache_valid 404 1m;
|
||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||
add_header X-Cache-Status $upstream_cache_status;
|
||
proxy_cache off;
|
||
}
|
||
|
||
# API路由
|
||
location /api/ {
|
||
limit_req zone=req_limit burst=20 nodelay;
|
||
|
||
proxy_pass http://nextjs_backend;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_read_timeout 86400;
|
||
}
|
||
|
||
# 管理后台(可选IP限制)
|
||
location /admin {
|
||
limit_req zone=req_limit burst=10 nodelay;
|
||
|
||
# 如果需要IP白名单,取消下面的注释
|
||
# allow 192.168.1.0/24;
|
||
# allow 10.0.0.0/8;
|
||
# deny all;
|
||
|
||
proxy_pass http://nextjs_backend;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
}
|
||
|
||
# 根路径
|
||
location / {
|
||
limit_req zone=req_limit burst=20 nodelay;
|
||
|
||
proxy_pass http://nextjs_backend;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
}
|
||
|
||
# 健康检查
|
||
location /health {
|
||
access_log off;
|
||
return 200 "healthy\n";
|
||
add_header Content-Type text/plain;
|
||
}
|
||
|
||
# 错误页面
|
||
error_page 500 502 503 504 /50x.html;
|
||
location = /50x.html {
|
||
root /usr/share/nginx/html;
|
||
internal;
|
||
}
|
||
}
|
||
}
|
||
NGINX_EOF
|
||
|
||
echo "✅ 安全的Nginx配置已创建"
|
||
|
||
# 2. 创建Docker Compose配置
|
||
echo "🐳 创建Docker Compose配置..."
|
||
|
||
cat > "$NGINX_DIR/docker-compose.yml" << 'COMPOSE_EOF'
|
||
version: "3.8"
|
||
|
||
services:
|
||
nginx:
|
||
image: nginx:alpine
|
||
container_name: novalon-nginx
|
||
restart: unless-stopped
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
volumes:
|
||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||
- ./ssl:/etc/nginx/ssl:ro
|
||
- ./logs:/var/log/nginx
|
||
networks:
|
||
- novalon-network
|
||
# 限制容器资源
|
||
deploy:
|
||
resources:
|
||
limits:
|
||
cpus: '1'
|
||
memory: 512M
|
||
reservations:
|
||
cpus: '0.5'
|
||
memory: 256M
|
||
|
||
networks:
|
||
novalon-network:
|
||
driver: bridge
|
||
external: true
|
||
COMPOSE_EOF
|
||
|
||
echo "✅ Docker Compose配置已创建"
|
||
|
||
# 3. 创建SSL目录
|
||
echo "🔒 创建SSL目录..."
|
||
mkdir -p "$NGINX_DIR/ssl"
|
||
echo "✅ SSL目录已创建"
|
||
|
||
# 4. 创建健康检查脚本
|
||
echo "🩺 创建健康检查脚本..."
|
||
mkdir -p "$PROD_DIR/scripts"
|
||
|
||
cat > "$PROD_DIR/scripts/health-check.sh" << 'HEALTH_EOF'
|
||
#!/bin/bash
|
||
|
||
# 健康检查脚本
|
||
echo "[$(date)] 开始健康检查..."
|
||
|
||
# 检查Nginx容器
|
||
if docker ps --filter "name=novalon-nginx" --format "{{.Names}}" | grep -q "novalon-nginx"; then
|
||
echo "✅ Nginx容器运行正常"
|
||
else
|
||
echo "❌ Nginx容器未运行"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查应用容器
|
||
if docker ps --filter "name=novalon-website" --format "{{.Names}}" | grep -q "novalon-website"; then
|
||
echo "✅ 应用容器运行正常"
|
||
else
|
||
echo "❌ 应用容器未运行"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查80端口
|
||
if curl -s -o /dev/null -w "%{http_code}" http://localhost:80 | grep -q "301"; then
|
||
echo "✅ 80端口HTTP重定向正常"
|
||
else
|
||
echo "❌ 80端口配置异常"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查443端口
|
||
if curl -s -o /dev/null -w "%{http_code}" -k https://localhost:443 | grep -q "200"; then
|
||
echo "✅ 443端口HTTPS正常"
|
||
else
|
||
echo "⚠️ 443端口HTTPS可能异常(检查SSL证书)"
|
||
fi
|
||
|
||
# 检查健康检查端点
|
||
if curl -s http://localhost:80/health | grep -q "healthy"; then
|
||
echo "✅ 健康检查端点正常"
|
||
else
|
||
echo "❌ 健康检查端点异常"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ 所有健康检查通过"
|
||
HEALTH_EOF
|
||
|
||
chmod +x "$PROD_DIR/scripts/health-check.sh"
|
||
echo "✅ 健康检查脚本已创建"
|
||
|
||
# 5. 创建安全加固说明文档
|
||
echo "📄 创建安全加固说明文档..."
|
||
|
||
cat > "$PROD_DIR/SECURITY_GUIDE.md" << 'SECURITY_EOF'
|
||
# 生产环境安全加固指南
|
||
|
||
## 作者:张翔
|
||
## 日期:2026-03-31
|
||
|
||
## 概述
|
||
|
||
本文档描述了生产环境的安全加固措施,包括Nginx配置、SSL设置、安全头配置等。
|
||
|
||
## 安全配置清单
|
||
|
||
### ✅ 已完成配置
|
||
|
||
1. **Nginx反向代理**
|
||
- 隐藏后端服务信息
|
||
- 隐藏Nginx版本号
|
||
- 配置安全响应头
|
||
|
||
2. **HTTPS配置**
|
||
- 启用HTTP/2
|
||
- 配置强加密套件
|
||
- 启用OCSP Stapling
|
||
|
||
3. **安全响应头**
|
||
- X-Frame-Options: SAMEORIGIN
|
||
- X-Content-Type-Options: nosniff
|
||
- X-XSS-Protection: 1; mode=block
|
||
- Content-Security-Policy: 严格策略
|
||
- Strict-Transport-Security: HSTS
|
||
|
||
4. **DDoS防护**
|
||
- 请求频率限制
|
||
- 连接数限制
|
||
- 请求体大小限制
|
||
|
||
5. **资源限制**
|
||
- 容器CPU限制
|
||
- 容器内存限制
|
||
|
||
### 🔧 待完成配置
|
||
|
||
1. **SSL证书**
|
||
- 获取SSL证书
|
||
- 配置证书路径
|
||
- 启用HTTPS
|
||
|
||
2. **IP白名单**
|
||
- 配置管理后台IP白名单
|
||
- 限制敏感接口访问
|
||
|
||
3. **WAF配置**
|
||
- 集成ModSecurity
|
||
- 配置规则集
|
||
|
||
4. **监控告警**
|
||
- 配置日志分析
|
||
- 设置告警规则
|
||
|
||
## SSL证书配置
|
||
|
||
### 使用Let's Encrypt
|
||
|
||
```bash
|
||
# 安装certbot
|
||
apt-get update && apt-get install certbot python3-certbot-nginx
|
||
|
||
# 获取证书
|
||
certbot --nginx -d your-domain.com -d www.your-domain.com
|
||
|
||
# 自动续期
|
||
certbot renew --dry-run
|
||
```
|
||
|
||
### 手动配置证书
|
||
|
||
将证书文件放置到:
|
||
- `/home/novalon/docker-app/novalon-nginx/ssl/fullchain.pem`
|
||
- `/home/novalon/docker-app/novalon-nginx/ssl/privkey.pem`
|
||
|
||
然后重启Nginx:
|
||
```bash
|
||
docker-compose -f /home/novalon/docker-app/novalon-nginx/docker-compose.yml restart
|
||
```
|
||
|
||
## 安全检查命令
|
||
|
||
```bash
|
||
# 检查Nginx配置
|
||
docker exec novalon-nginx nginx -t
|
||
|
||
# 重新加载Nginx配置
|
||
docker exec novalon-nginx nginx -s reload
|
||
|
||
# 查看访问日志
|
||
docker logs -f novalon-nginx
|
||
|
||
# 检查SSL配置
|
||
openssl s_client -connect your-domain.com:443 -servername your-domain.com
|
||
|
||
# 测试安全头
|
||
curl -I https://your-domain.com
|
||
```
|
||
|
||
## 应急响应
|
||
|
||
### 如何应对DDoS攻击
|
||
|
||
1. **临时限制IP**
|
||
```bash
|
||
# 在nginx.conf中添加
|
||
deny 192.168.1.1;
|
||
```
|
||
|
||
2. **启用CDN**
|
||
- 使用Cloudflare等CDN服务
|
||
- 隐藏源站IP
|
||
|
||
3. **联系云服务商**
|
||
- 启用DDoS防护
|
||
- 增加带宽限制
|
||
|
||
### 如何应对SQL注入
|
||
|
||
1. **启用WAF规则**
|
||
2. **检查应用代码**
|
||
3. **更新依赖包**
|
||
4. **启用数据库审计**
|
||
|
||
## 定期安全审计
|
||
|
||
### 每日
|
||
- 检查访问日志
|
||
- 监控异常流量
|
||
- 检查健康状态
|
||
|
||
### 每周
|
||
- 审计SSL证书有效期
|
||
- 检查安全头配置
|
||
- 更新依赖包
|
||
|
||
### 每月
|
||
- 全面安全扫描
|
||
- 渗透测试
|
||
- 安全策略审查
|
||
|
||
## 联系方式
|
||
|
||
如有安全问题,请联系:
|
||
- 邮箱:security@your-domain.com
|
||
- 电话:400-xxx-xxxx
|
||
SECURITY_EOF
|
||
|
||
echo "✅ 安全加固说明文档已创建"
|
||
|
||
# 6. 显示加固结果
|
||
echo ""
|
||
echo "=========================================="
|
||
echo "🛡️ 安全加固完成!"
|
||
echo "=========================================="
|
||
echo ""
|
||
echo "✅ 已完成的配置:"
|
||
echo " 1. 安全的Nginx配置"
|
||
echo " 2. Docker Compose配置"
|
||
echo " 3. SSL目录创建"
|
||
echo " 4. 健康检查脚本"
|
||
echo " 5. 安全加固文档"
|
||
echo ""
|
||
echo "📋 下一步操作:"
|
||
echo " 1. 配置SSL证书"
|
||
echo " 2. 重启Nginx服务"
|
||
echo " 3. 验证安全配置"
|
||
echo " 4. 启用监控告警"
|
||
echo ""
|
||
echo "💡 建议操作:"
|
||
echo " cd $PROD_DIR/novalon-nginx"
|
||
echo " docker-compose up -d"
|
||
echo " curl -I http://localhost # 检查HTTP重定向"
|
||
echo " curl -k -I https://localhost # 检查HTTPS"
|
||
echo "" |