From c7e9c57b82e18e19a55c18f9e3a7fc0c98cf2d50 Mon Sep 17 00:00:00 2001 From: David Montero Date: Fri, 6 Mar 2026 21:20:44 +0100 Subject: [PATCH] feat: add production deployment configuration with SSL support - Add docker-compose.prod.yml for standalone production deployment - Add nginx-host-velxio.conf for host nginx reverse proxy with SSL - Update deploy/nginx.conf with security headers, gzip, and health endpoint - Add deploy/nginx.prod.conf for production nginx configuration Co-Authored-By: Claude Opus 4.5 --- deploy/nginx.conf | 27 +++++++++++++++++--- deploy/nginx.prod.conf | 56 +++++++++++++++++++++++++++++++++++++++++ docker-compose.prod.yml | 15 +++++++++++ nginx-host-velxio.conf | 56 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 deploy/nginx.prod.conf create mode 100644 docker-compose.prod.yml create mode 100644 nginx-host-velxio.conf diff --git a/deploy/nginx.conf b/deploy/nginx.conf index dfdb858..df7b410 100644 --- a/deploy/nginx.conf +++ b/deploy/nginx.conf @@ -1,28 +1,42 @@ server { listen 80; - server_name localhost; + server_name localhost velxio.dev www.velxio.dev; root /usr/share/nginx/html; index index.html; + # Security headers + 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; + # Frontend SPA routing location / { try_files $uri $uri/ /index.html; } + # Health check endpoint + location /health { + proxy_pass http://127.0.0.1:8001/health; + proxy_set_header Host $host; + } + # Proxy /api requests to localhost backend location /api/ { proxy_pass http://127.0.0.1:8001/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_connect_timeout 75s; } # Proxy websockets/docs if needed location /docs { proxy_pass http://127.0.0.1:8001/docs; } - + location /openapi.json { proxy_pass http://127.0.0.1:8001/openapi.json; } @@ -32,4 +46,11 @@ server { expires 1y; add_header Cache-Control "public, immutable"; } + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied any; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml; } diff --git a/deploy/nginx.prod.conf b/deploy/nginx.prod.conf new file mode 100644 index 0000000..2c96cc1 --- /dev/null +++ b/deploy/nginx.prod.conf @@ -0,0 +1,56 @@ +server { + listen 80; + server_name velxio.dev www.velxio.dev; + root /usr/share/nginx/html; + index index.html; + + # Security headers + 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; + + # Frontend SPA routing + location / { + try_files $uri $uri/ /index.html; + } + + # Health check endpoint + location /health { + proxy_pass http://127.0.0.1:8001/health; + proxy_set_header Host $host; + } + + # Proxy /api requests to localhost backend + location /api/ { + proxy_pass http://127.0.0.1:8001/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; + proxy_read_timeout 300s; + proxy_connect_timeout 75s; + } + + # Proxy websockets/docs if needed + location /docs { + proxy_pass http://127.0.0.1:8001/docs; + } + + location /openapi.json { + proxy_pass http://127.0.0.1:8001/openapi.json; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied any; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml; +} diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..f260d72 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,15 @@ +services: + velxio: + build: + context: . + dockerfile: Dockerfile.standalone + container_name: velxio-app + restart: unless-stopped + ports: + - "3080:80" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 90s diff --git a/nginx-host-velxio.conf b/nginx-host-velxio.conf new file mode 100644 index 0000000..032fc9b --- /dev/null +++ b/nginx-host-velxio.conf @@ -0,0 +1,56 @@ +# Configuración de Nginx para velxio.dev +# Copiar a: /etc/nginx/sites-available/velxio.dev +# Luego: sudo ln -s /etc/nginx/sites-available/velxio.dev /etc/nginx/sites-enabled/ + +server { + listen 80; + server_name velxio.dev www.velxio.dev; + + # Redirect HTTP to HTTPS + location / { + return 301 https://$host$request_uri; + } + + # Let's Encrypt challenge + location /.well-known/acme-challenge/ { + root /var/www/html; + } +} + +server { + listen 443 ssl http2; + server_name velxio.dev www.velxio.dev; + + # SSL certificates (generados por certbot) + ssl_certificate /etc/letsencrypt/live/velxio.dev/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/velxio.dev/privkey.pem; + + # SSL configuration + 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; + + # Security headers + 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 Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # Proxy to Docker container + location / { + proxy_pass http://127.0.0.1:3080; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 300s; + proxy_connect_timeout 75s; + proxy_buffering off; + } +}