server { listen 80; server_name mieterportal.hocks.eu localhost _; root /usr/share/nginx/html; index index.html; gzip on; gzip_types text/css application/javascript image/svg+xml application/json; gzip_min_length 1024; # Docker-eigener DNS: Upstream-Namen bei jeder Anfrage neu auflösen. # Ohne das puffert nginx die Container-IP vom Start – nach einem Recreate # der API (neue IP) liefert jede Anfrage 502, bis nginx selbst neu startet. resolver 127.0.0.11 valid=10s; # HTML nie cachen (Assets sind hash-benannt → ein Reload genügt) location = /index.html { add_header Cache-Control "no-cache" always; } # Cache für gehashte Build-Assets (^~ = Prefix schlägt Regex-Locations, # sonst würde die Bild-Regel unten das immutable-Caching überschreiben) location ^~ /assets/ { expires 30d; add_header Cache-Control "public, immutable"; } # Statische Dateien im Root (Logo, Favicons – nicht hash-benannt, # daher nur kurz cachen, sonst riskiert der Browser veraltete Dateien) location ~* \.(png|jpg|jpeg|webp|ico|svg|woff2?)$ { expires 1d; add_header Cache-Control "public"; } # Mail-API des Portals (Container mp-mail-api im selben Docker-Netz npm_default). # Das Token kommt aus portal.env (envsubst beim Container-Start) und liegt # NIE im Repo und NIE im Browser – der Endpunkt ist nur vom Server erreichbar. location = /api/mail/send { limit_except POST { deny all; } set $mail_api http://mp-mail-api:8080; proxy_pass $mail_api/send; proxy_set_header Host $host; proxy_set_header X-Api-Token "${MAIL_API_TOKEN}"; proxy_set_header X-Request-Source mieterportal-nginx; client_max_body_size 64k; proxy_read_timeout 15s; } # Portal-API (Node/Express + PostgreSQL): Auth, Daten, Benachrichtigungen, # Dokumenten-Uploads/-Downloads (PDF bis 25 MB). location /api/ { set $portal_api http://mp-api:3000; proxy_pass $portal_api; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; client_max_body_size 25m; proxy_read_timeout 60s; } # SPA-Fallback für React Router location / { try_files $uri $uri/ /index.html; } add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; }