Files
team-tryouts/app/nginx.conf
T
GGThed d0a9e75fe6 perf: servir les statiques par nginx, et dire ce que le bot n a pas livre
PERF-006. Le bloc location /static/ etait commente : 59 Ko de CSS et de JS
passaient par Waitress a chaque page. L activer tel quel aurait ete une
regression : ces URL ne changent jamais, donc un cache de 30 jours sert une
feuille de style vieille d un mois apres chaque deploiement, sans moyen de
l invalider. url_for('static') estampille maintenant chaque URL du mtime du
fichier ; c est ce qui rend le immutable vrai et pas seulement rapide.

Deux pieges nginx consignes dans le fichier : un add_header dans un location
annule tous les add_header herites du server (nosniff disparaissait du
JavaScript), et un statique manquant doit renvoyer 404 plutot que retomber
sur Flask, sinon un deploiement casse se cache derriere une page qui marche.

PERF-005. Les objets utilisateur Discord sont mis en cache. A etre precis
sur le gain : un envoi coute deux appels reseau, resoudre puis envoyer, et
seul le premier est economise — un premier match a vingt joueurs fait
toujours vingt resolutions. Ce qui est gagne l est entre notifications, la
ou le bot ecrit aux memes personnes soir apres soir.

Chaque message dit desormais ce qu il est devenu, avec le destinataire et
la raison. Les trois echecs ne se ressemblent pas et ne se lisent plus
pareil : une boite fermee est definitive et ne se retente pas, une erreur
HTTP est passagere, un identifiant sans proprietaire est un compte a
corriger. Le lot quotidien annonce son propre deficit.

Piege trouve en ecrivant les tests : configure_logging met propagate=False
sur le logger 'app', et le handler de caplog est sur la racine. Les
assertions sur les journaux passaient seules et echouaient dans la suite
complete, ou une application avait deja ete construite — elles lisaient un
journal vide, pas un bot silencieux.

417 tests.
2026-08-11 11:56:48 -04:00

194 lines
7.8 KiB
Nginx Configuration File

# Team Tryouts - Production Nginx Configuration (Windows)
#
# This configuration provides:
# - HTTP to HTTPS redirect
# - TLS 1.2/1.3 with strong ciphers
# - HSTS enforcement
# - Request size limits
# - gzip compression
# - Proxy to Waitress (Flask)
# - Security headers (reinforced at reverse proxy level)
worker_processes auto;
events {
worker_connections 1024;
multi_accept on;
}
http {
# =========================================================================
# Basic Settings
# =========================================================================
server_tokens off; # Hide Nginx version
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 16M; # Max upload size (matches Flask MAX_CONTENT_LENGTH)
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
include mime.types;
default_type application/octet-stream;
# =========================================================================
# Logging
# =========================================================================
access_log logs/access.log;
error_log logs/error.log warn;
# =========================================================================
# Gzip Compression
# =========================================================================
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
image/svg+xml
font/ttf
font/otf;
# =========================================================================
# HTTP → HTTPS Redirect
# =========================================================================
server {
listen 80;
server_name _;
# Redirect all HTTP traffic to HTTPS
return 301 https://$host$request_uri;
}
# =========================================================================
# HTTPS Server
# =========================================================================
server {
listen 443 ssl http2;
server_name _;
# ---------------------------------------------------------------------
# SSL/TLS Configuration
# ---------------------------------------------------------------------
# Paths to SSL certificate and key (update these for your deployment)
ssl_certificate C:/nginx/certs/fullchain.pem;
ssl_certificate_key C:/nginx/certs/privkey.pem;
# Strong TLS configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# SSL session settings
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling (uncomment when running on a proper domain)
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate C:/nginx/certs/chain.pem;
# Diffie-Hellman parameters (generate with: openssl dhparam -out dhparam.pem 2048)
# ssl_dhparam C:/nginx/certs/dhparam.pem;
# ---------------------------------------------------------------------
# Security Headers (defense-in-depth with Flask's own headers)
# ---------------------------------------------------------------------
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
# X-XSS-Protection intentionally omitted: deprecated, removed from
# current browsers, and harmful in its last implementations.
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
# ---------------------------------------------------------------------
# Proxy to Waitress (Flask)
# ---------------------------------------------------------------------
location / {
proxy_pass http://127.0.0.1:5000;
# Proxy headers
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;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# Timeouts
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# Buffer settings
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
}
# ---------------------------------------------------------------------
# Static Files (PERF-006)
#
# 59 KB of CSS and JS on every page load, previously proxied through
# Waitress. Nginx serves them from disk instead.
#
# ADJUST THIS ONE PATH to the deployment's checkout, absolute, forward
# slashes even on Windows. Nginx resolves a relative path against its
# own install prefix, not against this file. The trailing slash on both
# the location and the alias is required: without it /static/css/x.css
# resolves one directory too high.
#
# `immutable` is safe here and only here: url_for('static', …) appends
# ?v=<mtime> (see version_static_urls in app/app.py), so a deployed file
# is requested under a new URL and the cached copy of the old one is
# never asked for again. Removing that stamp and leaving this block
# gives every visitor a month-old stylesheet.
# ---------------------------------------------------------------------
location /static/ {
alias C:/team-tryouts/app/static/;
expires 30d;
access_log off;
# These three are repeated on purpose. In nginx, add_header is
# inherited from the enclosing block ONLY when the current block
# declares none of its own — one add_header here silently drops
# every security header set at server level. Dropping nosniff on
# the JavaScript is the one that matters.
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# A missing static file must 404, not fall through to Flask: the
# fallthrough would hide a broken deploy behind a working page.
try_files $uri =404;
}
# ---------------------------------------------------------------------
# Rate Limiting
# ---------------------------------------------------------------------
# Define rate limit zones (uncomment when rate limiting at Nginx level)
# limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
# limit_req_zone $binary_remote_addr zone=global:10m rate=100r/m;
# location /auth/login {
# limit_req zone=login burst=5 nodelay;
# proxy_pass http://127.0.0.1:5000;
# }
}
}