Site personnel courcellematthi.eu

This commit is contained in:
lrdlg
2026-08-05 22:40:03 +02:00
commit df12d21165
39 changed files with 4503 additions and 0 deletions
+212
View File
@@ -0,0 +1,212 @@
# =============================================================================
# nginx.conf.example — Configuration serveur pour courcellematthi.eu
# -----------------------------------------------------------------------------
# À adapter puis inclure dans la configuration Nginx.
# Couvre : redirections canoniques, en-têtes de sécurité, cache, compression.
#
# Sans ces réglages, un site statique parfaitement écrit reste noté médiocre
# par les outils d'audit (Lighthouse, Mozilla Observatory, securityheaders.com)
# et sert des fichiers non compressés.
# =============================================================================
# -----------------------------------------------------------------------------
# REDIRECTION HTTP -> HTTPS
# Le certificat est supposé géré par Certbot ou acme.sh.
# -----------------------------------------------------------------------------
server {
listen 80;
listen [::]:80;
server_name courcellematthi.eu www.courcellematthi.eu;
# Laisse passer la validation ACME avant de rediriger
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://www.courcellematthi.eu$request_uri;
}
}
# -----------------------------------------------------------------------------
# REDIRECTION DU DOMAINE NU VERS WWW
# Une seule URL canonique évite la dilution du référencement et le contenu
# dupliqué. Le choix www / sans-www est indifférent, la constance ne l'est pas.
# La valeur retenue ici doit correspondre à <link rel="canonical"> dans le HTML.
# -----------------------------------------------------------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name courcellematthi.eu;
ssl_certificate /etc/letsencrypt/live/courcellematthi.eu/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/courcellematthi.eu/privkey.pem;
return 301 https://www.courcellematthi.eu$request_uri;
}
# -----------------------------------------------------------------------------
# SERVEUR PRINCIPAL
# -----------------------------------------------------------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name www.courcellematthi.eu;
root /var/www/courcellematthi.eu;
index index.html;
charset utf-8;
# -------------------------------------------------------------------------
# TLS
# TLS 1.2 minimum : les versions antérieures sont obsolètes et vulnérables.
# -------------------------------------------------------------------------
ssl_certificate /etc/letsencrypt/live/courcellematthi.eu/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/courcellematthi.eu/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off; # Laisse le client choisir : recommandé
# depuis TLS 1.3
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# Agrafage OCSP : le serveur fournit lui-même la preuve de non-révocation
# du certificat, ce qui évite au navigateur une requête vers l'autorité.
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
# =========================================================================
# EN-TÊTES DE SÉCURITÉ
# =========================================================================
# HSTS — force HTTPS pendant deux ans, y compris sur les sous-domaines.
# ATTENTION : ne l'activer qu'une fois le HTTPS confirmé fonctionnel
# partout. Un HSTS émis par erreur rend le site inaccessible jusqu'à
# expiration, sans possibilité d'annulation côté serveur.
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# CSP — liste blanche des sources autorisées. Défense principale contre
# l'injection de scripts.
# default-src 'self' : tout provient du domaine par défaut
# style-src ... 'unsafe-inline' : requis par le CSS injecté de Google Fonts
# font-src fonts.gstatic.com : fichiers de police
# script-src 'self' 'unsafe-inline' : 'unsafe-inline' n'est nécessaire
# que pour l'attribut onclick du bouton d'impression. Le retirer si
# ce bouton est déplacé dans un module.
# frame-ancestors 'none' : interdit l'inclusion en iframe (clickjacking)
# base-uri 'self' : empêche la réécriture des URL relatives
# form-action 'self' : limite les cibles de soumission
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;
# Empêche le navigateur de deviner le type MIME d'un fichier, technique
# utilisée pour faire exécuter une image comme du script.
add_header X-Content-Type-Options "nosniff" always;
# Ne transmet le référent complet qu'en navigation interne ; vers
# l'extérieur, seul le domaine est envoyé. Compromis usuel entre mesure
# d'audience et confidentialité.
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Désactive des API sensibles jamais utilisées par ce site.
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), interest-cohort=()" always;
# Redondant avec frame-ancestors, conservé pour les navigateurs anciens.
add_header X-Frame-Options "DENY" always;
# =========================================================================
# COMPRESSION
# Gzip partout ; Brotli en plus si le module est disponible (taux
# supérieur de 15 à 20 % sur du texte).
# =========================================================================
gzip on;
gzip_vary on; # Ajoute « Vary: Accept-Encoding » : sans lui,
# un proxy peut servir la version compressée
# à un client qui ne la supporte pas.
gzip_comp_level 6; # Au-delà, le gain marginal ne compense plus
# le coût CPU.
gzip_min_length 256; # En dessous, l'en-tête coûte plus que le gain.
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/manifest+json
application/xml
image/svg+xml;
# Décommenter si le module ngx_brotli est compilé
# brotli on;
# brotli_comp_level 6;
# brotli_types text/plain text/css application/javascript application/json image/svg+xml;
# =========================================================================
# CACHE
# Stratégie en deux niveaux :
# - Les ressources d'assets changent rarement : cache long.
# - Le HTML change à chaque mise à jour de contenu : jamais mis en cache
# durablement, sinon les visiteurs voient une version périmée.
#
# NOTE : « immutable » suppose des noms de fichiers versionnés
# (style.a1b2c3.css). Sans versionnement, garder une durée modérée
# pour pouvoir publier un correctif.
# =========================================================================
location ~* \.(css|js|woff2?|ttf|otf|eot)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
access_log off;
}
location ~* \.(png|jpe?g|gif|svg|webp|avif|ico)$ {
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 {
types { } default_type application/manifest+json;
}
location = /llms.txt {
types { } default_type text/plain;
charset utf-8;
}
location = /.well-known/security.txt {
types { } default_type text/plain;
charset utf-8;
}
# =========================================================================
# ROUTAGE
# =========================================================================
location / {
try_files $uri $uri/ /index.html;
}
# Refuse l'accès aux fichiers cachés, sauf .well-known (RFC 8615)
location ~ /\.(?!well-known) {
deny all;
return 404;
}
# Page d'erreur : renvoyer vers l'accueil plutôt qu'une page vide
error_page 404 /index.html;
}