UNPKG

claude-code-templates

Version:

CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects

621 lines (503 loc) 15.1 kB
# Flask Deployment Configuration Complete production deployment setup for Flask applications. ## Usage ```bash # Build Docker image docker build -t myapp . # Run with Docker Compose docker-compose up -d # Deploy to cloud gunicorn --bind 0.0.0.0:8000 app:app ``` ## Production Configuration ```python # config.py import os from urllib.parse import quote_plus class ProductionConfig: """Production configuration.""" # Security SECRET_KEY = os.environ.get('SECRET_KEY') DEBUG = False TESTING = False # Database SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ f"postgresql://{os.environ.get('DB_USER')}:{quote_plus(os.environ.get('DB_PASSWORD'))}@" \ f"{os.environ.get('DB_HOST')}:{os.environ.get('DB_PORT', '5432')}/{os.environ.get('DB_NAME')}" SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = { 'pool_size': 10, 'max_overflow': 20, 'pool_recycle': 3600, 'pool_pre_ping': True } # Security Headers SECURITY_HEADERS = { 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" } # Session SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Lax' PERMANENT_SESSION_LIFETIME = 3600 # 1 hour # Cache CACHE_TYPE = 'redis' CACHE_REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/0') CACHE_DEFAULT_TIMEOUT = 300 # Rate Limiting RATELIMIT_STORAGE_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/1') RATELIMIT_DEFAULT = '100/hour' # Logging LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') LOG_FILE = os.environ.get('LOG_FILE', '/var/log/app/app.log') # File Upload MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', '/var/uploads') # Email MAIL_SERVER = os.environ.get('MAIL_SERVER') MAIL_PORT = int(os.environ.get('MAIL_PORT', 587)) MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in ['true', 'on', '1'] MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') MAIL_DEFAULT_SENDER = os.environ.get('MAIL_DEFAULT_SENDER') ``` ## WSGI Configuration ```python # wsgi.py import os from app import create_app # Get environment config_name = os.environ.get('FLASK_ENV', 'production') app = create_app(config_name) if __name__ == "__main__": app.run() ``` ## Gunicorn Configuration ```python # gunicorn.conf.py import multiprocessing import os # Server socket bind = f"0.0.0.0:{os.environ.get('PORT', 8000)}" backlog = 2048 # Worker processes workers = multiprocessing.cpu_count() * 2 + 1 worker_class = 'sync' worker_connections = 1000 timeout = 30 keepalive = 60 max_requests = 1000 max_requests_jitter = 100 # Security limit_request_line = 4094 limit_request_fields = 100 limit_request_field_size = 8190 # Logging accesslog = '-' errorlog = '-' loglevel = os.environ.get('LOG_LEVEL', 'info').lower() access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s' # Process naming proc_name = 'flask_app' # Server mechanics daemon = False pidfile = '/tmp/gunicorn.pid' user = os.environ.get('USER', 'www-data') group = os.environ.get('GROUP', 'www-data') tmp_upload_dir = None # SSL keyfile = os.environ.get('SSL_KEYFILE') certfile = os.environ.get('SSL_CERTFILE') ``` ## Docker Configuration ```dockerfile # Dockerfile FROM python:3.11-slim # Set environment variables ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=1 \ PIP_DISABLE_PIP_VERSION_CHECK=1 # Install system dependencies RUN apt-get update && apt-get install -y \ build-essential \ libpq-dev \ curl \ && rm -rf /var/lib/apt/lists/* # Create app user RUN groupadd -r appuser && useradd -r -g appuser appuser # Set work directory WORKDIR /app # Install Python dependencies COPY requirements/production.txt ./requirements.txt RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY . . # Create necessary directories RUN mkdir -p /var/log/app /var/uploads && \ chown -R appuser:appuser /app /var/log/app /var/uploads # Switch to non-root user USER appuser # Expose port EXPOSE 8000 # Health check HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 # Run application CMD ["gunicorn", "--config", "gunicorn.conf.py", "wsgi:app"] ``` ## Docker Compose ```yaml # docker-compose.yml version: '3.8' services: web: build: . ports: - "8000:8000" environment: - FLASK_ENV=production - DATABASE_URL=postgresql://postgres:password@db:5432/myapp - REDIS_URL=redis://redis:6379/0 - SECRET_KEY=${SECRET_KEY} depends_on: - db - redis volumes: - uploads:/var/uploads - logs:/var/log/app restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 db: image: postgres:15 environment: - POSTGRES_DB=myapp - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 30s timeout: 10s retries: 3 redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - redis_data:/data restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 30s timeout: 10s retries: 3 nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro - uploads:/var/uploads:ro depends_on: - web restart: unless-stopped volumes: postgres_data: redis_data: uploads: logs: ``` ## Nginx Configuration ```nginx # nginx.conf events { worker_connections 1024; } http { upstream app { server web:8000; } # Rate limiting limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s; # SSL configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # Security headers add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; server { listen 80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; # File upload size client_max_body_size 16M; # Static files location /static/ { alias /var/uploads/static/; expires 1y; add_header Cache-Control "public, immutable"; } location /uploads/ { alias /var/uploads/; expires 1h; } # API rate limiting location /api/ { limit_req zone=api burst=20 nodelay; proxy_pass http://app; 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; } # Login rate limiting location /auth/login { limit_req zone=login burst=5 nodelay; proxy_pass http://app; 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; } # Main application location / { proxy_pass http://app; 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; # Timeout settings proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } } } ``` ## Environment Variables ```bash # .env.production # Application FLASK_ENV=production SECRET_KEY=your-super-secret-key-here # Database DATABASE_URL=postgresql://user:password@localhost:5432/myapp DB_HOST=localhost DB_PORT=5432 DB_NAME=myapp DB_USER=user DB_PASSWORD=password # Redis REDIS_URL=redis://localhost:6379/0 # Email MAIL_SERVER=smtp.gmail.com MAIL_PORT=587 MAIL_USE_TLS=true MAIL_USERNAME=your-email@gmail.com MAIL_PASSWORD=your-app-password MAIL_DEFAULT_SENDER=your-email@gmail.com # Logging LOG_LEVEL=INFO LOG_FILE=/var/log/app/app.log # File Upload UPLOAD_FOLDER=/var/uploads # SSL (if using) SSL_KEYFILE=/path/to/private.key SSL_CERTFILE=/path/to/certificate.crt ``` ## Health Check Endpoint ```python # app/health.py from flask import Blueprint, jsonify from app.extensions import db from sqlalchemy import text import redis import os health_bp = Blueprint('health', __name__) @health_bp.route('/health') def health_check(): """Application health check.""" checks = { 'status': 'healthy', 'database': check_database(), 'redis': check_redis(), 'disk_space': check_disk_space() } # Determine overall status if all(check['status'] == 'ok' for check in checks.values() if isinstance(check, dict)): status_code = 200 else: status_code = 503 checks['status'] = 'unhealthy' return jsonify(checks), status_code def check_database(): """Check database connectivity.""" try: db.session.execute(text('SELECT 1')) return {'status': 'ok', 'message': 'Database connection successful'} except Exception as e: return {'status': 'error', 'message': str(e)} def check_redis(): """Check Redis connectivity.""" try: redis_url = os.environ.get('REDIS_URL', 'redis://localhost:6379/0') r = redis.from_url(redis_url) r.ping() return {'status': 'ok', 'message': 'Redis connection successful'} except Exception as e: return {'status': 'error', 'message': str(e)} def check_disk_space(): """Check available disk space.""" try: import shutil total, used, free = shutil.disk_usage('/') free_percent = (free / total) * 100 if free_percent > 10: status = 'ok' elif free_percent > 5: status = 'warning' else: status = 'critical' return { 'status': status, 'free_space_percent': round(free_percent, 2), 'free_space_gb': round(free / (1024**3), 2) } except Exception as e: return {'status': 'error', 'message': str(e)} ``` ## Monitoring and Logging ```python # app/logging.py import logging import logging.handlers import os from flask import request, g import time def setup_logging(app): """Setup application logging.""" if not app.debug and not app.testing: # File logging if app.config.get('LOG_FILE'): file_handler = logging.handlers.RotatingFileHandler( app.config['LOG_FILE'], maxBytes=10240000, # 10MB backupCount=10 ) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s ' '[in %(pathname)s:%(lineno)d]' )) file_handler.setLevel(getattr(logging, app.config.get('LOG_LEVEL', 'INFO'))) app.logger.addHandler(file_handler) # Console logging if not app.logger.handlers: stream_handler = logging.StreamHandler() stream_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s' )) stream_handler.setLevel(logging.INFO) app.logger.addHandler(stream_handler) app.logger.setLevel(logging.INFO) app.logger.info('Application startup') # Request timing middleware @app.before_request def before_request(): g.start_time = time.time() @app.after_request def after_request(response): if hasattr(g, 'start_time'): duration = time.time() - g.start_time app.logger.info( f'{request.method} {request.path} - ' f'{response.status_code} - {duration:.3f}s' ) return response ``` ## Database Backup Script ```bash #!/bin/bash # backup.sh set -e # Configuration BACKUP_DIR="/var/backups/db" DATABASE_URL="$DATABASE_URL" DATE=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/backup_$DATE.sql" RETENTION_DAYS=7 # Create backup directory mkdir -p "$BACKUP_DIR" # Create backup echo "Creating database backup..." pg_dump "$DATABASE_URL" > "$BACKUP_FILE" # Compress backup gzip "$BACKUP_FILE" # Remove old backups echo "Cleaning up old backups..." find "$BACKUP_DIR" -name "backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete echo "Backup completed: $BACKUP_FILE.gz" ``` ## Deployment Scripts ```bash #!/bin/bash # deploy.sh set -e echo "Starting deployment..." # Pull latest code git pull origin main # Build new Docker image docker-compose build web # Run database migrations docker-compose run --rm web flask db upgrade # Update services docker-compose up -d # Health check echo "Waiting for application to be ready..." sleep 10 if curl -f http://localhost:8000/health; then echo "Deployment successful!" else echo "Deployment failed - health check failed" exit 1 fi ``` ## Monitoring with Prometheus ```python # app/metrics.py from prometheus_flask_exporter import PrometheusMetrics from flask import request import time def setup_metrics(app): """Setup Prometheus metrics.""" metrics = PrometheusMetrics(app) # Custom metrics metrics.info('app_info', 'Application info', version='1.0.0') # Database connection pool metrics @metrics.gauge('db_pool_size', 'Database connection pool size') def db_pool_size(): from app.extensions import db return db.engine.pool.size() return metrics ```