diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index bce4f8f..6e21676 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -9,8 +9,10 @@ services: container_name: tinyurl-nginx ports: - "80:80" + - "443:443" volumes: - ./infra/nginx/nginx.prod.conf:/etc/nginx/nginx.conf:ro + - /etc/letsencrypt:/etc/letsencrypt:ro depends_on: app: condition: service_healthy diff --git a/infra/nginx/nginx.prod.conf b/infra/nginx/nginx.prod.conf index 6c05a26..6d0b0cf 100644 --- a/infra/nginx/nginx.prod.conf +++ b/infra/nginx/nginx.prod.conf @@ -6,19 +6,32 @@ http { # ----------------------------------------------------------------------- # Real IP Resolution # - # Traffic path: Client → Cloudflare → ALB → nginx - # Without this, $remote_addr = ALB private IP (10.x.x.x) for every request. - # Rate limiting keyed on ALB IP = all users share one limit = broken. + # Traffic path: Client → Cloudflare → nginx (no ALB) + # Without this, $remote_addr = Cloudflare edge IP for every request. + # Rate limiting keyed on Cloudflare IP = all users share one limit = broken. # - # set_real_ip_from: trust the VPC (ALB) to forward the real client IP. + # set_real_ip_from: trust Cloudflare's published IP ranges. # real_ip_header: read real client IP from Cloudflare's CF-Connecting-IP. # real_ip_recursive: strip known proxy IPs from the chain to find the origin. # # After this, $remote_addr = actual client IP for all directives below. + # Cloudflare IP ranges: https://www.cloudflare.com/ips/ # ----------------------------------------------------------------------- - set_real_ip_from 10.0.0.0/8; - set_real_ip_from 172.16.0.0/12; - set_real_ip_from 192.168.0.0/16; + set_real_ip_from 173.245.48.0/20; + set_real_ip_from 103.21.244.0/22; + set_real_ip_from 103.22.200.0/22; + set_real_ip_from 103.31.4.0/22; + set_real_ip_from 141.101.64.0/18; + set_real_ip_from 108.162.192.0/18; + set_real_ip_from 190.93.240.0/20; + set_real_ip_from 188.114.96.0/20; + set_real_ip_from 197.234.240.0/22; + set_real_ip_from 198.41.128.0/17; + set_real_ip_from 162.158.0.0/15; + set_real_ip_from 104.16.0.0/13; + set_real_ip_from 104.24.0.0/14; + set_real_ip_from 172.64.0.0/13; + set_real_ip_from 131.0.72.0/22; real_ip_header CF-Connecting-IP; real_ip_recursive on; @@ -83,9 +96,21 @@ http { gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json; + # HTTP → HTTPS redirect server { listen 80; server_name go.buffden.com; + return 301 https://$host$request_uri; + } + + server { + listen 443 ssl; + server_name go.buffden.com; + + ssl_certificate /etc/letsencrypt/live/go.buffden.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/go.buffden.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; # ------------------------------------------------------------------- # Block malicious scanner tools by User-Agent @@ -213,9 +238,8 @@ http { } # ------------------------------------------------------------------- - # ALB Health Check — must be before the /actuator/ block - # ALB targets port 80 on EC2 and checks this path every 30s. - # If this returns anything other than 200, the target goes Unhealthy. + # Health Check endpoint — must be before the /actuator/ block + # Used by monitoring and CI/CD deploy verification. # ------------------------------------------------------------------- location = /actuator/health { proxy_pass http://app:8080;