QUA-001, volet dialecte.
`postgresql://` ne veut pas dire "le pilote installe" : SQLAlchemy y lit
psycopg2 et importe ce module a la creation du moteur. requirements.txt
epingle psycopg 3 (`psycopg[binary]`) et pas psycopg2. Une installation
propre demarree sur cette URL leve donc
ModuleNotFoundError: No module named 'psycopg2'
avant la premiere requete. Verifie dans le .venv du depot, et c est
exactement la forme que Render distribue -- celle que docs/deployment.md et
docs/database-restore.md donnaient en exemple.
normalise_database_url() nomme le pilote quand l URL n en nomme pas.
`postgres://` (alias hérite, abandonne par SQLAlchemy en 1.4) est traite de
meme. Une URL qui nomme deja son pilote est laissee telle quelle, y compris
`postgresql+psycopg2://` : un environnement qui a psycopg2 garde le choix.
La normalisation a lieu apres l application de la configuration passee en
argument, pour couvrir aussi les appels de test. backup.py n avait pas
besoin d etre touche : il retirait deja le suffixe +pilote.
Documentation alignee sur les trois fichiers qui donnaient l exemple, dont
docs/deployment.md qui proposait sqlite:/// pour DATABASE_URL alors que
create_app refuse de demarrer sans PostgreSQL.
Reste de QUA-001, dit franchement
- les trois paquets parasites (dotenv, login, discord) ne sont plus dans
requirements.txt : deja retires. psycopg est deja epingle.
- la consolidation vers des groupes de dependances n est PAS faite. Le
deploiement est un miroir de fichiers lftp sans etape de construction ;
les groupes PEP 735 demandent pip >= 25.1 sur une machine dont on ne
peut pas verifier la version d ici. A revoir avec OPS-011.
14 tests, dont trois qui prouvent que l echec est reel et non theorique.
Co-Authored-By: Claude Opus 5 <[email protected]>
4.7 KiB
4.7 KiB
Team Tryouts - Production Deployment Guide (Windows)
This document outlines the secure production deployment for the Team Tryouts Flask application on Windows with Nginx reverse proxy.
Architecture Overview
Internet → Nginx (HTTPS:443) → Waitress (127.0.0.1:5000) → Flask App
- Nginx: TLS termination, static file serving, rate limiting, security headers
- Waitress: Production WSGI server with multiple worker threads
- Flask: Application logic (never exposed directly to the internet)
Prerequisites
- Python 3.12+ installed
- Nginx for Windows downloaded from nginx.org
- SSL Certificate (Let's Encrypt via certbot or commercial provider)
- Windows Firewall configured properly
Step 1: Install Dependencies
# Install Python packages
pip install -r requirements.txt
# Create required directories
mkdir logs
mkdir backups
Step 2: Configure Environment Variables
Create a .env file in the project root:
# Security (REQUIRED - generate with: python -c "import secrets; print(secrets.token_hex(32))")
SECRET_KEY=<your-generated-64-char-hex-key>
# Database — PostgreSQL. create_app() refuses to start without this.
# Either form works; the driver is named for you if you leave it out.
DATABASE_URL=postgresql://user:password@host:5432/dbname
# Security settings
SESSION_COOKIE_SECURE=true
FORCE_HTTPS=true
FLASK_DEBUG=false
# CORS (set to your actual domain in production)
CORS_ALLOWED_ORIGINS=https://yourdomain.com
# Discord bot (optional)
DISCORD_BOT_TOKEN=
DISCORD_WEBHOOK_URL=
# Backup settings
BACKUP_DIR=./backups
BACKUP_RETENTION_DAYS=30
Important: Never commit .env to version control.
Step 3: Configure Nginx
- Copy
nginx.confto your Nginx installation directory (e.g.,C:\nginx\conf\) - Place SSL certificate files:
C:\nginx\certs\fullchain.pemC:\nginx\certs\privkey.pem
- Start Nginx:
C:\nginx\nginx.exe
Obtaining SSL Certificates
Using Let's Encrypt with certbot (recommended):
# Using certbot on Windows
certbot certonly --standalone -d yourdomain.com
Or use your hosting provider's SSL certificate.
Step 4: Start the Application
# Production start
python wsgi.py
# Or with custom port/threads
$env:PORT=5000
$env:WAITRESS_THREADS=5
python wsgi.py
Step 5: Configure Windows Firewall
# Allow only necessary ports
New-NetFirewallRule -DisplayName "Nginx HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow
New-NetFirewallRule -DisplayName "Nginx HTTP Redirect" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow
# Block direct access to Waitress port (5000) from outside
New-NetFirewallRule -DisplayName "Block Waitress External" -Direction Inbound -Protocol TCP -LocalPort 5000 -Action Block
Step 6: Set Up Automated Backups
Create a scheduled task for daily backups:
# Run backup script daily at 2:00 AM
$Action = New-ScheduledTaskAction -Execute "python" -Argument "backup.py" -WorkingDirectory "C:\path\to\team-tryouts"
$Trigger = New-ScheduledTaskTrigger -Daily -At 2:00AM
Register-ScheduledTask -TaskName "TeamTryoutsBackup" -Action $Action -Trigger $Trigger
Step 7: Run Security Validation
Before going live:
# Run the security scanner
python security_scan.py --url https://yourdomain.com
All checks must pass before deployment.
Security Checklist
.envis not committed to repositorySECRET_KEYis strong (64+ hex characters, randomly generated)FLASK_DEBUGis set tofalse- Nginx is running with HTTPS (port 443)
- HTTP (port 80) redirects to HTTPS
- TLS 1.2+ configured (TLS 1.0/1.1 disabled)
- HSTS header is present (
max-age=31536000; includeSubDomains; preload) - CSP header is configured with no
unsafe-eval server_tokensisoffin Nginx- File uploads restricted to PDF only
- File uploads limited to 16MB
- Database backups scheduled daily
- Firewall rules applied (only 80/443 open)
- Application is not running as administrator
- Logs directory exists and is writable
- Health check endpoint returns 200
Monitoring
- Application logs:
./logs/app.log - Error logs:
./logs/errors.log - Auth logs:
./logs/auth.log - Nginx access logs:
C:\nginx\logs\access.log - Nginx error logs:
C:\nginx\logs\error.log
Monitor these logs regularly for suspicious activity.
Maintenance
- Run
pip-auditweekly to check for vulnerabilities - Run
python security_scan.pyafter any configuration changes - Test backup restoration quarterly
- Review and rotate
SECRET_KEYif compromised - Keep Python and system packages updated