149 lines
5.8 KiB
Nginx Configuration File
149 lines
5.8 KiB
Nginx Configuration File
# =============================================================================
|
|
# deploy/nginx.conf — Configuration Nginx À L'INTÉRIEUR DU CONTENEUR
|
|
# -----------------------------------------------------------------------------
|
|
# DIFFÉRENCE MAJEURE avec nginx.conf.example (à la racine du projet) :
|
|
#
|
|
# Ce fichier ne gère NI TLS, NI redirection HTTP vers HTTPS, NI redirection
|
|
# du domaine nu vers www. Traefik, le reverse proxy de Coolify, s'en charge
|
|
# en amont.
|
|
#
|
|
# Dupliquer ces redirections ici provoquerait une boucle infinie : Traefik
|
|
# transmet la requête en HTTP clair au conteneur, qui la redirigerait vers
|
|
# HTTPS, ce qui repasserait par Traefik, et ainsi de suite.
|
|
#
|
|
# Le conteneur écoute donc en HTTP simple sur le port 80, en interne.
|
|
# nginx.conf.example reste utile si le site est un jour servi sans Coolify.
|
|
# =============================================================================
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name _;
|
|
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
charset utf-8;
|
|
|
|
# -------------------------------------------------------------------------
|
|
# JOURNALISATION
|
|
# Sortie standard : Coolify récupère les journaux du conteneur.
|
|
# Écrire dans un fichier ferait grossir la couche du conteneur sans profit.
|
|
# -------------------------------------------------------------------------
|
|
access_log /dev/stdout;
|
|
error_log /dev/stderr warn;
|
|
|
|
# Masque le numéro de version dans les en-têtes et les pages d'erreur
|
|
server_tokens off;
|
|
|
|
# =========================================================================
|
|
# EN-TÊTES DE SÉCURITÉ
|
|
# -------------------------------------------------------------------------
|
|
# HSTS est volontairement ABSENT ici : c'est Traefik qui termine le TLS,
|
|
# c'est donc à lui de l'émettre (voir DEPLOIEMENT-COOLIFY.md). L'émettre
|
|
# depuis le conteneur fonctionnerait, mais placerait un réglage
|
|
# irréversible dans une couche qu'on redéploie souvent.
|
|
# =========================================================================
|
|
|
|
add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; script-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; upgrade-insecure-requests" always;
|
|
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), interest-cohort=()" always;
|
|
add_header X-Frame-Options "DENY" always;
|
|
|
|
# =========================================================================
|
|
# COMPRESSION
|
|
# =========================================================================
|
|
gzip on;
|
|
gzip_vary on; # « Vary: Accept-Encoding » — sans lui, un proxy
|
|
# peut servir du gzip à un client incapable de
|
|
# le lire.
|
|
gzip_comp_level 6;
|
|
gzip_min_length 256;
|
|
gzip_proxied any; # Compresse aussi les réponses passant par
|
|
# Traefik (sinon Nginx s'en abstient dès qu'il
|
|
# détecte un proxy en amont).
|
|
gzip_types
|
|
text/plain
|
|
text/css
|
|
text/xml
|
|
text/javascript
|
|
application/javascript
|
|
application/json
|
|
application/manifest+json
|
|
application/xml
|
|
image/svg+xml;
|
|
|
|
# =========================================================================
|
|
# CACHE
|
|
# HTML revalidé à chaque visite, assets mis en cache longuement.
|
|
# Sans cette distinction, un visiteur garderait l'ancienne page après
|
|
# chaque redéploiement.
|
|
# =========================================================================
|
|
|
|
location ~* \.(css|js)$ {
|
|
expires 7d;
|
|
add_header Cache-Control "public, max-age=604800";
|
|
access_log off;
|
|
}
|
|
|
|
location ~* \.(png|jpe?g|gif|svg|webp|avif|ico|woff2?)$ {
|
|
expires 90d;
|
|
add_header Cache-Control "public, max-age=7776000";
|
|
access_log off;
|
|
}
|
|
|
|
location = /index.html {
|
|
add_header Cache-Control "public, max-age=0, must-revalidate";
|
|
}
|
|
|
|
location ~* \.(txt|xml|webmanifest)$ {
|
|
expires 1d;
|
|
add_header Cache-Control "public, max-age=86400";
|
|
}
|
|
|
|
# =========================================================================
|
|
# TYPES MIME PARTICULIERS
|
|
# =========================================================================
|
|
location = /site.webmanifest {
|
|
default_type application/manifest+json;
|
|
add_header Cache-Control "public, max-age=86400";
|
|
}
|
|
|
|
location = /llms.txt {
|
|
default_type text/plain;
|
|
charset utf-8;
|
|
}
|
|
|
|
location = /.well-known/security.txt {
|
|
default_type text/plain;
|
|
charset utf-8;
|
|
}
|
|
|
|
# =========================================================================
|
|
# SONDE DE SANTÉ
|
|
# Coolify et Docker interrogent ce point pour savoir si le conteneur est
|
|
# prêt. Réponse minimale, sans journalisation, pour ne pas polluer les logs.
|
|
# =========================================================================
|
|
location = /healthz {
|
|
access_log off;
|
|
add_header Content-Type text/plain;
|
|
return 200 "ok\n";
|
|
}
|
|
|
|
# =========================================================================
|
|
# ROUTAGE
|
|
# =========================================================================
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
# Bloque les fichiers cachés, sauf .well-known (RFC 8615)
|
|
location ~ /\.(?!well-known) {
|
|
deny all;
|
|
return 404;
|
|
}
|
|
|
|
error_page 404 /index.html;
|
|
}
|