rebours/nginx.conf
ordinarthur a9ebfb7b77 clean
2026-02-24 15:36:30 +01:00

114 lines
5.3 KiB
Nginx Configuration File

# ─────────────────────────────────────────────────────────────────────────────
# REBOUR — nginx.conf
# nginx sert public/ directement + proxifie /api/ vers Bun
# ─────────────────────────────────────────────────────────────────────────────
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr "$request" $status $body_bytes_sent "${request_time}s"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server_tokens off;
# ── Gzip ─────────────────────────────────────────────────────────────────
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types
text/plain text/css text/javascript text/xml
application/javascript application/json application/xml
image/svg+xml font/woff2;
# ── Rate limiting ─────────────────────────────────────────────────────────
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/m;
# ── Resolver Docker (résolution dynamique → pas de crash au boot) ─────────
resolver 127.0.0.11 valid=5s ipv6=off;
map $host $api_backend { default "http://app:3000"; }
# ── Redirection HTTP → HTTPS (décommenter en prod) ────────────────────────
# server {
# listen 80;
# server_name rebour.studio www.rebour.studio;
# return 301 https://rebour.studio$request_uri;
# }
server {
listen 80;
server_name _;
# Dossier public servi directement par nginx
root /srv/public;
index index.html;
# ── Headers sécurité ─────────────────────────────────────────────────
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=()" always;
# ── Assets statiques : cache 1 an immutable ───────────────────────────
location ~* \.(jpg|jpeg|png|webp|svg|ico|woff2|css|js)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary "Accept-Encoding";
}
# ── API → proxy vers Bun ──────────────────────────────────────────────
location /api/ {
limit_req zone=api burst=10 nodelay;
proxy_pass $api_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
add_header Cache-Control "no-store";
}
# ── Webhook Stripe : pas de buffering ─────────────────────────────────
location = /api/webhook {
limit_req zone=api burst=5 nodelay;
proxy_pass $api_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header stripe-signature $http_stripe_signature;
proxy_request_buffering off;
add_header Cache-Control "no-store";
}
# ── SEO dynamique (robots/sitemap générés par Bun) ────────────────────
location ~* ^/(robots\.txt|sitemap\.xml)$ {
proxy_pass $api_backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Cache-Control "public, max-age=86400";
}
# ── HTML : index.html pour toutes les routes (SPA-style) ─────────────
location / {
try_files $uri $uri/ $uri.html =404;
add_header Cache-Control "public, max-age=3600, stale-while-revalidate=86400";
}
}
}