114 lines
5.3 KiB
Nginx Configuration File
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";
|
|
}
|
|
}
|
|
}
|