From c992edccdcd8ac42c166f3780be52436429e7b94 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 21 Sep 2026 16:39:14 -0400 Subject: [PATCH] ci/cd: add Dockerfile and nginx.conf for production deployment --- Dockerfile | 45 ++++++++++++++++++++++++++++ nginx.conf | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 Dockerfile create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f7e3d66 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +# --- ETAPA 1: Compilación --- +# Usamos el registro moderno de CirrusLabs (ghcr.io) con tu versión de Flutter +FROM ghcr.io/cirruslabs/flutter:3.41.0 AS build-stage + +# Variables de entorno para Flutter/Pub en Docker (incluye mirror oficial para evitar bloqueos de IP en datacenters) +ENV PUB_ENVIRONMENT=docker +ENV PUB_CACHE=/root/.pub-cache +ENV PUB_HOSTED_URL=https://pub.flutter-io.cn +ENV FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn + +# Tus variables de Coolify +ARG COOLIFY_URL=https://med.hidalyx.com +ARG COOLIFY_FQDN=med.hidalyx.com + +# Directorio de trabajo dentro del contenedor +WORKDIR /app + +# Desactivamos telemetría +RUN flutter config --no-analytics + +# Paso 1: Copiamos descriptor y lockfile oficial +COPY pubspec.yaml pubspec.lock ./ + +# Descargamos dependencias de Flutter +RUN flutter pub get + +# Copiamos todo tu código fuente al contenedor +COPY . . + +# Compilamos para web en modo release explícito +RUN flutter build web --release --no-web-resources-cdn + +# --- ETAPA 2: Producción con Nginx --- +FROM nginx:alpine + +# Copiamos la carpeta build/web ya generada en la etapa anterior +COPY --from=build-stage /app/build/web /usr/share/nginx/html + +# Copiamos tu configuración personalizada de Nginx +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +# Arrancamos el servidor +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..908f5fc --- /dev/null +++ b/nginx.conf @@ -0,0 +1,88 @@ +server { + listen 80; + server_name localhost; + + # Soporte MIME type para WebAssembly (Flutter CanvasKit / WASM) + include /etc/nginx/mime.types; + types { + application/wasm wasm; + } + + # Compression optimizations + gzip on; + gzip_vary on; + gzip_min_length 10240; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript application/json application/wasm; + gzip_disable "MSIE [1-6]\."; + + location /api/ { + proxy_pass https://api.hidalyx.com; + + proxy_http_version 1.1; + + proxy_set_header Host api.hidalyx.com; + proxy_ssl_server_name on; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_connect_timeout 60s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + + proxy_redirect off; + } + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + + # Disable caching for entrypoint html + add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + # NEVER CACHE JavaScript entrypoints, manifests, service worker or version files + location ~* (?:index\.html|.*\.js|version\.json|manifest\.json|AssetManifest.*|FontManifest.*|flutter_service_worker\.js)$ { + root /usr/share/nginx/html; + add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always; + add_header Pragma "no-cache" always; + add_header Expires "0" always; + add_header Cloudflare-CDN-Cache-Control "no-store, no-cache, max-age=0" always; + add_header CDN-Cache-Control "no-store, no-cache, max-age=0" always; + } + + # Font files and icons (MaterialIcons, Inter, Cupertino): + # Short cache with mandatory revalidation to immediately load new glyphs on deploy + location ~* \.(?:otf|ttf|woff2?|eot)$ { + root /usr/share/nginx/html; + expires 1h; + add_header Cache-Control "public, max-age=3600, must-revalidate" always; + add_header Access-Control-Allow-Origin "*" always; + } + + # Static media assets (images, audio, css, wasm) + location ~* \.(?:ico|css|gif|jpe?g|png|wasm)$ { + root /usr/share/nginx/html; + expires 7d; + add_header Cache-Control "public, max-age=604800" always; + } + + # SVGs (quick revalidation to avoid stale logo caches) + location ~* \.svg$ { + root /usr/share/nginx/html; + add_header Cache-Control "no-cache, must-revalidate" always; + add_header Pragma "no-cache" always; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + +}