#!/bin/bash # 导入环境检测脚本 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/detect-environment.sh" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 log_info() { echo -e "${BLUE}ℹ️ $1${NC}" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } # 生成环境变量文件 generate_env_file() { log_info "生成环境变量配置..." local env_file=".env" # 生成随机密码 local turn_password=$(openssl rand -base64 32 2>/dev/null || echo "privydrop$(date +%s)") cat > "$env_file" << EOF # PrivyDrop Docker 配置文件 # 自动生成时间: $(date) # 网络模式: $NETWORK_MODE # 部署模式: $DEPLOYMENT_MODE # ============================================================================= # 网络配置 # ============================================================================= CORS_ORIGIN=http://${LOCAL_IP} NEXT_PUBLIC_API_URL=http://${LOCAL_IP}:3001 # ============================================================================= # 端口配置 # ============================================================================= FRONTEND_PORT=3000 BACKEND_PORT=3001 HTTP_PORT=80 HTTPS_PORT=443 # ============================================================================= # Redis配置 # ============================================================================= REDIS_HOST=redis REDIS_PORT=6379 # ============================================================================= # 部署配置 # ============================================================================= DEPLOYMENT_MODE=${DEPLOYMENT_MODE} NETWORK_MODE=${NETWORK_MODE} LOCAL_IP=${LOCAL_IP} PUBLIC_IP=${PUBLIC_IP:-} # ============================================================================= # SSL配置 # ============================================================================= SSL_MODE=self-signed DOMAIN_NAME=${DOMAIN_NAME:-} # ============================================================================= # TURN服务器配置 (可选) # ============================================================================= TURN_ENABLED=${TURN_ENABLED:-false} TURN_USERNAME=privydrop TURN_PASSWORD=${turn_password} TURN_REALM=${DOMAIN_NAME:-turn.local} # ============================================================================= # Nginx配置 # ============================================================================= NGINX_SERVER_NAME=${DOMAIN_NAME:-${LOCAL_IP}} # ============================================================================= # 日志配置 # ============================================================================= LOG_LEVEL=info EOF # 根据部署模式调整配置 if [[ "$DEPLOYMENT_MODE" == "full" ]]; then sed -i "s|CORS_ORIGIN=http://|CORS_ORIGIN=https://|g" "$env_file" sed -i "s|NEXT_PUBLIC_API_URL=http://|NEXT_PUBLIC_API_URL=https://|g" "$env_file" sed -i "s|SSL_MODE=self-signed|SSL_MODE=letsencrypt|g" "$env_file" sed -i "s|TURN_ENABLED=false|TURN_ENABLED=true|g" "$env_file" elif [[ "$DEPLOYMENT_MODE" == "public" ]]; then sed -i "s|TURN_ENABLED=false|TURN_ENABLED=true|g" "$env_file" fi log_success "环境变量配置已生成: $env_file" } # 生成Nginx配置 generate_nginx_config() { log_info "生成Nginx配置..." mkdir -p docker/nginx/conf.d local server_name="${DOMAIN_NAME:-${LOCAL_IP} localhost}" local upstream_backend="backend:3001" local upstream_frontend="frontend:3000" # 生成主Nginx配置 cat > docker/nginx/nginx.conf << 'EOF' user nginx; 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"'; access_log /var/log/nginx/access.log main; # 基础配置 sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; # 客户端配置 client_max_body_size 100M; client_header_timeout 60s; client_body_timeout 60s; # Gzip配置 gzip on; gzip_vary on; gzip_min_length 1000; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; # 包含站点配置 include /etc/nginx/conf.d/*.conf; } EOF # 生成站点配置 cat > docker/nginx/conf.d/default.conf << EOF # 上游服务定义 upstream backend { server ${upstream_backend}; keepalive 32; } upstream frontend { server ${upstream_frontend}; keepalive 32; } # HTTP服务器配置 server { listen 80; server_name ${server_name}; # 安全头 add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; # 健康检查端点 location /nginx-health { access_log off; return 200 "healthy\n"; add_header Content-Type text/plain; } # 后端API代理 location /api/ { proxy_pass http://backend/api/; 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_bypass \$http_upgrade; # 超时配置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # 后端健康检查代理 location /health { proxy_pass http://backend/health; proxy_http_version 1.1; 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; } # Socket.IO代理 location /socket.io/ { proxy_pass http://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; # WebSocket特殊配置 proxy_buffering off; proxy_cache off; } # 前端应用代理 location / { proxy_pass http://frontend; 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_bypass \$http_upgrade; # Next.js特殊配置 proxy_buffering off; } } EOF log_success "Nginx配置已生成" echo " 主配置: docker/nginx/nginx.conf" echo " 站点配置: docker/nginx/conf.d/default.conf" } # 生成SSL证书 generate_ssl_certificates() { if [[ "$SSL_MODE" == "self-signed" ]] || [[ "$NETWORK_MODE" == "private" ]]; then log_info "生成自签名SSL证书..." mkdir -p docker/ssl # 生成CA私钥 openssl genrsa -out docker/ssl/ca-key.pem 4096 2>/dev/null # 生成CA证书 openssl req -new -x509 -days 365 -key docker/ssl/ca-key.pem \ -out docker/ssl/ca-cert.pem \ -subj "/C=CN/ST=Local/L=Local/O=PrivyDrop/CN=PrivyDrop-CA" 2>/dev/null # 生成服务器私钥 openssl genrsa -out docker/ssl/server-key.pem 4096 2>/dev/null # 生成服务器证书请求 openssl req -new -key docker/ssl/server-key.pem \ -out docker/ssl/server.csr \ -subj "/C=CN/ST=Local/L=Local/O=PrivyDrop/CN=${LOCAL_IP}" 2>/dev/null # 创建扩展配置 cat > docker/ssl/server.ext << EOF authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = localhost DNS.2 = *.local DNS.3 = ${DOMAIN_NAME:-privydrop.local} IP.1 = ${LOCAL_IP} IP.2 = 127.0.0.1 EOF # 签名服务器证书 openssl x509 -req -days 365 -in docker/ssl/server.csr \ -CA docker/ssl/ca-cert.pem -CAkey docker/ssl/ca-key.pem \ -out docker/ssl/server-cert.pem -CAcreateserial \ -extensions v3_req -extfile docker/ssl/server.ext 2>/dev/null # 清理临时文件 rm -f docker/ssl/server.csr docker/ssl/server.ext docker/ssl/ca-cert.srl # 设置权限 chmod 600 docker/ssl/*-key.pem chmod 644 docker/ssl/*-cert.pem log_success "SSL证书已生成: docker/ssl/" log_info "要信任证书,请导入CA证书: docker/ssl/ca-cert.pem" # 生成HTTPS Nginx配置 if [[ "$DEPLOYMENT_MODE" != "basic" ]]; then generate_https_nginx_config fi fi } # 生成HTTPS Nginx配置 generate_https_nginx_config() { log_info "生成HTTPS Nginx配置..." cat >> docker/nginx/conf.d/default.conf << EOF # HTTPS服务器配置 server { listen 443 ssl http2; server_name ${DOMAIN_NAME:-${LOCAL_IP}}; # SSL配置 ssl_certificate /etc/nginx/ssl/server-cert.pem; ssl_certificate_key /etc/nginx/ssl/server-key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 安全头 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; # 健康检查端点 location /nginx-health { access_log off; return 200 "healthy\n"; add_header Content-Type text/plain; } # 后端API代理 location /api/ { proxy_pass http://backend/api/; 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 https; proxy_cache_bypass \$http_upgrade; } # 后端健康检查代理 location /health { proxy_pass http://backend/health; proxy_http_version 1.1; 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 https; } # Socket.IO代理 location /socket.io/ { proxy_pass http://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 https; proxy_buffering off; proxy_cache off; } # 前端应用代理 location / { proxy_pass http://frontend; 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 https; proxy_cache_bypass \$http_upgrade; proxy_buffering off; } } EOF log_success "HTTPS配置已添加" } # 生成Coturn配置 generate_coturn_config() { if [[ "$TURN_ENABLED" == "true" ]]; then log_info "生成Coturn TURN服务器配置..." mkdir -p docker/coturn cat > docker/coturn/turnserver.conf << EOF # PrivyDrop TURN服务器配置 # 自动生成时间: $(date) # 监听端口 listening-port=3478 tls-listening-port=5349 # 监听IP listening-ip=0.0.0.0 relay-ip=0.0.0.0 # 外部IP (用于NAT环境) external-ip=${PUBLIC_IP:-${LOCAL_IP}} # 服务器域名 realm=${TURN_REALM} server-name=${TURN_REALM} # 认证方式 lt-cred-mech # 用户认证 user=${TURN_USERNAME}:${TURN_PASSWORD} # SSL证书 (如果启用TLS) cert=/etc/ssl/certs/server-cert.pem pkey=/etc/ssl/certs/server-key.pem # 日志配置 no-stdout-log log-file=/var/log/turnserver.log verbose # 安全配置 no-cli no-loopback-peers no-multicast-peers # 性能配置 min-port=49152 max-port=65535 # 数据库 (可选) # userdb=/var/lib/turn/turndb # 其他配置 mobility no-tlsv1 no-tlsv1_1 EOF log_success "Coturn配置已生成: docker/coturn/turnserver.conf" log_info "TURN服务器用户名: ${TURN_USERNAME}" log_warning "TURN服务器密码已保存在.env文件中" fi } # 生成Docker忽略文件 generate_dockerignore() { log_info "生成Docker忽略文件..." # 后端.dockerignore cat > backend/.dockerignore << EOF node_modules npm-debug.log* .npm .env* .git .gitignore README.md Dockerfile .dockerignore coverage .nyc_output logs *.log EOF # 前端.dockerignore cat > frontend/.dockerignore << EOF node_modules .next .git .gitignore README.md Dockerfile .dockerignore .env* npm-debug.log* .npm coverage .nyc_output *.log public/sw.js public/workbox-*.js EOF log_success "Docker忽略文件已生成" } # 创建日志目录 create_log_directories() { log_info "创建日志目录..." mkdir -p logs/{nginx,backend,frontend,coturn} # 设置权限 chmod 755 logs chmod 755 logs/* log_success "日志目录已创建: logs/" } # 主函数 main() { echo -e "${BLUE}=== PrivyDrop 配置生成 ===${NC}" echo "" # 首先运行环境检测 if ! detect_network_environment; then log_error "环境检测失败" exit 1 fi if ! check_system_resources; then log_error "系统资源检查失败" exit 1 fi detect_deployment_mode echo "" # 生成所有配置文件 generate_env_file echo "" generate_nginx_config echo "" generate_ssl_certificates echo "" generate_coturn_config echo "" generate_dockerignore echo "" create_log_directories echo "" log_success "🎉 所有配置文件生成完成!" echo "" echo -e "${BLUE}生成的文件:${NC}" echo " .env - 环境变量配置" echo " docker/nginx/ - Nginx配置" echo " docker/ssl/ - SSL证书" [[ "$TURN_ENABLED" == "true" ]] && echo " docker/coturn/ - TURN服务器配置" echo " logs/ - 日志目录" echo "" echo -e "${BLUE}下一步:${NC}" echo " 运行 './deploy.sh' 开始部署" } # 如果脚本被直接执行 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi