# ============================================ # Configuración Nginx para App Canchas de Pádel # ============================================ # Ubicación: /etc/nginx/sites-available/app-padel # Activar con: ln -s /etc/nginx/sites-available/app-padel /etc/nginx/sites-enabled/ # ============================================ # Upstream para la API - Balanceo de carga upstream app_padel_api { least_conn; server 127.0.0.1:3000 max_fails=3 fail_timeout=30s; # Añadir más servidores para escalar horizontalmente: # server 127.0.0.1:3001 max_fails=3 fail_timeout=30s; # server 127.0.0.1:3002 max_fails=3 fail_timeout=30s; keepalive 32; } # Rate limiting zones limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/m; limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # Map para determinar si es un webhook map $uri $is_webhook { ~^/api/v1/(payments|subscriptions)/webhook 0; default 1; } # Servidor HTTP - Redirección a HTTPS server { listen 80; server_name api.tudominio.com; # Redirigir todo a HTTPS location / { return 301 https://$server_name$request_uri; } # Certbot challenge (para renovación SSL) location /.well-known/acme-challenge/ { root /var/www/certbot; } } # Servidor HTTPS server { listen 443 ssl http2; server_name api.tudominio.com; # ============================================ # SSL Configuration (Let's Encrypt) # ============================================ ssl_certificate /etc/letsencrypt/live/api.tudominio.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.tudominio.com/privkey.pem; # SSL Security 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 10m; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/letsencrypt/live/api.tudominio.com/chain.pem; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; # Security headers add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; 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 Permissions-Policy "geolocation=(), microphone=(), camera=()" always; # ============================================ # Logging # ============================================ access_log /var/log/nginx/app-padel-access.log; error_log /var/log/nginx/app-padel-error.log warn; # ============================================ # General Configuration # ============================================ # Client body size client_max_body_size 10M; client_body_buffer_size 128k; # Timeouts client_header_timeout 30s; client_body_timeout 30s; send_timeout 30s; keepalive_timeout 65s; # Gzip compression gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml; # ============================================ # Routes Configuration # ============================================ # Root - API Info location / { return 200 '{"status":"API App Canchas de Pádel","version":"1.0.0","docs":"/api/v1/health"}'; add_header Content-Type application/json; access_log off; } # Health check (lightweight, no rate limit) location /api/v1/health { proxy_pass http://app_padel_api; 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; access_log off; # Fast response for health checks proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; } # Webhooks de MercadoPago (sin rate limit, timeout extendido) location ~ ^/api/v1/(payments|subscriptions)/webhook { proxy_pass http://app_padel_api; 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; # Webhooks necesitan tiempo para procesar proxy_read_timeout 60s; proxy_connect_timeout 60s; proxy_send_timeout 60s; # Buffering desactivado para webhooks proxy_buffering off; proxy_request_buffering off; # Sin rate limiting para webhooks limit_req off; limit_conn off; } # Auth endpoints (rate limit más estricto) location ~ ^/api/v1/auth/(login|register|refresh)$ { limit_req zone=auth_limit burst=10 nodelay; limit_conn conn_limit 10; proxy_pass http://app_padel_api; 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; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_connect_timeout 30s; proxy_send_timeout 30s; proxy_read_timeout 30s; } # API endpoints (rate limit estándar) location /api/ { limit_req zone=api_limit burst=20 nodelay; limit_conn conn_limit 50; proxy_pass http://app_padel_api; 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; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header Connection ""; # Timeouts proxy_connect_timeout 30s; proxy_send_timeout 30s; proxy_read_timeout 300s; # Buffer settings proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; # Cache control for API responses proxy_hide_header X-Powered-By; proxy_hide_header Server; } # Denegar acceso a archivos sensibles location ~ /\. { deny all; access_log off; log_not_found off; } location ~* \.(env|env\.local|env\.production|env\.development)$ { deny all; access_log off; log_not_found off; } location ~* \.(git|gitignore|gitattributes)$ { deny all; access_log off; log_not_found off; } # Favicon y robots.txt location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; return 200 "User-agent: *\nDisallow: /api/\n"; } } # ============================================ # Configuración para múltiples dominios (opcional) # ============================================ # Si necesitas servir el frontend desde el mismo servidor: # server { # listen 443 ssl http2; # server_name tudominio.com www.tudominio.com; # # ssl_certificate /etc/letsencrypt/live/tudominio.com/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem; # # # Frontend static files # root /var/www/frontend/dist; # index index.html; # # location / { # try_files $uri $uri/ /index.html; # } # # # API proxy # location /api/ { # proxy_pass http://app_padel_api; # 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; # } # }