# Fichier: python_cheats/cheatsheets/nginx_for_python.txt
# Nginx pour Applications Python - Guide Complet Débutant


[OK] COMPRENDRE L'ARCHITECTURE (POUR DÉBUTANTS)

# === POURQUOI CETTE ARCHITECTURE ? ===

# Quand vous développez en Flask/Django sur Windows:
# - Vous lancez: python app.py
# - Flask démarre un serveur de développement
# - Vous visitez: http://localhost:5000
# - [OK] Fonctionne bien en développement
# - [X] NE CONVIENT PAS pour production !

# Problèmes du serveur de développement:
# [X] Lent (une seule requête à la fois)
# [X] Pas sécurisé
# [X] Crash facilement
# [X] Pas de HTTPS
# [X] Pas de gestion des fichiers statiques
# [X] Message: "WARNING: This is a development server. Do not use it in production"

# Solution production (Linux):
#
# [Internet] 
#     v (port 80/443)
# [NGINX] <- Vous êtes ICI (serveur Linux)
#     v (port 8000)
# [GUNICORN] <- Serveur WSGI Python
#     v
# [FLASK/DJANGO APP] <- Votre code Python

# Rôles:
# 
# NGINX (devant):
# - Reçoit toutes les requêtes d'Internet
# - Gère HTTPS/SSL (certificats)
# - Sert fichiers statiques (CSS, JS, images) TRÈS RAPIDEMENT
# - Cache les réponses
# - Protection DDoS, rate limiting
# - Load balancing si plusieurs serveurs
#
# GUNICORN (milieu):
# - Serveur WSGI (interface Python <-> Web)
# - Lance plusieurs "workers" Python
# - Gère crashes (redémarre automatiquement)
# - Meilleure performance que serveur dev
#
# FLASK/DJANGO (derrière):
# - Votre code applicatif
# - Logique métier
# - Base de données
# - Ne s'occupe QUE de la logique


[OK] PRÉREQUIS - CE DONT VOUS AVEZ BESOIN

# === SUR VOTRE WINDOWS (Développement) ===

# 1. Python installé
python --version
# Devrait afficher: Python 3.8+ (minimum)

# 2. Git installé (pour versionner code)
git --version

# 3. Un éditeur de code (VS Code recommandé)
# Télécharger: https://code.visualstudio.com/

# 4. Votre application Flask qui fonctionne
# On va créer un exemple complet ci-dessous


# === SUR LE SERVEUR LINUX (Production) ===

# Vous aurez besoin d'un serveur Linux (Ubuntu recommandé)
# Options:
# 1. VPS: DigitalOcean, Linode, Vultr (~5$/mois)
# 2. AWS EC2 (gratuit 1 an avec Free Tier)
# 3. Google Cloud Platform
# 4. Azure

# Ce guide suppose Ubuntu 22.04 LTS


[OK] ÉTAPE 1 - CRÉER APPLICATION FLASK SUR WINDOWS

# === CRÉER STRUCTURE PROJET ===

# Ouvrir PowerShell ou CMD sur Windows
# Créer dossier projet:
mkdir C:\Users\VotreNom\flask_app
cd C:\Users\VotreNom\flask_app

# Créer environnement virtuel:
python -m venv venv

# Activer l'environnement (PowerShell):
venv\Scripts\Activate.ps1

# Si erreur "execution policy", exécuter en admin:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Activer l'environnement (CMD):
venv\Scripts\activate.bat

# Vous verrez (venv) devant votre prompt


# === INSTALLER FLASK ===

pip install flask gunicorn

# Créer requirements.txt:
pip freeze > requirements.txt

# Contenu typique de requirements.txt:
# Flask==3.0.0
# gunicorn==21.2.0
# Werkzeug==3.0.1
# etc.


# === CRÉER APPLICATION FLASK SIMPLE ===

# Créer fichier: app.py
# (Avec VS Code: code app.py)

"""
app.py - Application Flask simple mais complète
"""
from flask import Flask, render_template, jsonify
import os

# Créer instance Flask
app = Flask(__name__)

# Configuration
app.config['SECRET_KEY'] = 'votre-clé-secrète-ici'  # Changer en production!

# Route page d'accueil
@app.route('/')
def home():
    """Page d'accueil"""
    return render_template('index.html')

# Route API
@app.route('/api/hello')
def api_hello():
    """Endpoint API simple"""
    return jsonify({
        'message': 'Hello from Flask!',
        'status': 'success'
    })

# Route avec paramètre
@app.route('/api/greet/<name>')
def api_greet(name):
    """Saluer quelqu'un par son nom"""
    return jsonify({
        'message': f'Bonjour {name}!',
        'status': 'success'
    })

# Route health check (pour monitoring)
@app.route('/health')
def health():
    """Vérifier que l'app fonctionne"""
    return jsonify({'status': 'healthy'}), 200

# Route info
@app.route('/info')
def info():
    """Infos sur l'application"""
    return jsonify({
        'app': 'Flask Demo',
        'version': '1.0.0',
        'python_version': os.sys.version
    })

# Gestion erreur 404
@app.errorhandler(404)
def not_found(error):
    """Page 404 personnalisée"""
    return jsonify({'error': 'Page non trouvée'}), 404

# Point d'entrée développement
if __name__ == '__main__':
    # NE PAS utiliser en production!
    app.run(debug=True, host='127.0.0.1', port=5000)


# === CRÉER TEMPLATES HTML ===

# Créer dossier templates:
mkdir templates

# Créer fichier: templates\index.html

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask App Demo</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <h1>[RAPIDE] Application Flask</h1>
        <p>Votre application fonctionne correctement!</p>
        
        <div class="buttons">
            <button onclick="testAPI()">Tester API</button>
        </div>
        
        <div id="result"></div>
    </div>
    
    <script>
        async function testAPI() {
            const response = await fetch('/api/hello');
            const data = await response.json();
            document.getElementById('result').innerHTML = 
                `<p>Réponse API: ${data.message}</p>`;
        }
    </script>
</body>
</html>


# === CRÉER FICHIERS STATIQUES ===

# Créer dossier static:
mkdir static

# Créer fichier: static\style.css

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.container {
    background: white;
    padding: 40px;
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
    text-align: center;
    max-width: 600px;
}

h1 {
    color: #333;
    margin-bottom: 20px;
}

button {
    background: #667eea;
    color: white;
    border: none;
    padding: 15px 30px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    margin: 10px;
}

button:hover {
    background: #5568d3;
}

#result {
    margin-top: 20px;
    padding: 15px;
    background: #f0f0f0;
    border-radius: 5px;
}


# === TESTER EN DÉVELOPPEMENT ===

# Lancer l'application:
python app.py

# Vous verrez:
# * Running on http://127.0.0.1:5000
# * WARNING: This is a development server...

# Ouvrir navigateur: http://localhost:5000
# Vous devriez voir votre page!

# Tester API:
# http://localhost:5000/api/hello
# http://localhost:5000/health

# Pour arrêter: Ctrl+C


# === STRUCTURE FINALE DU PROJET ===

flask_app/
├── venv/                    # Environnement virtuel (NE PAS commiter)
├── static/
│   └── style.css           # CSS
├── templates/
│   └── index.html          # HTML
├── app.py                  # Application Flask
├── requirements.txt        # Dépendances
└── .gitignore             # À créer ci-dessous


# === CRÉER .gitignore ===

# Fichier: .gitignore

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
ENV/

# Flask
instance/
.webassets-cache

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Config sensibles
.env
config.py


# === INITIALISER GIT ===

git init
git add .
git commit -m "Initial commit - Flask app"

# Créer repository sur GitHub et pusher:
git remote add origin https://github.com/votre-username/flask_app.git
git branch -M main
git push -u origin main


[OK] ÉTAPE 2 - PRÉPARER SERVEUR LINUX (Ubuntu)

# === SE CONNECTER AU SERVEUR ===

# Depuis Windows, utiliser:
# 1. PuTTY (télécharger sur putty.org)
# 2. PowerShell (Windows 10+)
# 3. Git Bash

# Exemple avec PowerShell:
ssh root@votre-ip-serveur
# Ou:
ssh ubuntu@votre-ip-serveur

# Entrer mot de passe quand demandé


# === METTRE À JOUR LE SYSTÈME ===

# Une fois connecté au serveur:
sudo apt update
sudo apt upgrade -y

# Cette commande:
# - apt update: Met à jour liste des paquets
# - apt upgrade: Installe les mises à jour
# - -y: Accepte automatiquement


# === INSTALLER PYTHON ET OUTILS ===

# Installer Python 3 et pip:
sudo apt install python3 python3-pip python3-venv -y

# Vérifier installation:
python3 --version
# Devrait afficher: Python 3.10+ ou 3.11+

pip3 --version


# === INSTALLER NGINX ===

sudo apt install nginx -y

# Vérifier installation:
nginx -v
# Devrait afficher: nginx version: nginx/1.22+

# Démarrer Nginx:
sudo systemctl start nginx

# Activer démarrage automatique:
sudo systemctl enable nginx

# Vérifier statut:
sudo systemctl status nginx
# Devrait afficher: active (running)

# Tester dans navigateur:
# http://votre-ip-serveur
# Vous devriez voir "Welcome to nginx!"


# === COMPRENDRE STRUCTURE NGINX ===

# Nginx sur Ubuntu est organisé ainsi:

# /etc/nginx/                    <- Dossier PRINCIPAL configuration
#   ├── nginx.conf               <- Fichier principal (ne PAS toucher débutant)
#   ├── sites-available/         <- VOS configurations de sites ICI
#   │   └── default              <- Site par défaut (exemple)
#   ├── sites-enabled/           <- Sites actifs (liens symboliques)
#   │   └── default -> ../sites-available/default
#   └── snippets/                <- Morceaux réutilisables

# /var/www/                      <- Vos FICHIERS WEB ici
#   └── html/                    <- Site par défaut
#       └── index.nginx-debian.html

# /var/log/nginx/                <- LOGS
#   ├── access.log               <- Toutes les requêtes
#   └── error.log                <- Erreurs

# Comment ça marche:
# 1. Vous créez fichier dans sites-available/
# 2. Vous créez lien symbolique dans sites-enabled/
# 3. Nginx lit SEULEMENT sites-enabled/
# 4. Vous pouvez désactiver site en supprimant lien


# === CRÉER UTILISATEUR POUR L'APPLICATION ===

# Pour sécurité, ne PAS utiliser root

# Créer utilisateur:
sudo adduser flaskuser

# Quand demandé:
# - Enter password: [votre-mot-de-passe]
# - Retype password: [même-mot-de-passe]
# - Full Name: Flask User (appuyer Enter pour passer autres questions)

# Ajouter aux sudoers (optionnel):
sudo usermod -aG sudo flaskuser

# Se connecter en tant que cet utilisateur:
su - flaskuser
# Ou se reconnecter en SSH:
# ssh flaskuser@votre-ip-serveur


[OK] ÉTAPE 3 - TRANSFÉRER CODE SUR SERVEUR

# === MÉTHODE 1: GIT (Recommandé) ===

# Sur le SERVEUR Linux:

# Installer Git:
sudo apt install git -y

# Créer dossier pour application:
sudo mkdir -p /var/www/flask_app
sudo chown -R $USER:$USER /var/www/flask_app

# Cloner votre repository GitHub:
cd /var/www/flask_app
git clone https://github.com/votre-username/flask_app.git .
# Le point "." à la fin = cloner dans dossier actuel

# Vérifier fichiers:
ls -la
# Vous devriez voir: app.py, requirements.txt, static/, templates/


# === MÉTHODE 2: SCP (Si pas Git) ===

# Depuis Windows PowerShell (PAS sur serveur!):

# Transférer dossier complet:
scp -r C:\Users\VotreNom\flask_app flaskuser@votre-ip:/var/www/
# -r = récursif (tout le dossier)

# Ou avec WinSCP (interface graphique):
# 1. Télécharger WinSCP: https://winscp.net/
# 2. Se connecter au serveur
# 3. Glisser-déposer fichiers


# === MÉTHODE 3: SFTP ===

# Avec FileZilla:
# 1. Télécharger FileZilla: https://filezilla-project.org/
# 2. Nouvelle connexion SFTP:
#    - Hôte: sftp://votre-ip
#    - Utilisateur: flaskuser
#    - Mot de passe: votre-mot-de-passe
#    - Port: 22
# 3. Glisser-déposer fichiers


[OK] ÉTAPE 4 - CONFIGURER ENVIRONNEMENT PYTHON SUR SERVEUR

# === CRÉER ENVIRONNEMENT VIRTUEL ===

# Sur le SERVEUR, dans /var/www/flask_app:
cd /var/www/flask_app

# Créer venv:
python3 -m venv venv

# Activer venv:
source venv/bin/activate
# Vous verrez (venv) devant le prompt

# Mettre à jour pip:
pip install --upgrade pip


# === INSTALLER DÉPENDANCES ===

# Installer depuis requirements.txt:
pip install -r requirements.txt

# Vérifier installations:
pip list
# Vous devriez voir Flask, gunicorn, etc.


# === TESTER APPLICATION PYTHON ===

# Tester avec serveur dev Flask (temporaire):
python app.py

# Dans AUTRE terminal SSH ou sur Windows:
curl http://votre-ip:5000
# Ou navigateur: http://votre-ip:5000

# Si ça fonctionne, vous verrez votre page!
# Arrêter avec Ctrl+C


# === CONFIGURER GUNICORN ===

# Créer fichier de configuration Gunicorn:
nano gunicorn_config.py

# Copier ce contenu:

"""
gunicorn_config.py - Configuration Gunicorn
"""
import multiprocessing

# Adresse:port à écouter
# 127.0.0.1 = seulement localhost (Nginx y accédera)
bind = "127.0.0.1:8000"

# Nombre de workers (processus)
# Formule: (2 × nb_CPU) + 1
# Pour 1 CPU: 3 workers
# Pour 2 CPU: 5 workers
workers = multiprocessing.cpu_count() * 2 + 1

# Type de worker
worker_class = "sync"  # Sync pour Flask simple
# Pour apps async: "gevent" ou "eventlet"

# Timeouts
timeout = 30          # Timeout requête (secondes)
keepalive = 2         # Keep-alive connexions

# Logs
accesslog = "/var/www/flask_app/logs/gunicorn_access.log"
errorlog = "/var/www/flask_app/logs/gunicorn_error.log"
loglevel = "info"     # debug, info, warning, error, critical

# Process
proc_name = "flask_app"  # Nom du processus

# Daemon
daemon = False  # systemd gère ça

# Sauvegarder: Ctrl+O, Enter, Ctrl+X


# === CRÉER DOSSIER LOGS ===

mkdir -p /var/www/flask_app/logs


# === TESTER GUNICORN ===

# Lancer Gunicorn manuellement (test):
gunicorn -c gunicorn_config.py app:app

# Vous verrez:
# [INFO] Starting gunicorn ...
# [INFO] Listening at: http://127.0.0.1:8000
# [INFO] Using worker: sync
# [INFO] Booting worker with pid: ...

# Tester:
curl http://127.0.0.1:8000
# Devrait afficher HTML de votre page

# Si ça marche, arrêter: Ctrl+C


[OK] ÉTAPE 5 - CONFIGURER NGINX

# === DÉSACTIVER SITE PAR DÉFAUT ===

# Supprimer lien symbolique du site par défaut:
sudo rm /etc/nginx/sites-enabled/default

# Le fichier dans sites-available/ reste (pas grave)


# === CRÉER CONFIGURATION POUR VOTRE APP ===

# Créer nouveau fichier de configuration:
sudo nano /etc/nginx/sites-available/flask_app

# COPIER CETTE CONFIGURATION COMPLÈTE:

# /etc/nginx/sites-available/flask_app
# Configuration Nginx pour Flask App

# Définir backend (Gunicorn)
upstream flask_backend {
    # Gunicorn écoute sur 127.0.0.1:8000
    server 127.0.0.1:8000 fail_timeout=0;
}

# Serveur HTTP (port 80)
server {
    # Écouter sur port 80 (HTTP)
    listen 80;
    listen [::]:80;  # IPv6
    
    # Nom de domaine (remplacer par votre domaine ou IP)
    server_name votre-domaine.com www.votre-domaine.com;
    # Si pas de domaine, utiliser:
    # server_name votre-ip-serveur;
    # Exemple: server_name 203.0.113.45;
    
    # Logs spécifiques à cette app
    access_log /var/www/flask_app/logs/nginx_access.log;
    error_log /var/www/flask_app/logs/nginx_error.log;
    
    # Taille max upload (pour formulaires avec fichiers)
    client_max_body_size 20M;
    
    # === FICHIERS STATIQUES ===
    # Nginx sert directement CSS, JS, images
    # (Plus rapide que Python!)
    location /static/ {
        # Alias vers dossier static
        alias /var/www/flask_app/static/;
        
        # Cache navigateur: 1 mois
        expires 1M;
        add_header Cache-Control "public";
        
        # Pas de logs pour fichiers statiques (optimisation)
        access_log off;
    }
    
    # === FAVICON ===
    location = /favicon.ico {
        alias /var/www/flask_app/static/favicon.ico;
        access_log off;
        log_not_found off;
    }
    
    # === ROBOTS.TXT ===
    location = /robots.txt {
        alias /var/www/flask_app/static/robots.txt;
        access_log off;
        log_not_found off;
    }
    
    # === APPLICATION PYTHON (via Gunicorn) ===
    location / {
        # Passer requêtes à Gunicorn
        proxy_pass http://flask_backend;
        
        # Headers importants
        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;
        
        # Timeouts (ajuster selon votre app)
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # Buffering
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
        
        # Ne pas modifier redirections
        proxy_redirect off;
    }
}

# Sauvegarder: Ctrl+O, Enter, Ctrl+X


# === EXPLICATION LIGNE PAR LIGNE ===

# upstream flask_backend { ... }
# -> Définit où est Gunicorn (127.0.0.1:8000)

# server { ... }
# -> Bloc de configuration pour votre site

# listen 80;
# -> Écouter sur port 80 (HTTP standard)

# server_name votre-domaine.com;
# -> Nom de domaine (ou IP si pas de domaine)

# location /static/ { ... }
# -> Règle pour URLs commençant par /static/
# -> Nginx sert directement les fichiers

# location / { ... }
# -> Règle pour TOUTES les autres URLs
# -> Nginx passe la requête à Gunicorn

# proxy_pass http://flask_backend;
# -> Envoyer requête à Gunicorn

# proxy_set_header ...
# -> Passer infos importantes à Flask (IP visiteur, etc.)


# === ACTIVER LA CONFIGURATION ===

# Créer lien symbolique (activer le site):
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/

# Vérifier lien créé:
ls -l /etc/nginx/sites-enabled/
# Devrait montrer: flask_app -> ../sites-available/flask_app


# === TESTER CONFIGURATION NGINX ===

# TOUJOURS tester avant de recharger!
sudo nginx -t

# Si OK, vous verrez:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# Si ERREUR:
# - Nginx affiche ligne et problème
# - Corriger dans nano
# - Retester


# === RECHARGER NGINX ===

# Une fois test OK:
sudo systemctl reload nginx

# Vérifier statut:
sudo systemctl status nginx
# Devrait afficher: active (running)


[OK] ÉTAPE 6 - CRÉER SERVICE SYSTEMD (Auto-démarrage)

# === QU'EST-CE QUE SYSTEMD ? ===

# systemd = Gestionnaire de services Linux
# Permet de:
# - Démarrer Gunicorn automatiquement au boot serveur
# - Redémarrer automatiquement si crash
# - Gérer logs
# - Contrôler facilement (start/stop/restart)


# === CRÉER FICHIER SERVICE ===

sudo nano /etc/systemd/system/flask_app.service

# COPIER CETTE CONFIGURATION:

[Unit]
# Description du service
Description=Gunicorn instance pour Flask App
# Démarrer après le réseau
After=network.target

[Service]
# Utilisateur qui exécute le service
User=flaskuser
Group=www-data

# Dossier de travail
WorkingDirectory=/var/www/flask_app

# Environnement (chemin Python)
Environment="PATH=/var/www/flask_app/venv/bin"

# Variables d'environnement (optionnel)
# Environment="FLASK_ENV=production"
# Environment="SECRET_KEY=votre-clé-secrète"

# Commande à exécuter
ExecStart=/var/www/flask_app/venv/bin/gunicorn \
    --config /var/www/flask_app/gunicorn_config.py \
    app:app

# Redémarrage automatique
Restart=always
# Attendre 3 secondes avant redémarrage
RestartSec=3

# Logs (journalctl)
StandardOutput=journal
StandardError=journal

[Install]
# Démarrer au boot
WantedBy=multi-user.target

# Sauvegarder: Ctrl+O, Enter, Ctrl+X


# === EXPLICATION DU SERVICE ===

# [Unit]
# -> Métadonnées du service

# User=flaskuser
# -> Service s'exécute en tant que cet utilisateur (sécurité)

# WorkingDirectory=/var/www/flask_app
# -> Dossier où est l'application

# Environment="PATH=..."
# -> Utiliser Python du venv

# ExecStart=...
# -> Commande pour lancer Gunicorn

# Restart=always
# -> Si crash, redémarrer automatiquement

# WantedBy=multi-user.target
# -> Démarrer au boot serveur


# === ACTIVER ET DÉMARRER SERVICE ===

# Recharger systemd (lire nouveau service):
sudo systemctl daemon-reload

# Activer démarrage automatique au boot:
sudo systemctl enable flask_app

# Démarrer le service:
sudo systemctl start flask_app

# Vérifier statut:
sudo systemctl status flask_app

# Devrait afficher:
# [BLACK_CIRCLE] flask_app.service - Gunicorn instance pour Flask App
#    Loaded: loaded (/etc/systemd/system/flask_app.service; enabled)
#    Active: active (running) since ...
# 
# [INFO] Starting gunicorn ...
# [INFO] Listening at: http://127.0.0.1:8000
# [INFO] Booting worker with pid: ...

# Si "active (running)" en VERT -> Tout est OK! [OK]


# === COMMANDES UTILES SYSTEMD ===

# Démarrer:
sudo systemctl start flask_app

# Arrêter:
sudo systemctl stop flask_app

# Redémarrer:
sudo systemctl restart flask_app

# Recharger config (sans arrêter):
sudo systemctl reload flask_app

# Voir statut:
sudo systemctl status flask_app

# Voir logs en temps réel:
sudo journalctl -u flask_app -f
# Arrêter avec Ctrl+C

# Voir dernières 100 lignes logs:
sudo journalctl -u flask_app -n 100


[OK] ÉTAPE 7 - TESTER L'APPLICATION

# === VÉRIFIER QUE TOUT FONCTIONNE ===

# 1. Vérifier Gunicorn tourne:
ps aux | grep gunicorn
# Devrait montrer plusieurs processus gunicorn

# 2. Vérifier port 8000:
sudo netstat -tulpn | grep 8000
# Devrait montrer gunicorn écoute sur 127.0.0.1:8000

# 3. Vérifier Nginx tourne:
sudo systemctl status nginx

# 4. Vérifier port 80:
sudo netstat -tulpn | grep :80
# Devrait montrer nginx écoute sur 0.0.0.0:80


# === TESTER DANS NAVIGATEUR ===

# Ouvrir navigateur sur Windows:
# http://votre-ip-serveur
# Ou si vous avez configuré domaine:
# http://votre-domaine.com

# Vous devriez voir votre page Flask! [BRAVO]


# === TESTER API ===

# Depuis Windows PowerShell ou navigateur:
curl http://votre-ip-serveur/api/hello
# Devrait retourner: {"message":"Hello from Flask!","status":"success"}

curl http://votre-ip-serveur/health
# Devrait retourner: {"status":"healthy"}


# === TESTER FICHIERS STATIQUES ===

# CSS devrait se charger depuis Nginx:
curl -I http://votre-ip-serveur/static/style.css

# Devrait montrer headers Nginx:
# HTTP/1.1 200 OK
# Server: nginx/...
# Content-Type: text/css


# === VOIR LOGS EN TEMPS RÉEL ===

# Ouvrir 3 terminaux SSH:

# Terminal 1 - Logs Gunicorn:
tail -f /var/www/flask_app/logs/gunicorn_access.log

# Terminal 2 - Logs Nginx Access:
sudo tail -f /var/log/nginx/access.log

# Terminal 3 - Logs Nginx Error:
sudo tail -f /var/log/nginx/error.log

# Visitez site dans navigateur
# Vous verrez requêtes apparaître en temps réel!


[OK] ÉTAPE 8 - AJOUTER HTTPS (Let's Encrypt)

# === INSTALLER CERTBOT ===

sudo apt install certbot python3-certbot-nginx -y


# === OBTENIR CERTIFICAT SSL ===

# IMPORTANT: Vous devez avoir un nom de domaine!
# Let's Encrypt ne fonctionne PAS avec IP seule

# Avant de continuer:
# 1. Acheter domaine (Namecheap, GoDaddy, OVH, etc.) ~10$/an
# 2. Pointer domaine vers IP serveur (DNS A record)
# 3. Attendre propagation DNS (5-60 minutes)

# Vérifier DNS propagé:
nslookup votre-domaine.com
# Devrait afficher votre IP serveur

# Obtenir certificat automatiquement:
sudo certbot --nginx -d votre-domaine.com -d www.votre-domaine.com

# Certbot va demander:
# 1. Email (pour alertes expiration): votre@email.com
# 2. Accepter Terms of Service: A
# 3. Partager email: N (optionnel)
# 4. Redirect HTTP -> HTTPS: 2 (Oui, recommandé!)

# Certbot va:
# [OK] Vérifier que domaine pointe vers serveur
# [OK] Obtenir certificat
# [OK] Modifier automatiquement config Nginx
# [OK] Configurer renouvellement automatique

# Si succès:
# Congratulations! You have successfully enabled HTTPS on ...


# === VÉRIFIER HTTPS ===

# Ouvrir navigateur:
# https://votre-domaine.com

# Vous devriez voir:
# [OK] Cadenas vert/gris (sécurisé)
# [OK] https:// dans URL
# [OK] Votre site fonctionne


# === CONFIGURATION FINALE NGINX (avec HTTPS) ===

# Certbot a modifié votre config
# Voir changements:
sudo nano /etc/nginx/sites-available/flask_app

# Certbot a ajouté bloc HTTPS et redirection HTTP:

# Bloc HTTP (redirection vers HTTPS)
server {
    listen 80;
    server_name votre-domaine.com www.votre-domaine.com;
    
    # Redirection automatique vers HTTPS
    return 301 https://$server_name$request_uri;
}

# Bloc HTTPS (ajouté par Certbot)
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name votre-domaine.com www.votre-domaine.com;
    
    # Certificats SSL
    ssl_certificate /etc/letsencrypt/live/votre-domaine.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/votre-domaine.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
    # ... reste de la config (static, proxy_pass, etc.)
}


# === RENOUVELLEMENT AUTOMATIQUE ===

# Certbot configure automatiquement renouvellement
# Certificat valide 90 jours, renouvellement à 30 jours

# Tester renouvellement (sans vraiment renouveler):
sudo certbot renew --dry-run

# Si OK:
# Congratulations, all simulated renewals succeeded!

# Certbot a créé timer systemd:
sudo systemctl list-timers | grep certbot
# Devrait montrer certbot.timer actif

# Renouvellement automatique configuré! [OK]


[OK] ÉTAPE 9 - MAINTENANCE ET MISE À JOUR

# === METTRE À JOUR L'APPLICATION ===

# Scénario: Vous avez modifié code sur Windows
# Vous devez mettre à jour sur serveur

# 1. Sur Windows, commiter changements:
git add .
git commit -m "Amélioration XYZ"
git push origin main

# 2. Sur serveur, récupérer changements:
cd /var/www/flask_app
git pull origin main

# 3. Réinstaller dépendances (si requirements.txt modifié):
source venv/bin/activate
pip install -r requirements.txt

# 4. Redémarrer Gunicorn:
sudo systemctl restart flask_app

# 5. Vérifier que ça fonctionne:
curl https://votre-domaine.com/health
sudo systemctl status flask_app


# === VOIR LOGS ===

# Logs application (Gunicorn):
tail -f /var/www/flask_app/logs/gunicorn_access.log
tail -f /var/www/flask_app/logs/gunicorn_error.log

# Logs Nginx:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

# Logs systemd (journalctl):
sudo journalctl -u flask_app -f
sudo journalctl -u nginx -f


# === REDÉMARRER SERVICES ===

# Redémarrer Gunicorn (après modif code):
sudo systemctl restart flask_app

# Recharger Nginx (après modif config):
sudo nginx -t                    # Tester d'abord!
sudo systemctl reload nginx      # Si test OK

# Redémarrer Nginx (rare):
sudo systemctl restart nginx


# === VÉRIFIER ESPACE DISQUE ===

df -h
# Devrait montrer espace disponible

# Si logs prennent trop de place:
# Nettoyer vieux logs:
sudo find /var/log/nginx/ -name "*.gz" -mtime +30 -delete
sudo journalctl --vacuum-time=7d


[OK] ÉTAPE 10 - DÉPANNAGE (SI PROBLÈMES)

# === PROBLÈME: 502 Bad Gateway ===

# Signifie: Nginx ne peut pas contacter Gunicorn

# Étape 1: Vérifier Gunicorn tourne
sudo systemctl status flask_app
# Si "inactive (dead)" -> Démarrer:
sudo systemctl start flask_app

# Étape 2: Vérifier port
ps aux | grep gunicorn
sudo netstat -tulpn | grep 8000
# Gunicorn doit écouter sur 127.0.0.1:8000

# Étape 3: Voir logs erreur
sudo journalctl -u flask_app -n 50
# Chercher erreurs Python

# Étape 4: Tester Gunicorn directement
curl http://127.0.0.1:8000
# Si erreur ici, problème dans code Python

# Erreurs courantes:
# - Import error: Module manquant
#   -> pip install module-manquant
# - Syntax error: Erreur dans code
#   -> Corriger code, git push, git pull
# - Permission denied: Mauvaises permissions
#   -> sudo chown -R flaskuser:www-data /var/www/flask_app


# === PROBLÈME: 404 Not Found ===

# Page n'existe pas

# Vérifier route existe dans Flask:
nano app.py
# Chercher @app.route('/votre-url')

# Vérifier logs Nginx:
sudo tail -f /var/log/nginx/access.log
# Regarder l'URL demandée

# Si fichier statique 404:
# Vérifier chemin dans location /static/:
ls -la /var/www/flask_app/static/


# === PROBLÈME: CSS/JS ne se chargent pas ===

# Fichiers statiques 404

# Vérifier dossier static existe:
ls -la /var/www/flask_app/static/

# Vérifier permissions:
sudo chown -R flaskuser:www-data /var/www/flask_app/static/
sudo chmod -R 755 /var/www/flask_app/static/

# Vérifier config Nginx:
sudo nano /etc/nginx/sites-available/flask_app
# location /static/ {
#     alias /var/www/flask_app/static/;
# }

# Tester directement:
curl http://votre-domaine.com/static/style.css


# === PROBLÈME: 500 Internal Server Error ===

# Erreur dans code Python

# Voir logs Gunicorn:
tail -f /var/www/flask_app/logs/gunicorn_error.log

# Voir logs journalctl:
sudo journalctl -u flask_app -n 100

# Erreur typique: Module manquant
# Solution: pip install dans venv


# === PROBLÈME: Site très lent ===

# Pas assez de workers Gunicorn

# Vérifier nombre CPUs:
nproc
# Si 2 -> devrait avoir ~5 workers

# Modifier gunicorn_config.py:
nano /var/www/flask_app/gunicorn_config.py
# workers = 5  # Augmenter

# Redémarrer:
sudo systemctl restart flask_app


# === PROBLÈME: Certificat SSL expiré ===

# Forcer renouvellement:
sudo certbot renew --force-renewal

# Recharger Nginx:
sudo systemctl reload nginx


# === PROBLÈME: "Permission denied" ===

# Permissions fichiers incorrectes

# Fixer propriétaire:
sudo chown -R flaskuser:www-data /var/www/flask_app/

# Fixer permissions:
sudo chmod -R 755 /var/www/flask_app/
sudo chmod -R 644 /var/www/flask_app/app.py


# === VÉRIFICATION COMPLÈTE SYSTÈME ===

# Script pour tout vérifier:
cat > ~/check_app.sh << 'EOF'
#!/bin/bash
echo "=== Vérification Flask App ==="
echo ""

echo "1. Service flask_app:"
sudo systemctl status flask_app --no-pager | head -5
echo ""

echo "2. Service nginx:"
sudo systemctl status nginx --no-pager | head -5
echo ""

echo "3. Processus Gunicorn:"
ps aux | grep gunicorn | grep -v grep | wc -l
echo " workers trouvés"
echo ""

echo "4. Port 8000 (Gunicorn):"
sudo netstat -tulpn | grep :8000
echo ""

echo "5. Port 80/443 (Nginx):"
sudo netstat -tulpn | grep nginx
echo ""

echo "6. Espace disque:"
df -h | grep -E 'Filesystem|/# Fichier: python_cheats/cheatsheets/nginx_for_python.txt
# Nginx pour Applications Python - Guide Complet


[OK] INTRODUCTION - NGINX ET PYTHON

# === POURQUOI NGINX AVEC PYTHON ? ===

# Python n'est PAS conçu pour servir directement du HTTP en production
# Problèmes sans Nginx:
# [X] Serveur dev (Flask, Django) lent et non sécurisé
# [X] Pas de gestion SSL/HTTPS
# [X] Pas de cache
# [X] Pas de fichiers statiques optimisés
# [X] Pas de load balancing
# [X] Vulnérable aux attaques

# Architecture CLASSIQUE en production:
# 
# Internet -> Nginx (port 80/443) -> Gunicorn/uWSGI -> Application Python
#              ^                        ^                    ^
#         Reverse proxy         WSGI Server          Flask/Django/FastAPI
#         SSL, Cache            Multi-workers         Logique métier
#         Fichiers statiques    Process manager

# Nginx gère:
# [OK] SSL/HTTPS
# [OK] Fichiers statiques (CSS, JS, images)
# [OK] Cache
# [OK] Compression (gzip)
# [OK] Load balancing
# [OK] Rate limiting
# [OK] Sécurité

# Serveur WSGI (Gunicorn/uWSGI) gère:
# [OK] Multiple workers Python
# [OK] Process management
# [OK] Auto-restart
# [OK] Interface WSGI

# Application Python gère:
# [OK] Logique métier
# [OK] Base de données
# [OK] API/Views


# === SERVEURS WSGI POUR PYTHON ===

# 1. GUNICORN (Recommandé - Simple et efficace)
#    - Green Unicorn
#    - Pure Python
#    - Facile à configurer
#    - Utilisé par Instagram, Spotify, etc.

# 2. uWSGI (Puissant mais complexe)
#    - Très performant
#    - Beaucoup d'options
#    - Plus difficile à configurer

# 3. Waitress (Windows-friendly)
#    - Pure Python
#    - Fonctionne bien sur Windows
#    - Moins performant que Gunicorn

# 4. Uvicorn (Pour FastAPI/AsyncIO)
#    - Serveur ASGI (pas WSGI)
#    - Pour applications asynchrones
#    - FastAPI, Starlette


[OK] FLASK + GUNICORN + NGINX

# === INSTALLATION ===

# 1. Installer Flask et Gunicorn
pip install flask gunicorn

# 2. Créer application Flask
# app.py
from flask import Flask, render_template, jsonify
import os

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html')

@app.route('/api/data')
def api_data():
    return jsonify({
        'status': 'success',
        'data': {'message': 'Hello from Flask!'}
    })

@app.route('/health')
def health():
    return jsonify({'status': 'healthy'}), 200

if __name__ == '__main__':
    # NE PAS utiliser en production !
    app.run(debug=True)


# === DÉMARRER AVEC GUNICORN ===

# Commande basique:
gunicorn app:app
# app:app = fichier:objet_app
# Écoute sur 127.0.0.1:8000 par défaut

# Avec options:
gunicorn app:app \
    --bind 0.0.0.0:8000 \
    --workers 4 \
    --worker-class sync \
    --timeout 30 \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log

# Explication options:
# --bind 0.0.0.0:8000       -> IP et port (0.0.0.0 = toutes interfaces)
# --workers 4               -> 4 processus workers (2-4 × nb CPU)
# --worker-class sync       -> Type worker (sync, gevent, eventlet)
# --timeout 30              -> Timeout requêtes (secondes)
# --access-logfile          -> Log des requêtes
# --error-logfile           -> Log des erreurs


# === CONFIGURATION GUNICORN (gunicorn_config.py) ===

# gunicorn_config.py
import multiprocessing

# Bind
bind = "127.0.0.1:8000"

# Workers
workers = multiprocessing.cpu_count() * 2 + 1  # Formule recommandée
worker_class = "sync"  # ou "gevent" pour async

# Timeouts
timeout = 30
keepalive = 2

# Logs
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
loglevel = "info"

# Process naming
proc_name = "flask_app"

# Server mechanics
daemon = False  # Ne pas daemonizer (systemd gère ça)
pidfile = "/var/run/gunicorn.pid"
umask = 0o007
user = None
group = None
tmp_upload_dir = None

# Démarrer avec config:
# gunicorn app:app -c gunicorn_config.py


# === CONFIGURATION NGINX POUR FLASK ===

# /etc/nginx/sites-available/flask_app

upstream flask_backend {
    # Gunicorn écoute sur localhost:8000
    server 127.0.0.1:8000 fail_timeout=0;
    
    # Si plusieurs workers Gunicorn sur ports différents:
    # server 127.0.0.1:8000;
    # server 127.0.0.1:8001;
    # server 127.0.0.1:8002;
}

server {
    # HTTP -> HTTPS redirect
    listen 80;
    listen [::]:80;
    server_name flask.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    # HTTPS
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name flask.example.com;
    
    # SSL
    ssl_certificate /etc/letsencrypt/live/flask.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/flask.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Logs
    access_log /var/log/nginx/flask-access.log;
    error_log /var/log/nginx/flask-error.log;
    
    # Upload size
    client_max_body_size 20M;
    
    # === FICHIERS STATIQUES (CSS, JS, images) ===
    # Flask sert mal les fichiers statiques -> Nginx le fait mieux
    location /static/ {
        alias /var/www/flask_app/static/;
        expires 1M;
        add_header Cache-Control "public";
        access_log off;
    }
    
    # === REVERSE PROXY VERS GUNICORN ===
    location / {
        # Proxy vers Gunicorn
        proxy_pass http://flask_backend;
        
        # Headers essentiels
        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;
        
        # Headers Flask spécifiques
        proxy_set_header X-Scheme $scheme;
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # Buffering
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
        
        # Redirect
        proxy_redirect off;
    }
    
    # === HEALTH CHECK ===
    location /health {
        proxy_pass http://flask_backend/health;
        access_log off;
    }
}

# Activer et recharger:
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx


# === SYSTEMD SERVICE (Auto-start Gunicorn) ===

# /etc/systemd/system/flask_app.service
[Unit]
Description=Gunicorn instance for Flask App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/flask_app
Environment="PATH=/var/www/flask_app/venv/bin"

# Commande Gunicorn
ExecStart=/var/www/flask_app/venv/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:8000 \
    --timeout 30 \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log \
    app:app

# Restart automatique
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

# Créer dossiers logs:
sudo mkdir -p /var/log/gunicorn
sudo chown www-data:www-data /var/log/gunicorn

# Activer et démarrer:
sudo systemctl daemon-reload
sudo systemctl enable flask_app
sudo systemctl start flask_app
sudo systemctl status flask_app


# === STRUCTURE COMPLÈTE PROJET FLASK ===

flask_app/
├── venv/                   # Environnement virtuel
├── app.py                  # Application principale
├── wsgi.py                 # Point d'entrée WSGI
├── gunicorn_config.py      # Config Gunicorn
├── requirements.txt        # Dépendances
├── static/                 # Fichiers statiques
│   ├── css/
│   ├── js/
│   └── images/
├── templates/              # Templates HTML
│   └── index.html
└── logs/                   # Logs application

# wsgi.py (point d'entrée)
from app import app

if __name__ == "__main__":
    app.run()


[OK] DJANGO + GUNICORN + NGINX

# === INSTALLATION ===

pip install django gunicorn

# Créer projet Django:
django-admin startproject myproject
cd myproject


# === CONFIGURATION DJANGO POUR PRODUCTION ===

# myproject/settings.py

# DEBUG = False en production !
DEBUG = False

# Hosts autorisés
ALLOWED_HOSTS = ['django.example.com', 'www.django.example.com']

# Fichiers statiques
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/django_app/static/'  # Pour collectstatic

# Media files (uploads)
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/django_app/media/'

# Sécurité
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')  # Depuis variable env
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'

# Base de données (exemple PostgreSQL)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'django_db',
        'USER': 'django_user',
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


# === COLLECTER FICHIERS STATIQUES ===

# Créer dossier:
sudo mkdir -p /var/www/django_app/static
sudo mkdir -p /var/www/django_app/media
sudo chown -R www-data:www-data /var/www/django_app/

# Collecter:
python manage.py collectstatic --noinput

# Cette commande copie tous CSS/JS/images de Django et apps
# vers STATIC_ROOT pour que Nginx puisse les servir


# === DÉMARRER AVEC GUNICORN ===

gunicorn myproject.wsgi:application \
    --bind 127.0.0.1:8000 \
    --workers 4 \
    --timeout 60 \
    --access-logfile /var/log/gunicorn/django-access.log \
    --error-logfile /var/log/gunicorn/django-error.log


# === CONFIGURATION NGINX POUR DJANGO ===

# /etc/nginx/sites-available/django_app

upstream django_backend {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    listen 80;
    server_name django.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name django.example.com;
    
    # SSL
    ssl_certificate /etc/letsencrypt/live/django.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/django.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Headers sécurité
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    
    # Logs
    access_log /var/log/nginx/django-access.log;
    error_log /var/log/nginx/django-error.log;
    
    # Upload
    client_max_body_size 50M;
    
    # === FICHIERS STATIQUES (CSS, JS, Admin Django) ===
    location /static/ {
        alias /var/www/django_app/static/;
        expires 1M;
        add_header Cache-Control "public";
        access_log off;
    }
    
    # === MEDIA FILES (Uploads utilisateurs) ===
    location /media/ {
        alias /var/www/django_app/media/;
        expires 1d;
        add_header Cache-Control "public";
    }
    
    # === REVERSE PROXY DJANGO ===
    location / {
        proxy_pass http://django_backend;
        
        # 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;
        
        # Timeouts (augmenter si requêtes lentes)
        proxy_connect_timeout 75s;
        proxy_send_timeout 75s;
        proxy_read_timeout 75s;
    }
}


# === SYSTEMD SERVICE DJANGO ===

# /etc/systemd/system/django_app.service
[Unit]
Description=Gunicorn instance for Django App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/django_app
Environment="PATH=/var/www/django_app/venv/bin"
Environment="DJANGO_SECRET_KEY=your-secret-key-here"
Environment="DB_PASSWORD=your-db-password"

ExecStart=/var/www/django_app/venv/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:8000 \
    --timeout 60 \
    --access-logfile /var/log/gunicorn/django-access.log \
    --error-logfile /var/log/gunicorn/django-error.log \
    myproject.wsgi:application

Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

# Activer:
sudo systemctl daemon-reload
sudo systemctl enable django_app
sudo systemctl start django_app


# === STRUCTURE PROJET DJANGO ===

django_app/
├── venv/
├── myproject/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
├── myapp/
│   ├── models.py
│   ├── views.py
│   └── urls.py
├── static/                 # Fichiers dev
├── media/                  # Uploads
├── manage.py
├── requirements.txt
└── gunicorn_config.py


[OK] FASTAPI + UVICORN + NGINX

# FastAPI = Framework moderne, asynchrone
# Uvicorn = Serveur ASGI (pas WSGI!)

# === INSTALLATION ===

pip install fastapi uvicorn[standard]

# === APPLICATION FASTAPI ===

# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI(
    title="Mon API",
    description="API avec FastAPI",
    version="1.0.0"
)

class Item(BaseModel):
    id: int
    name: str
    price: float

# Base de données simulée
items_db = []

@app.get("/")
async def root():
    return {"message": "Welcome to FastAPI"}

@app.get("/api/items", response_model=List[Item])
async def get_items():
    return items_db

@app.post("/api/items", response_model=Item)
async def create_item(item: Item):
    items_db.append(item)
    return item

@app.get("/health")
async def health():
    return {"status": "healthy"}


# === DÉMARRER AVEC UVICORN ===

# Développement:
uvicorn main:app --reload

# Production:
uvicorn main:app \
    --host 0.0.0.0 \
    --port 8000 \
    --workers 4 \
    --log-level info

# Ou avec Gunicorn + Uvicorn workers (RECOMMANDÉ):
gunicorn main:app \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --timeout 60


# === CONFIGURATION NGINX POUR FASTAPI ===

# /etc/nginx/sites-available/fastapi_app

upstream fastapi_backend {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    # SSL
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # CORS headers (si nécessaire)
    add_header Access-Control-Allow-Origin "*" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    
    # Logs
    access_log /var/log/nginx/fastapi-access.log;
    error_log /var/log/nginx/fastapi-error.log;
    
    # === API DOCS (Swagger/ReDoc) ===
    # FastAPI génère docs automatiquement
    location /docs {
        proxy_pass http://fastapi_backend/docs;
        proxy_set_header Host $host;
    }
    
    location /redoc {
        proxy_pass http://fastapi_backend/redoc;
        proxy_set_header Host $host;
    }
    
    # === WEBSOCKET (si utilisé) ===
    location /ws {
        proxy_pass http://fastapi_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
    
    # === API ROUTES ===
    location / {
        proxy_pass http://fastapi_backend;
        
        # 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;
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}


# === SYSTEMD SERVICE FASTAPI ===

# /etc/systemd/system/fastapi_app.service
[Unit]
Description=FastAPI with Uvicorn
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/fastapi_app
Environment="PATH=/var/www/fastapi_app/venv/bin"

# Avec Gunicorn + Uvicorn workers (RECOMMANDÉ)
ExecStart=/var/www/fastapi_app/venv/bin/gunicorn \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 127.0.0.1:8000 \
    --timeout 60 \
    --access-logfile /var/log/fastapi/access.log \
    --error-logfile /var/log/fastapi/error.log \
    main:app

Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target


[OK] PLUSIEURS APPLICATIONS PYTHON SUR UN SERVEUR

# === PAR SOUS-DOMAINE ===

# Structure:
# flask-app.example.com -> Flask sur port 8001
# django-app.example.com -> Django sur port 8002
# fastapi-app.example.com -> FastAPI sur port 8003

# Configuration Nginx:

upstream flask_backend {
    server 127.0.0.1:8001;
}

upstream django_backend {
    server 127.0.0.1:8002;
}

upstream fastapi_backend {
    server 127.0.0.1:8003;
}

# Flask
server {
    listen 443 ssl http2;
    server_name flask-app.example.com;
    
    ssl_certificate /etc/letsencrypt/live/flask-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/flask-app.example.com/privkey.pem;
    
    location / {
        proxy_pass http://flask_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Django
server {
    listen 443 ssl http2;
    server_name django-app.example.com;
    
    ssl_certificate /etc/letsencrypt/live/django-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/django-app.example.com/privkey.pem;
    
    location /static/ {
        alias /var/www/django_app/static/;
    }
    
    location / {
        proxy_pass http://django_backend;
        proxy_set_header Host $host;
    }
}

# FastAPI
server {
    listen 443 ssl http2;
    server_name fastapi-app.example.com;
    
    ssl_certificate /etc/letsencrypt/live/fastapi-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/fastapi-app.example.com/privkey.pem;
    
    location / {
        proxy_pass http://fastapi_backend;
        proxy_set_header Host $host;
    }
}


# === PAR PATH (Chemin URL) ===

# Structure:
# example.com/ -> Site statique
# example.com/flask-app -> Flask
# example.com/django-app -> Django
# example.com/api -> FastAPI

server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    # Site principal (statique)
    root /var/www/html;
    index index.html;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # Flask app
    location /flask-app/ {
        proxy_pass http://127.0.0.1:8001/;
        # Note le / à la fin pour enlever /flask-app/ du path
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # Django app
    location /django-app/ {
        proxy_pass http://127.0.0.1:8002/;
        proxy_set_header Host $host;
    }
    
    # FastAPI
    location /api/ {
        proxy_pass http://127.0.0.1:8003/;
        proxy_set_header Host $host;
    }
}


[OK] OPTIMISATIONS SPÉCIFIQUES PYTHON

# === CACHE POUR API PYTHON ===

http {
    # Zone cache
    proxy_cache_path /var/cache/nginx/python_api
                     levels=1:2
                     keys_zone=python_api:50m
                     max_size=5g
                     inactive=1h;
    
    server {
        listen 443 ssl http2;
        server_name api.example.com;
        
        # API publique (cache court)
        location /api/public/ {
            proxy_pass http://python_backend;
            
            # Cache 5 minutes
            proxy_cache python_api;
            proxy_cache_valid 200 5m;
            proxy_cache_key "$request_uri";
            
            add_header X-Cache-Status $upstream_cache_status;
            proxy_set_header Host $host;
        }
        
        # API privée (pas de cache)
        location /api/private/ {
            proxy_pass http://python_backend;
            proxy_cache_bypass 1;
            proxy_set_header Host $host;
        }
    }
}


# === RATE LIMITING API PYTHON ===

http {
    # Rate limiting agressif pour API
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;
    limit_req_zone $binary_remote_addr zone=api_burst:10m rate=10r/s;
    
    server {
        listen 443 ssl http2;
        server_name api.example.com;
        
        # Endpoints normaux
        location /api/ {
            limit_req zone=api_burst burst=20 nodelay;
            proxy_pass http://python_backend;
        }
        
        # Endpoint de recherche (plus strict)
        location /api/search {
            limit_req zone=api_limit burst=5 nodelay;
            proxy_pass http://python_backend;
        }
    }
}


# === COMPRESSION SPÉCIFIQUE JSON ===

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        application/json
        application/javascript
        text/plain
        text/css
        text/xml
        application/xml;
    
    # Pour APIs JSON, compression cruciale!
    # JSON typiquement compresse 70-80%
}


# === TIMEOUT POUR TÂCHES LONGUES ===

# Si votre app Python fait traitement long

location /api/process {
    proxy_pass http://python_backend;
    
    # Timeouts longs
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    
    # Pour tâches TRÈS longues, considérer:
    # - Celery (tâches asynchrones)
    # - Streaming response
    # - WebSocket
}


[OK] DÉBOGAGE ET MONITORING

# === VÉRIFIER QUE GUNICORN TOURNE ===

# Vérifier processus:
ps aux | grep gunicorn

# Devrait montrer:
# - 1 processus master
# - X processus workers

# Vérifier port:
sudo netstat -tulpn | grep 8000

# Tester directement Gunicorn (bypass Nginx):
curl http://localhost:8000


# === LOGS GUNICORN ===

# Accès:
sudo tail -f /var/log/gunicorn/access.log

# Erreurs:
sudo tail -f /var/log/gunicorn/error.log

# Erreurs Python app:
sudo journalctl -u flask_app -f


# === LOGS NGINX ===

# Accès:
sudo tail -f /var/log/nginx/access.log

# Erreurs:
sudo tail -f /var/log/nginx/error.log


# === TESTER CONFIGURATION COMPLÈTE ===

# 1. Tester app Python directement:
curl http://localhost:8000

# 2. Tester via Nginx:
curl https://example.com

# 3. Comparer temps de réponse:
time curl http://localhost:8000
time curl https://example.com

# 4. Vérifier headers:
curl -I https://example.com

# Devrait voir headers Nginx (gzip, cache, etc.)


[OK] ERREURS COURANTES

# === ERREUR: 502 Bad Gateway ===

# Cause 1: Gunicorn pas démarré
sudo systemctl status flask_app
sudo systemctl start flask_app

# Cause 2: Mauvais port
# Vérifier nginx.conf:
proxy_pass http://127.0.0.1:8000;
# Vérifier Gunicorn écoute bien sur 8000

# Cause 3: Firewall bloque
sudo ufw allow 8000  # Temporairement pour tester


# === ERREUR: 404 sur fichiers statiques ===

# Cause: Chemin incorrect

# Django:
# 1. Vérifier STATIC_ROOT dans settings.py
STATIC_ROOT = '/var/www/django_app/static/'

# 2. Collecter fichiers statiques
python manage.py collectstatic --noinput

# 3. Vérifier permissions
sudo chown -R www-data:www-data /var/www/django_app/static/

# 4. Vérifier Nginx:
location /static/ {
    alias /var/www/django_app/static/;  # Doit correspondre à STATIC_ROOT
}


# === ERREUR: Application lente ===

# Cause: Pas assez de workers

# Règle: 2-4 × nombre de CPU cores
# Vérifier nombre CPUs:
nproc

# Si 2 CPUs -> 4-8 workers
gunicorn app:app --workers 6

# Ou avec config:
workers = multiprocessing.cpu_count() * 2 + 1


# === ERREUR: Connection refused ===

# Gunicorn écoute sur 127.0.0.1 mais Nginx tente autre IP

# Solution: Vérifier bind dans Gunicorn match proxy_pass dans Nginx
# Gunicorn:
--bind 127.0.0.1:8000

# Nginx:
proxy_pass http://127.0.0.1:8000;


# === ERREUR: Timeout ===

# Application Python prend trop de temps

# Solution 1: Augmenter timeout Gunicorn
gunicorn app:app --timeout 120

# Solution 2: Augmenter timeout Nginx
proxy_read_timeout 120s;

# Solution 3: Refactorer code Python (préférable!)
# - Utiliser cache Redis
# - Optimiser requêtes database
# - Utiliser Celery pour tâches longues


[OK] EXEMPLES AVANCÉS

# === DJANGO AVEC CELERY (Tâches asynchrones) ===

# Architecture:
# Nginx -> Gunicorn -> Django (requêtes web)
#                  -> Celery Worker (tâches async)
#                  -> Redis/RabbitMQ (broker)

# Installation:
pip install celery redis

# Django settings.py:
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

# Celery config (myproject/celery.py):
from celery import Celery
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

# Tâche exemple (myapp/tasks.py):
from celery import shared_task

@shared_task
def process_data(data):
    # Tâche longue qui tourne en arrière-plan
    import time
    time.sleep(10)
    return f"Processed: {data}"

# Vue Django qui utilise Celery:
from django.http import JsonResponse
from .tasks import process_data

def start_processing(request):
    # Lance tâche asynchrone
    task = process_data.delay("some data")
    return JsonResponse({'task_id': task.id})

def check_processing(request, task_id):
    # Vérifie statut tâche
    task = process_data.AsyncResult(task_id)
    return JsonResponse({
        'state': task.state,
        'result': task.result if task.ready() else None
    })


# Systemd service pour Celery Worker:
# /etc/systemd/system/celery_worker.service
[Unit]
Description=Celery Worker
After=network.target redis.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/django_app
Environment="PATH=/var/www/django_app/venv/bin"

ExecStart=/var/www/django_app/venv/bin/celery -A myproject worker \
    --loglevel=info \
    --concurrency=4 \
    --logfile=/var/log/celery/worker.log

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

# Nginx reste inchangé (proxy vers Gunicorn seulement)


# === FLASK AVEC WEBSOCKET (Flask-SocketIO) ===

# Installation:
pip install flask-socketio eventlet

# app.py:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('message')
def handle_message(data):
    print(f'Received: {data}')
    emit('response', {'data': 'Message reçu!'})

@socketio.on('connect')
def handle_connect():
    print('Client connecté')

if __name__ == '__main__':
    socketio.run(app, host='127.0.0.1', port=8000)

# Démarrer avec Eventlet:
gunicorn --worker-class eventlet -w 1 app:app --bind 127.0.0.1:8000

# Nginx config WebSocket:
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen 443 ssl http2;
    server_name chat.example.com;
    
    ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
    
    location /socket.io/ {
        proxy_pass http://127.0.0.1:8000/socket.io/;
        
        # WebSocket headers
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        
        # Timeouts longs
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
    }
}


# === FASTAPI AVEC STREAMING RESPONSE ===

# Pour envoyer données progressivement (téléchargement fichier, etc.)

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio

app = FastAPI()

async def generate_data():
    for i in range(100):
        yield f"data: {i}\n\n"
        await asyncio.sleep(0.1)

@app.get("/stream")
async def stream():
    return StreamingResponse(
        generate_data(),
        media_type="text/event-stream"
    )

# Nginx config pour streaming:
location /stream {
    proxy_pass http://fastapi_backend;
    
    # Désactiver buffering pour streaming
    proxy_buffering off;
    proxy_cache off;
    
    # Headers
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding on;
    
    proxy_set_header Host $host;
}


# === MULTI-TENANCY (Plusieurs clients/tenants) ===

# Routage basé sur sous-domaine

# Structure:
# client1.example.com -> Instance Python pour client1
# client2.example.com -> Instance Python pour client2
# client3.example.com -> Instance Python pour client3

upstream client1_backend {
    server 127.0.0.1:8001;
}

upstream client2_backend {
    server 127.0.0.1:8002;
}

upstream client3_backend {
    server 127.0.0.1:8003;
}

# Template serveur (répéter pour chaque client)
server {
    listen 443 ssl http2;
    server_name client1.example.com;
    
    ssl_certificate /etc/letsencrypt/live/client1.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/client1.example.com/privkey.pem;
    
    location / {
        proxy_pass http://client1_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Ou dynamique avec map:
map $host $backend {
    client1.example.com 127.0.0.1:8001;
    client2.example.com 127.0.0.1:8002;
    client3.example.com 127.0.0.1:8003;
    default 127.0.0.1:8000;
}

server {
    listen 443 ssl http2;
    server_name *.example.com;
    
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    location / {
        proxy_pass http://$backend;
        proxy_set_header Host $host;
    }
}


# === API VERSIONING ===

# Structure:
# /api/v1/ -> Version 1 (port 8001)
# /api/v2/ -> Version 2 (port 8002)

upstream api_v1 {
    server 127.0.0.1:8001;
}

upstream api_v2 {
    server 127.0.0.1:8002;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    
    # API v1
    location /api/v1/ {
        proxy_pass http://api_v1/;
        proxy_set_header Host $host;
    }
    
    # API v2
    location /api/v2/ {
        proxy_pass http://api_v2/;
        proxy_set_header Host $host;
    }
    
    # Redirection racine vers dernière version
    location = /api/ {
        return 302 /api/v2/;
    }
}


[OK] MONITORING ET HEALTHCHECKS

# === ENDPOINT HEALTH CHECK ===

# Flask:
@app.route('/health')
def health():
    # Vérifier connexion DB, Redis, etc.
    try:
        db.session.execute('SELECT 1')
        redis_client.ping()
        return {'status': 'healthy'}, 200
    except Exception as e:
        return {'status': 'unhealthy', 'error': str(e)}, 503

# Django:
from django.http import JsonResponse
from django.db import connection

def health(request):
    try:
        connection.ensure_connection()
        return JsonResponse({'status': 'healthy'})
    except Exception as e:
        return JsonResponse({'status': 'unhealthy', 'error': str(e)}, status=503)

# FastAPI:
@app.get("/health")
async def health():
    return {"status": "healthy"}

# Nginx config:
location /health {
    proxy_pass http://python_backend/health;
    access_log off;  # Ne pas logger health checks
}

# Test automatique:
# Cron job qui vérifie toutes les 5 minutes:
*/5 * * * * curl -f http://localhost/health || systemctl restart flask_app


# === PROMETHEUS METRICS ===

# Flask avec prometheus_client:
pip install prometheus-client

from prometheus_client import Counter, Histogram, generate_latest

# Métriques
REQUEST_COUNT = Counter('app_requests_total', 'Total requests')
REQUEST_DURATION = Histogram('app_request_duration_seconds', 'Request duration')

@app.before_request
def before_request():
    request.start_time = time.time()

@app.after_request
def after_request(response):
    REQUEST_COUNT.inc()
    duration = time.time() - request.start_time
    REQUEST_DURATION.observe(duration)
    return response

@app.route('/metrics')
def metrics():
    return generate_latest()

# Nginx:
location /metrics {
    proxy_pass http://python_backend/metrics;
    allow 127.0.0.1;  # Seulement depuis localhost
    deny all;
}


[OK] SÉCURITÉ SPÉCIFIQUE PYTHON

# === PROTECTION CSRF DJANGO ===

# Django a protection CSRF intégrée
# Nginx doit passer cookies correctement:

location / {
    proxy_pass http://django_backend;
    
    # Ne PAS filtrer cookies
    proxy_set_header Cookie $http_cookie;
    
    # Headers CSRF
    proxy_set_header X-CSRFToken $http_x_csrftoken;
}


# === CORS POUR API ===

# Si API Python utilisée par frontend JavaScript

# Option 1: Dans Nginx
server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    # CORS headers
    add_header Access-Control-Allow-Origin "https://frontend.example.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always;
    add_header Access-Control-Allow-Credentials "true" always;
    
    # Preflight requests
    if ($request_method = OPTIONS) {
        return 204;
    }
    
    location / {
        proxy_pass http://python_backend;
    }
}

# Option 2: Dans Python (Flask-CORS)
pip install flask-cors

from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins=["https://frontend.example.com"])


# === AUTHENTIFICATION JWT ===

# Valider JWT dans Nginx avant d'atteindre Python

# Nécessite module lua ou auth_request
# Exemple avec auth_request:

location /api/protected/ {
    # Vérifier JWT d'abord
    auth_request /auth;
    
    proxy_pass http://python_backend;
}

location = /auth {
    internal;
    proxy_pass http://python_backend/validate-token;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}


# === RATE LIMITING PAR USER ===

# Limiter par token/user au lieu d'IP

# Dans Python, ajouter header avec user ID
response.headers['X-User-ID'] = current_user.id

# Dans Nginx:
map $http_x_user_id $limit_key {
    default $http_x_user_id;
    '' $binary_remote_addr;  # Fallback sur IP si pas de user
}

limit_req_zone $limit_key zone=per_user:10m rate=100r/m;

location /api/ {
    limit_req zone=per_user burst=20 nodelay;
    proxy_pass http://python_backend;
}


[OK] DÉPLOIEMENT AUTOMATISÉ

# === SCRIPT DÉPLOIEMENT COMPLET ===

#!/bin/bash
# deploy.sh - Script déploiement application Python

set -e  # Arrêter si erreur

APP_NAME="flask_app"
APP_DIR="/var/www/flask_app"
VENV_DIR="$APP_DIR/venv"
GIT_REPO="https://github.com/user/flask_app.git"

echo "=== Déploiement $APP_NAME ==="

# 1. Pull dernières modifications
cd $APP_DIR
git pull origin main

# 2. Activer virtualenv
source $VENV_DIR/bin/activate

# 3. Installer/mettre à jour dépendances
pip install -r requirements.txt --upgrade

# 4. Django: Migrations et collectstatic
if [ -f "manage.py" ]; then
    python manage.py migrate --noinput
    python manage.py collectstatic --noinput
fi

# 5. Tests
pytest tests/ || {
    echo "Tests échoués! Rollback..."
    git reset --hard HEAD~1
    exit 1
}

# 6. Recharger Gunicorn
sudo systemctl restart $APP_NAME

# 7. Vérifier santé
sleep 5
curl -f http://localhost:8000/health || {
    echo "Health check échoué! Rollback..."
    sudo systemctl restart $APP_NAME
    exit 1
}

# 8. Purger cache Nginx (si configuré)
sudo rm -rf /var/cache/nginx/python_api/*
sudo systemctl reload nginx

echo "=== Déploiement réussi! ==="


# === AVEC DOCKER COMPOSE ===

# docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/ssl:ro
      - static_volume:/var/www/static:ro
    depends_on:
      - flask_app
    restart: unless-stopped

  flask_app:
    build: .
    command: gunicorn app:app --bind 0.0.0.0:8000 --workers 4
    volumes:
      - ./app:/app
      - static_volume:/app/static
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - db
      - redis
    restart: unless-stopped

  db:
    image: postgres:14-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  postgres_data:
  static_volume:

# Déployer:
docker-compose up -d --build


# === AVEC ANSIBLE ===

# playbook.yml
---
- name: Déployer application Flask
  hosts: webserver
  become: yes
  
  vars:
    app_name: flask_app
    app_dir: /var/www/flask_app
    git_repo: https://github.com/user/flask_app.git
  
  tasks:
    - name: Installer dépendances système
      apt:
        name:
          - python3
          - python3-pip
          - python3-venv
          - nginx
        state: present
        update_cache: yes
    
    - name: Cloner repository
      git:
        repo: "{{ git_repo }}"
        dest: "{{ app_dir }}"
        version: main
    
    - name: Créer virtualenv
      pip:
        requirements: "{{ app_dir }}/requirements.txt"
        virtualenv: "{{ app_dir }}/venv"
        virtualenv_python: python3
    
    - name: Copier config Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/sites-available/{{ app_name }}
    
    - name: Activer site Nginx
      file:
        src: /etc/nginx/sites-available/{{ app_name }}
        dest: /etc/nginx/sites-enabled/{{ app_name }}
        state: link
    
    - name: Copier service systemd
      template:
        src: app.service.j2
        dest: /etc/systemd/system/{{ app_name }}.service
    
    - name: Démarrer services
      systemd:
        name: "{{ item }}"
        state: restarted
        enabled: yes
        daemon_reload: yes
      loop:
        - "{{ app_name }}"
        - nginx

# Déployer:
ansible-playbook -i inventory playbook.yml


[OK] CHECKLIST PRODUCTION PYTHON + NGINX

[ ] === APPLICATION PYTHON ===
[ ] DEBUG = False (Django)
[ ] ALLOWED_HOSTS configuré (Django)
[ ] SECRET_KEY dans variable environnement
[ ] Base de données production configurée
[ ] Migrations appliquées (Django)
[ ] Tests passent
[ ] Requirements.txt à jour
[ ] Logs configurés

[ ] === GUNICORN ===
[ ] Workers = 2-4 × CPU cores
[ ] Timeout approprié pour votre app
[ ] Logs configurés (access + error)
[ ] Service systemd créé
[ ] Auto-restart configuré
[ ] Écoute sur 127.0.0.1 (pas 0.0.0.0 si derrière Nginx)

[ ] === NGINX ===
[ ] Configuration testée (nginx -t)
[ ] HTTPS configuré (Let's Encrypt)
[ ] Redirection HTTP -> HTTPS
[ ] Headers sécurité
[ ] Fichiers statiques servis par Nginx
[ ] Gzip activé
[ ] Cache configuré si applicable
[ ] Rate limiting sur API
[ ] Logs rotatés

[ ] === SÉCURITÉ ===
[ ] Firewall configuré (UFW)
[ ] SSH avec clés (pas password)
[ ] Fail2ban installé
[ ] Mises à jour automatiques système
[ ] Backup réguliers DB
[ ] Monitoring actif

[ ] === PERFORMANCE ===
[ ] Cache Redis/Memcached si nécessaire
[ ] Connection pooling DB
[ ] Celery pour tâches longues
[ ] CDN pour fichiers statiques
[ ] Database optimisée (index, queries)


[OK] RESSOURCES PYTHON + NGINX

# === DOCUMENTATION ===
# Gunicorn: https://docs.gunicorn.org/
# uWSGI: https://uwsgi-docs.readthedocs.io/
# Flask deployment: https://flask.palletsprojects.com/en/latest/deploying/
# Django deployment: https://docs.djangoproject.com/en/stable/howto/deployment/
# FastAPI deployment: https://fastapi.tiangolo.com/deployment/

# === OUTILS ===
# Supervisor: Process manager alternatif
# systemd: Process manager moderne (recommandé)
# Docker: Containerisation
# Ansible: Automatisation déploiement

# === MONITORING ===
# Sentry: Error tracking Python
# New Relic: APM complet
# Datadog: Monitoring infrastructure
# Prometheus + Grafana: Open source


[OK] COMMANDES ESSENTIELLES MÉMO

# Gunicorn:
gunicorn app:app --bind 127.0.0.1:8000 --workers 4

# Systemd:
sudo systemctl restart flask_app
sudo systemctl status flask_app
sudo journalctl -u flask_app -f

# Nginx:
sudo nginx -t
sudo systemctl reload nginx

# Django:
python manage.py migrate
python manage.py collectstatic --noinput

# Logs:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/gunicorn/error.log

# Test:
curl http://localhost:8000
curl https://example.com

# Debug:
ps aux | grep gunicorn
netstat -tulpn | grep 8000


# === FIN DU GUIDE NGINX POUR PYTHON ===
# Bonne chance avec votre déploiement Python! [PYTHON][RAPIDE]
echo ""

echo "7. Test santé app:"
curl -s http://127.0.0.1:8000/health
echo ""

echo "=== Fin vérification ==="
EOF

chmod +x ~/check_app.sh

# Exécuter:
~/check_app.sh


[OK] ÉTAPE 11 - OPTIMISATIONS PRODUCTION

# === AJOUTER CACHE NGINX ===

# Éditer config Nginx:
sudo nano /etc/nginx/sites-available/flask_app

# Ajouter dans bloc http ou server:

# Cache pour API (dans bloc server)
location /api/ {
    proxy_pass http://flask_backend;
    
    # Cache 5 minutes
    proxy_cache_valid 200 5m;
    proxy_cache_bypass $http_cache_control;
    
    # Headers
    add_header X-Cache-Status $upstream_cache_status;
    
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

# Sauvegarder, tester, recharger:
sudo nginx -t
sudo systemctl reload nginx


# === ACTIVER COMPRESSION GZIP ===

# Éditer config principale Nginx:
sudo nano /etc/nginx/nginx.conf

# Chercher section "Gzip Settings" et activer:

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

# Sauvegarder et recharger:
sudo systemctl reload nginx


# === AJOUTER RATE LIMITING ===

# Protection contre abus API

# Éditer config:
sudo nano /etc/nginx/sites-available/flask_app

# Ajouter AVANT bloc server:

# Zone rate limiting
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;

# Dans location /api/:
location /api/ {
    # Limiter à 100 requêtes/minute par IP
    limit_req zone=api_limit burst=20 nodelay;
    
    proxy_pass http://flask_backend;
    proxy_set_header Host $host;
}


# === MONITORING AVEC HEALTH CHECK ===

# Script vérifie santé toutes les 5 minutes:
cat > ~/health_monitor.sh << 'EOF'
#!/bin/bash
HEALTH_URL="http://127.0.0.1:8000/health"
RESPONSE=$(curl -s $HEALTH_URL)

if [[ $RESPONSE != *"healthy"* ]]; then
    echo "App unhealthy! Restarting..."
    sudo systemctl restart flask_app
    echo "$(date): App restarted" >> ~/health_monitor.log
fi
EOF

chmod +x ~/health_monitor.sh

# Ajouter au crontab:
crontab -e
# Ajouter ligne:
*/5 * * * * ~/health_monitor.sh


[OK] COMMANDES MÉMO RAPIDE

# === SUR WINDOWS (Développement) ===

# Activer venv:
venv\Scripts\Activate.ps1

# Lancer dev:
python app.py

# Commit changements:
git add .
git commit -m "Description"
git push origin main


# === SUR SERVEUR LINUX (Production) ===

# Se connecter:
ssh flaskuser@votre-ip

# Aller dans dossier app:
cd /var/www/flask_app

# Mettre à jour code:
git pull origin main

# Redémarrer app:
sudo systemctl restart flask_app

# Voir statut:
sudo systemctl status flask_app

# Voir logs:
sudo journalctl -u flask_app -f

# Recharger Nginx:
sudo nginx -t
sudo systemctl reload nginx

# Vérifier santé:
curl http://127.0.0.1:8000/health


# === FICHIERS IMPORTANTS À CONNAÎTRE ===

# Configuration app Flask:
/var/www/flask_app/app.py

# Configuration Gunicorn:
/var/www/flask_app/gunicorn_config.py

# Service systemd:
/etc/systemd/system/flask_app.service

# Configuration Nginx:
/etc/nginx/sites-available/flask_app
/etc/nginx/sites-enabled/flask_app

# Logs Gunicorn:
/var/www/flask_app/logs/gunicorn_access.log
/var/www/flask_app/logs/gunicorn_error.log

# Logs Nginx:
/var/log/nginx/access.log
/var/log/nginx/error.log

# Certificats SSL:
/etc/letsencrypt/live/votre-domaine.com/


[OK] CHECKLIST COMPLÈTE DÉPLOIEMENT

[ ] === PRÉPARATION (Windows) ===
[ ] Application Flask fonctionne en local
[ ] requirements.txt à jour (pip freeze > requirements.txt)
[ ] .gitignore créé (venv/, __pycache__/, etc.)
[ ] Code poussé sur GitHub/GitLab
[ ] Domaine acheté et DNS configuré

[ ] === SERVEUR (Linux) ===
[ ] Serveur Ubuntu créé et accessible SSH
[ ] Système mis à jour (apt update && apt upgrade)
[ ] Python3, pip, venv installés
[ ] Nginx installé
[ ] Git installé
[ ] Utilisateur créé (flaskuser)

[ ] === APPLICATION ===
[ ] Code cloné dans /var/www/flask_app
[ ] Virtualenv créé (python3 -m venv venv)
[ ] Dépendances installées (pip install -r requirements.txt)
[ ] gunicorn_config.py créé
[ ] Dossier logs créé
[ ] Gunicorn testé manuellement

[ ] === NGINX ===
[ ] Site par défaut désactivé
[ ] Configuration flask_app créée dans sites-available/
[ ] Lien symbolique créé dans sites-enabled/
[ ] Configuration testée (nginx -t)
[ ] Nginx rechargé

[ ] === SYSTEMD ===
[ ] Service flask_app.service créé
[ ] daemon-reload exécuté
[ ] Service enabled (démarrage auto)
[ ] Service started
[ ] Service status vérifié (active running)

[ ] === TESTS ===
[ ] Application accessible dans navigateur
[ ] Fichiers statiques se chargent
[ ] API répond correctement
[ ] Logs s'écrivent correctement

[ ] === HTTPS ===
[ ] Certbot installé
[ ] Certificat SSL obtenu
[ ] HTTPS fonctionne (cadenas vert)
[ ] HTTP redirige vers HTTPS
[ ] Renouvellement automatique testé

[ ] === MONITORING ===
[ ] Health check endpoint fonctionne
[ ] Logs surveillés
[ ] Backup configuré (optionnel)


[OK] RESSOURCES SUPPLÉMENTAIRES

# === DOCUMENTATION ===
# Flask: https://flask.palletsprojects.com/
# Gunicorn: https://docs.gunicorn.org/
# Nginx: https://nginx.org/en/docs/
# Let's Encrypt: https://letsencrypt.org/docs/
# systemd: https://systemd.io/

# === TUTORIELS VIDÉO ===
# Chercher sur YouTube:
# - "Flask deployment"
# - "Nginx Flask tutorial"
# - "Gunicorn systemd"

# === OUTILS UTILES ===
# DigitalOcean: VPS simple et pas cher
# PuTTY: Client SSH pour Windows
# WinSCP: Transfert fichiers SFTP
# VS Code Remote: Éditer fichiers directement sur serveur

# === COMMUNAUTÉS ===
# Stack Overflow: tag [flask] [nginx]
# Reddit: r/flask, r/webdev
# Discord: Serveurs Flask/Python


[OK] EXEMPLE COMPLET - RÉSUMÉ

# === STRUCTURE FINALE PROJET ===

# Sur Windows (développement):
C:\Users\VotreNom\flask_app\
├── venv\                    # Environnement virtuel (ne pas commiter)
├── static\
│   ├── style.css
│   └── app.js
├── templates\
│   └── index.html
├── app.py                   # Application Flask
├── requirements.txt         # Dépendances Python
├── .gitignore              # Fichiers à ignorer Git
└── README.md               # Documentation projet

# Sur Linux (production):
/var/www/flask_app/
├── venv/                    # Environnement virtuel serveur
├── static/
│   ├── style.css
│   └── app.js
├── templates/
│   └── index.html
├── logs/                    # Logs Gunicorn
│   ├── gunicorn_access.log
│   └── gunicorn_error.log
├── app.py                   # Application Flask
├── gunicorn_config.py       # Config Gunicorn
├── requirements.txt         # Dépendances
└── README.md

# Configuration système:
/etc/nginx/sites-available/flask_app    # Config Nginx
/etc/systemd/system/flask_app.service   # Service systemd


# === WORKFLOW COMPLET ===

# 1. DÉVELOPPEMENT (Windows)
# - Coder dans VS Code
# - Tester: python app.py
# - Commiter: git commit
# - Pusher: git push

# 2. DÉPLOIEMENT (Linux)
# - Connecter SSH: ssh flaskuser@server
# - Update code: git pull
# - Restart: sudo systemctl restart flask_app
# - Vérifier: curl http://localhost:8000/health

# 3. VÉRIFICATION
# - Navigateur: https://votre-domaine.com
# - Logs: sudo journalctl -u flask_app -f
# - Monitoring: ~/check_app.sh


# === PROCHAINES ÉTAPES ===

# Une fois déploiement réussi, vous pouvez:
# 1. Ajouter base de données (PostgreSQL, MySQL)
# 2. Configurer Redis pour cache
# 3. Ajouter Celery pour tâches asynchrones
# 4. Mettre en place monitoring (Sentry, New Relic)
# 5. Configurer backup automatique
# 6. Ajouter CI/CD (GitHub Actions, GitLab CI)
# 7. Scaler avec load balancing


# === FIN DU GUIDE ===
# Félicitations! Vous savez maintenant déployer Flask avec Nginx! [BRAVO][RAPIDE]

# Ce guide vous a montré:
# [OK] Créer application Flask sur Windows
# [OK] Configurer serveur Linux
# [OK] Installer et configurer Nginx
# [OK] Déployer avec Gunicorn
# [OK] Automatiser avec systemd
# [OK] Sécuriser avec HTTPS
# [OK] Maintenir et débugger

# Bon déploiement! [PYTHON]# Fichier: python_cheats/cheatsheets/nginx_for_python.txt
# Nginx pour Applications Python - Guide Complet


[OK] INTRODUCTION - NGINX ET PYTHON

# === POURQUOI NGINX AVEC PYTHON ? ===

# Python n'est PAS conçu pour servir directement du HTTP en production
# Problèmes sans Nginx:
# [X] Serveur dev (Flask, Django) lent et non sécurisé
# [X] Pas de gestion SSL/HTTPS
# [X] Pas de cache
# [X] Pas de fichiers statiques optimisés
# [X] Pas de load balancing
# [X] Vulnérable aux attaques

# Architecture CLASSIQUE en production:
# 
# Internet -> Nginx (port 80/443) -> Gunicorn/uWSGI -> Application Python
#              ^                        ^                    ^
#         Reverse proxy         WSGI Server          Flask/Django/FastAPI
#         SSL, Cache            Multi-workers         Logique métier
#         Fichiers statiques    Process manager

# Nginx gère:
# [OK] SSL/HTTPS
# [OK] Fichiers statiques (CSS, JS, images)
# [OK] Cache
# [OK] Compression (gzip)
# [OK] Load balancing
# [OK] Rate limiting
# [OK] Sécurité

# Serveur WSGI (Gunicorn/uWSGI) gère:
# [OK] Multiple workers Python
# [OK] Process management
# [OK] Auto-restart
# [OK] Interface WSGI

# Application Python gère:
# [OK] Logique métier
# [OK] Base de données
# [OK] API/Views


# === SERVEURS WSGI POUR PYTHON ===

# 1. GUNICORN (Recommandé - Simple et efficace)
#    - Green Unicorn
#    - Pure Python
#    - Facile à configurer
#    - Utilisé par Instagram, Spotify, etc.

# 2. uWSGI (Puissant mais complexe)
#    - Très performant
#    - Beaucoup d'options
#    - Plus difficile à configurer

# 3. Waitress (Windows-friendly)
#    - Pure Python
#    - Fonctionne bien sur Windows
#    - Moins performant que Gunicorn

# 4. Uvicorn (Pour FastAPI/AsyncIO)
#    - Serveur ASGI (pas WSGI)
#    - Pour applications asynchrones
#    - FastAPI, Starlette


[OK] FLASK + GUNICORN + NGINX

# === INSTALLATION ===

# 1. Installer Flask et Gunicorn
pip install flask gunicorn

# 2. Créer application Flask
# app.py
from flask import Flask, render_template, jsonify
import os

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html')

@app.route('/api/data')
def api_data():
    return jsonify({
        'status': 'success',
        'data': {'message': 'Hello from Flask!'}
    })

@app.route('/health')
def health():
    return jsonify({'status': 'healthy'}), 200

if __name__ == '__main__':
    # NE PAS utiliser en production !
    app.run(debug=True)


# === DÉMARRER AVEC GUNICORN ===

# Commande basique:
gunicorn app:app
# app:app = fichier:objet_app
# Écoute sur 127.0.0.1:8000 par défaut

# Avec options:
gunicorn app:app \
    --bind 0.0.0.0:8000 \
    --workers 4 \
    --worker-class sync \
    --timeout 30 \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log

# Explication options:
# --bind 0.0.0.0:8000       -> IP et port (0.0.0.0 = toutes interfaces)
# --workers 4               -> 4 processus workers (2-4 × nb CPU)
# --worker-class sync       -> Type worker (sync, gevent, eventlet)
# --timeout 30              -> Timeout requêtes (secondes)
# --access-logfile          -> Log des requêtes
# --error-logfile           -> Log des erreurs


# === CONFIGURATION GUNICORN (gunicorn_config.py) ===

# gunicorn_config.py
import multiprocessing

# Bind
bind = "127.0.0.1:8000"

# Workers
workers = multiprocessing.cpu_count() * 2 + 1  # Formule recommandée
worker_class = "sync"  # ou "gevent" pour async

# Timeouts
timeout = 30
keepalive = 2

# Logs
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
loglevel = "info"

# Process naming
proc_name = "flask_app"

# Server mechanics
daemon = False  # Ne pas daemonizer (systemd gère ça)
pidfile = "/var/run/gunicorn.pid"
umask = 0o007
user = None
group = None
tmp_upload_dir = None

# Démarrer avec config:
# gunicorn app:app -c gunicorn_config.py


# === CONFIGURATION NGINX POUR FLASK ===

# /etc/nginx/sites-available/flask_app

upstream flask_backend {
    # Gunicorn écoute sur localhost:8000
    server 127.0.0.1:8000 fail_timeout=0;
    
    # Si plusieurs workers Gunicorn sur ports différents:
    # server 127.0.0.1:8000;
    # server 127.0.0.1:8001;
    # server 127.0.0.1:8002;
}

server {
    # HTTP -> HTTPS redirect
    listen 80;
    listen [::]:80;
    server_name flask.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    # HTTPS
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name flask.example.com;
    
    # SSL
    ssl_certificate /etc/letsencrypt/live/flask.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/flask.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Logs
    access_log /var/log/nginx/flask-access.log;
    error_log /var/log/nginx/flask-error.log;
    
    # Upload size
    client_max_body_size 20M;
    
    # === FICHIERS STATIQUES (CSS, JS, images) ===
    # Flask sert mal les fichiers statiques -> Nginx le fait mieux
    location /static/ {
        alias /var/www/flask_app/static/;
        expires 1M;
        add_header Cache-Control "public";
        access_log off;
    }
    
    # === REVERSE PROXY VERS GUNICORN ===
    location / {
        # Proxy vers Gunicorn
        proxy_pass http://flask_backend;
        
        # Headers essentiels
        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;
        
        # Headers Flask spécifiques
        proxy_set_header X-Scheme $scheme;
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # Buffering
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
        
        # Redirect
        proxy_redirect off;
    }
    
    # === HEALTH CHECK ===
    location /health {
        proxy_pass http://flask_backend/health;
        access_log off;
    }
}

# Activer et recharger:
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx


# === SYSTEMD SERVICE (Auto-start Gunicorn) ===

# /etc/systemd/system/flask_app.service
[Unit]
Description=Gunicorn instance for Flask App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/flask_app
Environment="PATH=/var/www/flask_app/venv/bin"

# Commande Gunicorn
ExecStart=/var/www/flask_app/venv/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:8000 \
    --timeout 30 \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log \
    app:app

# Restart automatique
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

# Créer dossiers logs:
sudo mkdir -p /var/log/gunicorn
sudo chown www-data:www-data /var/log/gunicorn

# Activer et démarrer:
sudo systemctl daemon-reload
sudo systemctl enable flask_app
sudo systemctl start flask_app
sudo systemctl status flask_app


# === STRUCTURE COMPLÈTE PROJET FLASK ===

flask_app/
├── venv/                   # Environnement virtuel
├── app.py                  # Application principale
├── wsgi.py                 # Point d'entrée WSGI
├── gunicorn_config.py      # Config Gunicorn
├── requirements.txt        # Dépendances
├── static/                 # Fichiers statiques
│   ├── css/
│   ├── js/
│   └── images/
├── templates/              # Templates HTML
│   └── index.html
└── logs/                   # Logs application

# wsgi.py (point d'entrée)
from app import app

if __name__ == "__main__":
    app.run()


[OK] DJANGO + GUNICORN + NGINX

# === INSTALLATION ===

pip install django gunicorn

# Créer projet Django:
django-admin startproject myproject
cd myproject


# === CONFIGURATION DJANGO POUR PRODUCTION ===

# myproject/settings.py

# DEBUG = False en production !
DEBUG = False

# Hosts autorisés
ALLOWED_HOSTS = ['django.example.com', 'www.django.example.com']

# Fichiers statiques
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/django_app/static/'  # Pour collectstatic

# Media files (uploads)
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/django_app/media/'

# Sécurité
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')  # Depuis variable env
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'

# Base de données (exemple PostgreSQL)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'django_db',
        'USER': 'django_user',
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


# === COLLECTER FICHIERS STATIQUES ===

# Créer dossier:
sudo mkdir -p /var/www/django_app/static
sudo mkdir -p /var/www/django_app/media
sudo chown -R www-data:www-data /var/www/django_app/

# Collecter:
python manage.py collectstatic --noinput

# Cette commande copie tous CSS/JS/images de Django et apps
# vers STATIC_ROOT pour que Nginx puisse les servir


# === DÉMARRER AVEC GUNICORN ===

gunicorn myproject.wsgi:application \
    --bind 127.0.0.1:8000 \
    --workers 4 \
    --timeout 60 \
    --access-logfile /var/log/gunicorn/django-access.log \
    --error-logfile /var/log/gunicorn/django-error.log


# === CONFIGURATION NGINX POUR DJANGO ===

# /etc/nginx/sites-available/django_app

upstream django_backend {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    listen 80;
    server_name django.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name django.example.com;
    
    # SSL
    ssl_certificate /etc/letsencrypt/live/django.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/django.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Headers sécurité
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    
    # Logs
    access_log /var/log/nginx/django-access.log;
    error_log /var/log/nginx/django-error.log;
    
    # Upload
    client_max_body_size 50M;
    
    # === FICHIERS STATIQUES (CSS, JS, Admin Django) ===
    location /static/ {
        alias /var/www/django_app/static/;
        expires 1M;
        add_header Cache-Control "public";
        access_log off;
    }
    
    # === MEDIA FILES (Uploads utilisateurs) ===
    location /media/ {
        alias /var/www/django_app/media/;
        expires 1d;
        add_header Cache-Control "public";
    }
    
    # === REVERSE PROXY DJANGO ===
    location / {
        proxy_pass http://django_backend;
        
        # 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;
        
        # Timeouts (augmenter si requêtes lentes)
        proxy_connect_timeout 75s;
        proxy_send_timeout 75s;
        proxy_read_timeout 75s;
    }
}


# === SYSTEMD SERVICE DJANGO ===

# /etc/systemd/system/django_app.service
[Unit]
Description=Gunicorn instance for Django App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/django_app
Environment="PATH=/var/www/django_app/venv/bin"
Environment="DJANGO_SECRET_KEY=your-secret-key-here"
Environment="DB_PASSWORD=your-db-password"

ExecStart=/var/www/django_app/venv/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:8000 \
    --timeout 60 \
    --access-logfile /var/log/gunicorn/django-access.log \
    --error-logfile /var/log/gunicorn/django-error.log \
    myproject.wsgi:application

Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

# Activer:
sudo systemctl daemon-reload
sudo systemctl enable django_app
sudo systemctl start django_app


# === STRUCTURE PROJET DJANGO ===

django_app/
├── venv/
├── myproject/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
├── myapp/
│   ├── models.py
│   ├── views.py
│   └── urls.py
├── static/                 # Fichiers dev
├── media/                  # Uploads
├── manage.py
├── requirements.txt
└── gunicorn_config.py


[OK] FASTAPI + UVICORN + NGINX

# FastAPI = Framework moderne, asynchrone
# Uvicorn = Serveur ASGI (pas WSGI!)

# === INSTALLATION ===

pip install fastapi uvicorn[standard]

# === APPLICATION FASTAPI ===

# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI(
    title="Mon API",
    description="API avec FastAPI",
    version="1.0.0"
)

class Item(BaseModel):
    id: int
    name: str
    price: float

# Base de données simulée
items_db = []

@app.get("/")
async def root():
    return {"message": "Welcome to FastAPI"}

@app.get("/api/items", response_model=List[Item])
async def get_items():
    return items_db

@app.post("/api/items", response_model=Item)
async def create_item(item: Item):
    items_db.append(item)
    return item

@app.get("/health")
async def health():
    return {"status": "healthy"}


# === DÉMARRER AVEC UVICORN ===

# Développement:
uvicorn main:app --reload

# Production:
uvicorn main:app \
    --host 0.0.0.0 \
    --port 8000 \
    --workers 4 \
    --log-level info

# Ou avec Gunicorn + Uvicorn workers (RECOMMANDÉ):
gunicorn main:app \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --timeout 60


# === CONFIGURATION NGINX POUR FASTAPI ===

# /etc/nginx/sites-available/fastapi_app

upstream fastapi_backend {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    # SSL
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # CORS headers (si nécessaire)
    add_header Access-Control-Allow-Origin "*" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    
    # Logs
    access_log /var/log/nginx/fastapi-access.log;
    error_log /var/log/nginx/fastapi-error.log;
    
    # === API DOCS (Swagger/ReDoc) ===
    # FastAPI génère docs automatiquement
    location /docs {
        proxy_pass http://fastapi_backend/docs;
        proxy_set_header Host $host;
    }
    
    location /redoc {
        proxy_pass http://fastapi_backend/redoc;
        proxy_set_header Host $host;
    }
    
    # === WEBSOCKET (si utilisé) ===
    location /ws {
        proxy_pass http://fastapi_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
    
    # === API ROUTES ===
    location / {
        proxy_pass http://fastapi_backend;
        
        # 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;
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}


# === SYSTEMD SERVICE FASTAPI ===

# /etc/systemd/system/fastapi_app.service
[Unit]
Description=FastAPI with Uvicorn
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/fastapi_app
Environment="PATH=/var/www/fastapi_app/venv/bin"

# Avec Gunicorn + Uvicorn workers (RECOMMANDÉ)
ExecStart=/var/www/fastapi_app/venv/bin/gunicorn \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 127.0.0.1:8000 \
    --timeout 60 \
    --access-logfile /var/log/fastapi/access.log \
    --error-logfile /var/log/fastapi/error.log \
    main:app

Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target


[OK] PLUSIEURS APPLICATIONS PYTHON SUR UN SERVEUR

# === PAR SOUS-DOMAINE ===

# Structure:
# flask-app.example.com -> Flask sur port 8001
# django-app.example.com -> Django sur port 8002
# fastapi-app.example.com -> FastAPI sur port 8003

# Configuration Nginx:

upstream flask_backend {
    server 127.0.0.1:8001;
}

upstream django_backend {
    server 127.0.0.1:8002;
}

upstream fastapi_backend {
    server 127.0.0.1:8003;
}

# Flask
server {
    listen 443 ssl http2;
    server_name flask-app.example.com;
    
    ssl_certificate /etc/letsencrypt/live/flask-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/flask-app.example.com/privkey.pem;
    
    location / {
        proxy_pass http://flask_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Django
server {
    listen 443 ssl http2;
    server_name django-app.example.com;
    
    ssl_certificate /etc/letsencrypt/live/django-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/django-app.example.com/privkey.pem;
    
    location /static/ {
        alias /var/www/django_app/static/;
    }
    
    location / {
        proxy_pass http://django_backend;
        proxy_set_header Host $host;
    }
}

# FastAPI
server {
    listen 443 ssl http2;
    server_name fastapi-app.example.com;
    
    ssl_certificate /etc/letsencrypt/live/fastapi-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/fastapi-app.example.com/privkey.pem;
    
    location / {
        proxy_pass http://fastapi_backend;
        proxy_set_header Host $host;
    }
}


# === PAR PATH (Chemin URL) ===

# Structure:
# example.com/ -> Site statique
# example.com/flask-app -> Flask
# example.com/django-app -> Django
# example.com/api -> FastAPI

server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    # Site principal (statique)
    root /var/www/html;
    index index.html;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # Flask app
    location /flask-app/ {
        proxy_pass http://127.0.0.1:8001/;
        # Note le / à la fin pour enlever /flask-app/ du path
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # Django app
    location /django-app/ {
        proxy_pass http://127.0.0.1:8002/;
        proxy_set_header Host $host;
    }
    
    # FastAPI
    location /api/ {
        proxy_pass http://127.0.0.1:8003/;
        proxy_set_header Host $host;
    }
}


[OK] OPTIMISATIONS SPÉCIFIQUES PYTHON

# === CACHE POUR API PYTHON ===

http {
    # Zone cache
    proxy_cache_path /var/cache/nginx/python_api
                     levels=1:2
                     keys_zone=python_api:50m
                     max_size=5g
                     inactive=1h;
    
    server {
        listen 443 ssl http2;
        server_name api.example.com;
        
        # API publique (cache court)
        location /api/public/ {
            proxy_pass http://python_backend;
            
            # Cache 5 minutes
            proxy_cache python_api;
            proxy_cache_valid 200 5m;
            proxy_cache_key "$request_uri";
            
            add_header X-Cache-Status $upstream_cache_status;
            proxy_set_header Host $host;
        }
        
        # API privée (pas de cache)
        location /api/private/ {
            proxy_pass http://python_backend;
            proxy_cache_bypass 1;
            proxy_set_header Host $host;
        }
    }
}


# === RATE LIMITING API PYTHON ===

http {
    # Rate limiting agressif pour API
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;
    limit_req_zone $binary_remote_addr zone=api_burst:10m rate=10r/s;
    
    server {
        listen 443 ssl http2;
        server_name api.example.com;
        
        # Endpoints normaux
        location /api/ {
            limit_req zone=api_burst burst=20 nodelay;
            proxy_pass http://python_backend;
        }
        
        # Endpoint de recherche (plus strict)
        location /api/search {
            limit_req zone=api_limit burst=5 nodelay;
            proxy_pass http://python_backend;
        }
    }
}


# === COMPRESSION SPÉCIFIQUE JSON ===

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        application/json
        application/javascript
        text/plain
        text/css
        text/xml
        application/xml;
    
    # Pour APIs JSON, compression cruciale!
    # JSON typiquement compresse 70-80%
}


# === TIMEOUT POUR TÂCHES LONGUES ===

# Si votre app Python fait traitement long

location /api/process {
    proxy_pass http://python_backend;
    
    # Timeouts longs
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    
    # Pour tâches TRÈS longues, considérer:
    # - Celery (tâches asynchrones)
    # - Streaming response
    # - WebSocket
}


[OK] DÉBOGAGE ET MONITORING

# === VÉRIFIER QUE GUNICORN TOURNE ===

# Vérifier processus:
ps aux | grep gunicorn

# Devrait montrer:
# - 1 processus master
# - X processus workers

# Vérifier port:
sudo netstat -tulpn | grep 8000

# Tester directement Gunicorn (bypass Nginx):
curl http://localhost:8000


# === LOGS GUNICORN ===

# Accès:
sudo tail -f /var/log/gunicorn/access.log

# Erreurs:
sudo tail -f /var/log/gunicorn/error.log

# Erreurs Python app:
sudo journalctl -u flask_app -f


# === LOGS NGINX ===

# Accès:
sudo tail -f /var/log/nginx/access.log

# Erreurs:
sudo tail -f /var/log/nginx/error.log


# === TESTER CONFIGURATION COMPLÈTE ===

# 1. Tester app Python directement:
curl http://localhost:8000

# 2. Tester via Nginx:
curl https://example.com

# 3. Comparer temps de réponse:
time curl http://localhost:8000
time curl https://example.com

# 4. Vérifier headers:
curl -I https://example.com

# Devrait voir headers Nginx (gzip, cache, etc.)


[OK] ERREURS COURANTES

# === ERREUR: 502 Bad Gateway ===

# Cause 1: Gunicorn pas démarré
sudo systemctl status flask_app
sudo systemctl start flask_app

# Cause 2: Mauvais port
# Vérifier nginx.conf:
proxy_pass http://127.0.0.1:8000;
# Vérifier Gunicorn écoute bien sur 8000

# Cause 3: Firewall bloque
sudo ufw allow 8000  # Temporairement pour tester


# === ERREUR: 404 sur fichiers statiques ===

# Cause: Chemin incorrect

# Django:
# 1. Vérifier STATIC_ROOT dans settings.py
STATIC_ROOT = '/var/www/django_app/static/'

# 2. Collecter fichiers statiques
python manage.py collectstatic --noinput

# 3. Vérifier permissions
sudo chown -R www-data:www-data /var/www/django_app/static/

# 4. Vérifier Nginx:
location /static/ {
    alias /var/www/django_app/static/;  # Doit correspondre à STATIC_ROOT
}


# === ERREUR: Application lente ===

# Cause: Pas assez de workers

# Règle: 2-4 × nombre de CPU cores
# Vérifier nombre CPUs:
nproc

# Si 2 CPUs -> 4-8 workers
gunicorn app:app --workers 6

# Ou avec config:
workers = multiprocessing.cpu_count() * 2 + 1


# === ERREUR: Connection refused ===

# Gunicorn écoute sur 127.0.0.1 mais Nginx tente autre IP

# Solution: Vérifier bind dans Gunicorn match proxy_pass dans Nginx
# Gunicorn:
--bind 127.0.0.1:8000

# Nginx:
proxy_pass http://127.0.0.1:8000;


# === ERREUR: Timeout ===

# Application Python prend trop de temps

# Solution 1: Augmenter timeout Gunicorn
gunicorn app:app --timeout 120

# Solution 2: Augmenter timeout Nginx
proxy_read_timeout 120s;

# Solution 3: Refactorer code Python (préférable!)
# - Utiliser cache Redis
# - Optimiser requêtes database
# - Utiliser Celery pour tâches longues


[OK] EXEMPLES AVANCÉS

# === DJANGO AVEC CELERY (Tâches asynchrones) ===

# Architecture:
# Nginx -> Gunicorn -> Django (requêtes web)
#                  -> Celery Worker (tâches async)
#                  -> Redis/RabbitMQ (broker)

# Installation:
pip install celery redis

# Django settings.py:
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

# Celery config (myproject/celery.py):
from celery import Celery
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

# Tâche exemple (myapp/tasks.py):
from celery import shared_task

@shared_task
def process_data(data):
    # Tâche longue qui tourne en arrière-plan
    import time
    time.sleep(10)
    return f"Processed: {data}"

# Vue Django qui utilise Celery:
from django.http import JsonResponse
from .tasks import process_data

def start_processing(request):
    # Lance tâche asynchrone
    task = process_data.delay("some data")
    return JsonResponse({'task_id': task.id})

def check_processing(request, task_id):
    # Vérifie statut tâche
    task = process_data.AsyncResult(task_id)
    return JsonResponse({
        'state': task.state,
        'result': task.result if task.ready() else None
    })


# Systemd service pour Celery Worker:
# /etc/systemd/system/celery_worker.service
[Unit]
Description=Celery Worker
After=network.target redis.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/django_app
Environment="PATH=/var/www/django_app/venv/bin"

ExecStart=/var/www/django_app/venv/bin/celery -A myproject worker \
    --loglevel=info \
    --concurrency=4 \
    --logfile=/var/log/celery/worker.log

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

# Nginx reste inchangé (proxy vers Gunicorn seulement)


# === FLASK AVEC WEBSOCKET (Flask-SocketIO) ===

# Installation:
pip install flask-socketio eventlet

# app.py:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('message')
def handle_message(data):
    print(f'Received: {data}')
    emit('response', {'data': 'Message reçu!'})

@socketio.on('connect')
def handle_connect():
    print('Client connecté')

if __name__ == '__main__':
    socketio.run(app, host='127.0.0.1', port=8000)

# Démarrer avec Eventlet:
gunicorn --worker-class eventlet -w 1 app:app --bind 127.0.0.1:8000

# Nginx config WebSocket:
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen 443 ssl http2;
    server_name chat.example.com;
    
    ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
    
    location /socket.io/ {
        proxy_pass http://127.0.0.1:8000/socket.io/;
        
        # WebSocket headers
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        
        # Timeouts longs
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
    }
}


# === FASTAPI AVEC STREAMING RESPONSE ===

# Pour envoyer données progressivement (téléchargement fichier, etc.)

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio

app = FastAPI()

async def generate_data():
    for i in range(100):
        yield f"data: {i}\n\n"
        await asyncio.sleep(0.1)

@app.get("/stream")
async def stream():
    return StreamingResponse(
        generate_data(),
        media_type="text/event-stream"
    )

# Nginx config pour streaming:
location /stream {
    proxy_pass http://fastapi_backend;
    
    # Désactiver buffering pour streaming
    proxy_buffering off;
    proxy_cache off;
    
    # Headers
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding on;
    
    proxy_set_header Host $host;
}


# === MULTI-TENANCY (Plusieurs clients/tenants) ===

# Routage basé sur sous-domaine

# Structure:
# client1.example.com -> Instance Python pour client1
# client2.example.com -> Instance Python pour client2
# client3.example.com -> Instance Python pour client3

upstream client1_backend {
    server 127.0.0.1:8001;
}

upstream client2_backend {
    server 127.0.0.1:8002;
}

upstream client3_backend {
    server 127.0.0.1:8003;
}

# Template serveur (répéter pour chaque client)
server {
    listen 443 ssl http2;
    server_name client1.example.com;
    
    ssl_certificate /etc/letsencrypt/live/client1.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/client1.example.com/privkey.pem;
    
    location / {
        proxy_pass http://client1_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Ou dynamique avec map:
map $host $backend {
    client1.example.com 127.0.0.1:8001;
    client2.example.com 127.0.0.1:8002;
    client3.example.com 127.0.0.1:8003;
    default 127.0.0.1:8000;
}

server {
    listen 443 ssl http2;
    server_name *.example.com;
    
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    location / {
        proxy_pass http://$backend;
        proxy_set_header Host $host;
    }
}


# === API VERSIONING ===

# Structure:
# /api/v1/ -> Version 1 (port 8001)
# /api/v2/ -> Version 2 (port 8002)

upstream api_v1 {
    server 127.0.0.1:8001;
}

upstream api_v2 {
    server 127.0.0.1:8002;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    
    # API v1
    location /api/v1/ {
        proxy_pass http://api_v1/;
        proxy_set_header Host $host;
    }
    
    # API v2
    location /api/v2/ {
        proxy_pass http://api_v2/;
        proxy_set_header Host $host;
    }
    
    # Redirection racine vers dernière version
    location = /api/ {
        return 302 /api/v2/;
    }
}


[OK] MONITORING ET HEALTHCHECKS

# === ENDPOINT HEALTH CHECK ===

# Flask:
@app.route('/health')
def health():
    # Vérifier connexion DB, Redis, etc.
    try:
        db.session.execute('SELECT 1')
        redis_client.ping()
        return {'status': 'healthy'}, 200
    except Exception as e:
        return {'status': 'unhealthy', 'error': str(e)}, 503

# Django:
from django.http import JsonResponse
from django.db import connection

def health(request):
    try:
        connection.ensure_connection()
        return JsonResponse({'status': 'healthy'})
    except Exception as e:
        return JsonResponse({'status': 'unhealthy', 'error': str(e)}, status=503)

# FastAPI:
@app.get("/health")
async def health():
    return {"status": "healthy"}

# Nginx config:
location /health {
    proxy_pass http://python_backend/health;
    access_log off;  # Ne pas logger health checks
}

# Test automatique:
# Cron job qui vérifie toutes les 5 minutes:
*/5 * * * * curl -f http://localhost/health || systemctl restart flask_app


# === PROMETHEUS METRICS ===

# Flask avec prometheus_client:
pip install prometheus-client

from prometheus_client import Counter, Histogram, generate_latest

# Métriques
REQUEST_COUNT = Counter('app_requests_total', 'Total requests')
REQUEST_DURATION = Histogram('app_request_duration_seconds', 'Request duration')

@app.before_request
def before_request():
    request.start_time = time.time()

@app.after_request
def after_request(response):
    REQUEST_COUNT.inc()
    duration = time.time() - request.start_time
    REQUEST_DURATION.observe(duration)
    return response

@app.route('/metrics')
def metrics():
    return generate_latest()

# Nginx:
location /metrics {
    proxy_pass http://python_backend/metrics;
    allow 127.0.0.1;  # Seulement depuis localhost
    deny all;
}


[OK] SÉCURITÉ SPÉCIFIQUE PYTHON

# === PROTECTION CSRF DJANGO ===

# Django a protection CSRF intégrée
# Nginx doit passer cookies correctement:

location / {
    proxy_pass http://django_backend;
    
    # Ne PAS filtrer cookies
    proxy_set_header Cookie $http_cookie;
    
    # Headers CSRF
    proxy_set_header X-CSRFToken $http_x_csrftoken;
}


# === CORS POUR API ===

# Si API Python utilisée par frontend JavaScript

# Option 1: Dans Nginx
server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    # CORS headers
    add_header Access-Control-Allow-Origin "https://frontend.example.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always;
    add_header Access-Control-Allow-Credentials "true" always;
    
    # Preflight requests
    if ($request_method = OPTIONS) {
        return 204;
    }
    
    location / {
        proxy_pass http://python_backend;
    }
}

# Option 2: Dans Python (Flask-CORS)
pip install flask-cors

from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins=["https://frontend.example.com"])


# === AUTHENTIFICATION JWT ===

# Valider JWT dans Nginx avant d'atteindre Python

# Nécessite module lua ou auth_request
# Exemple avec auth_request:

location /api/protected/ {
    # Vérifier JWT d'abord
    auth_request /auth;
    
    proxy_pass http://python_backend;
}

location = /auth {
    internal;
    proxy_pass http://python_backend/validate-token;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}


# === RATE LIMITING PAR USER ===

# Limiter par token/user au lieu d'IP

# Dans Python, ajouter header avec user ID
response.headers['X-User-ID'] = current_user.id

# Dans Nginx:
map $http_x_user_id $limit_key {
    default $http_x_user_id;
    '' $binary_remote_addr;  # Fallback sur IP si pas de user
}

limit_req_zone $limit_key zone=per_user:10m rate=100r/m;

location /api/ {
    limit_req zone=per_user burst=20 nodelay;
    proxy_pass http://python_backend;
}


[OK] DÉPLOIEMENT AUTOMATISÉ

# === SCRIPT DÉPLOIEMENT COMPLET ===

#!/bin/bash
# deploy.sh - Script déploiement application Python

set -e  # Arrêter si erreur

APP_NAME="flask_app"
APP_DIR="/var/www/flask_app"
VENV_DIR="$APP_DIR/venv"
GIT_REPO="https://github.com/user/flask_app.git"

echo "=== Déploiement $APP_NAME ==="

# 1. Pull dernières modifications
cd $APP_DIR
git pull origin main

# 2. Activer virtualenv
source $VENV_DIR/bin/activate

# 3. Installer/mettre à jour dépendances
pip install -r requirements.txt --upgrade

# 4. Django: Migrations et collectstatic
if [ -f "manage.py" ]; then
    python manage.py migrate --noinput
    python manage.py collectstatic --noinput
fi

# 5. Tests
pytest tests/ || {
    echo "Tests échoués! Rollback..."
    git reset --hard HEAD~1
    exit 1
}

# 6. Recharger Gunicorn
sudo systemctl restart $APP_NAME

# 7. Vérifier santé
sleep 5
curl -f http://localhost:8000/health || {
    echo "Health check échoué! Rollback..."
    sudo systemctl restart $APP_NAME
    exit 1
}

# 8. Purger cache Nginx (si configuré)
sudo rm -rf /var/cache/nginx/python_api/*
sudo systemctl reload nginx

echo "=== Déploiement réussi! ==="


# === AVEC DOCKER COMPOSE ===

# docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/ssl:ro
      - static_volume:/var/www/static:ro
    depends_on:
      - flask_app
    restart: unless-stopped

  flask_app:
    build: .
    command: gunicorn app:app --bind 0.0.0.0:8000 --workers 4
    volumes:
      - ./app:/app
      - static_volume:/app/static
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - db
      - redis
    restart: unless-stopped

  db:
    image: postgres:14-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  postgres_data:
  static_volume:

# Déployer:
docker-compose up -d --build


# === AVEC ANSIBLE ===

# playbook.yml
---
- name: Déployer application Flask
  hosts: webserver
  become: yes
  
  vars:
    app_name: flask_app
    app_dir: /var/www/flask_app
    git_repo: https://github.com/user/flask_app.git
  
  tasks:
    - name: Installer dépendances système
      apt:
        name:
          - python3
          - python3-pip
          - python3-venv
          - nginx
        state: present
        update_cache: yes
    
    - name: Cloner repository
      git:
        repo: "{{ git_repo }}"
        dest: "{{ app_dir }}"
        version: main
    
    - name: Créer virtualenv
      pip:
        requirements: "{{ app_dir }}/requirements.txt"
        virtualenv: "{{ app_dir }}/venv"
        virtualenv_python: python3
    
    - name: Copier config Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/sites-available/{{ app_name }}
    
    - name: Activer site Nginx
      file:
        src: /etc/nginx/sites-available/{{ app_name }}
        dest: /etc/nginx/sites-enabled/{{ app_name }}
        state: link
    
    - name: Copier service systemd
      template:
        src: app.service.j2
        dest: /etc/systemd/system/{{ app_name }}.service
    
    - name: Démarrer services
      systemd:
        name: "{{ item }}"
        state: restarted
        enabled: yes
        daemon_reload: yes
      loop:
        - "{{ app_name }}"
        - nginx

# Déployer:
ansible-playbook -i inventory playbook.yml


[OK] CHECKLIST PRODUCTION PYTHON + NGINX

[ ] === APPLICATION PYTHON ===
[ ] DEBUG = False (Django)
[ ] ALLOWED_HOSTS configuré (Django)
[ ] SECRET_KEY dans variable environnement
[ ] Base de données production configurée
[ ] Migrations appliquées (Django)
[ ] Tests passent
[ ] Requirements.txt à jour
[ ] Logs configurés

[ ] === GUNICORN ===
[ ] Workers = 2-4 × CPU cores
[ ] Timeout approprié pour votre app
[ ] Logs configurés (access + error)
[ ] Service systemd créé
[ ] Auto-restart configuré
[ ] Écoute sur 127.0.0.1 (pas 0.0.0.0 si derrière Nginx)

[ ] === NGINX ===
[ ] Configuration testée (nginx -t)
[ ] HTTPS configuré (Let's Encrypt)
[ ] Redirection HTTP -> HTTPS
[ ] Headers sécurité
[ ] Fichiers statiques servis par Nginx
[ ] Gzip activé
[ ] Cache configuré si applicable
[ ] Rate limiting sur API
[ ] Logs rotatés

[ ] === SÉCURITÉ ===
[ ] Firewall configuré (UFW)
[ ] SSH avec clés (pas password)
[ ] Fail2ban installé
[ ] Mises à jour automatiques système
[ ] Backup réguliers DB
[ ] Monitoring actif

[ ] === PERFORMANCE ===
[ ] Cache Redis/Memcached si nécessaire
[ ] Connection pooling DB
[ ] Celery pour tâches longues
[ ] CDN pour fichiers statiques
[ ] Database optimisée (index, queries)


[OK] RESSOURCES PYTHON + NGINX

# === DOCUMENTATION ===
# Gunicorn: https://docs.gunicorn.org/
# uWSGI: https://uwsgi-docs.readthedocs.io/
# Flask deployment: https://flask.palletsprojects.com/en/latest/deploying/
# Django deployment: https://docs.djangoproject.com/en/stable/howto/deployment/
# FastAPI deployment: https://fastapi.tiangolo.com/deployment/

# === OUTILS ===
# Supervisor: Process manager alternatif
# systemd: Process manager moderne (recommandé)
# Docker: Containerisation
# Ansible: Automatisation déploiement

# === MONITORING ===
# Sentry: Error tracking Python
# New Relic: APM complet
# Datadog: Monitoring infrastructure
# Prometheus + Grafana: Open source


[OK] COMMANDES ESSENTIELLES MÉMO

# Gunicorn:
gunicorn app:app --bind 127.0.0.1:8000 --workers 4

# Systemd:
sudo systemctl restart flask_app
sudo systemctl status flask_app
sudo journalctl -u flask_app -f

# Nginx:
sudo nginx -t
sudo systemctl reload nginx

# Django:
python manage.py migrate
python manage.py collectstatic --noinput

# Logs:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/gunicorn/error.log

# Test:
curl http://localhost:8000
curl https://example.com

# Debug:
ps aux | grep gunicorn
netstat -tulpn | grep 8000


# === FIN DU GUIDE NGINX POUR PYTHON ===
# Bonne chance avec votre déploiement Python! [PYTHON][RAPIDE]