Před nasazením do produkce MUSÍŠ projít celý tento checklist!
# Check git history for .env file
git log --all --full-history --source --patch -- .env
# Search for any committed encryption keys
git log --all --source --patch -S "FERNET_KEY_PRIMARY"
# Search for any committed secret keys
git log --all --source --patch -S "SECRET_KEY"✅ Akce: Pokud najdeš .env nebo klíče v historii, jsou COMPROMISED a musíš:
- Vygenerovat NOVÉ klíče
- Re-encryptovat všechna data s novým FERNET_KEY
- Vyčistit git historii:
git filter-repo --path .env --invert-paths
# Check .env is in .gitignore
grep "^\.env$" .gitignore✅ Očekávaný výstup: .env (pokud není, přidej ho!)
Production server MUSÍ mít tyto env variables:
# CRITICAL - Security Keys
export SECRET_KEY="<50+ random characters>"
export FERNET_KEY_PRIMARY="<44-byte base64 key>"
# Hosting
export ALLOWED_HOSTS="yourdomain.com,www.yourdomain.com"
# Database
export DB_ENGINE=django.db.backends.postgresql
export DB_NAME=quietpage_prod
export DB_USER=quietpage
export DB_PASSWORD=<strong-password>
export DB_HOST=localhost
export DB_PORT=5432
# Email
export EMAIL_HOST=smtp.example.com
export EMAIL_PORT=587
export EMAIL_USE_TLS=True
export EMAIL_HOST_USER=noreply@yourdomain.com
export EMAIL_HOST_PASSWORD=<email-password>
export DEFAULT_FROM_EMAIL=noreply@yourdomain.com
# Django Settings
export DJANGO_SETTINGS_MODULE=config.settings.productionpython -c "import secrets; print(secrets.token_urlsafe(50))"✅ Požadavky:
- Minimálně 50 znaků
- Náhodný, kryptograficky bezpečný
- NIKDY nepoužívej default:
django-insecure-please-change-this-in-env-file
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"✅ Požadavky:
- Přesně 44 bytů (base64-encoded 32-byte key)
- Náhodný, kryptograficky bezpečný
- Uložený v .env, NIKDY v kódu
export DJANGO_SETTINGS_MODULE=config.settings.production
python manage.py check✅ Očekávaný výstup: System check identified no issues
❌ Pokud vidíš ImproperlyConfigured: Oprav env variables podle chybové zprávy.
-- Create dedicated user (NOT superuser)
CREATE USER quietpage WITH PASSWORD 'strong-password';
-- Grant minimal permissions
GRANT CONNECT ON DATABASE quietpage_prod TO quietpage;
GRANT USAGE ON SCHEMA public TO quietpage;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO quietpage;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO quietpage;
-- Revoke dangerous permissions
REVOKE CREATE ON SCHEMA public FROM quietpage;✅ Checklist:
- Database uses SSL/TLS encryption
- Database password je strong (20+ random chars)
- Database je accessible pouze z app serveru (firewall rules)
- Database má regular automated backups
export DJANGO_SETTINGS_MODULE=config.settings.production
python manage.py check --deploy✅ Očekávaný výstup: Žádné CRITICAL nebo ERROR warnings.
Zkontroluj config/settings/production.py:
# Must be False
DEBUG = False # ✅
# Must be set
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com'] # ✅
# HTTPS settings
# SECURE_SSL_REDIRECT must be True when Django terminates SSL.
# May be set to False ONLY when Nginx reverse proxy performs SSL termination
# (typical in containerized deployments with Nginx handling HTTPS).
SECURE_SSL_REDIRECT = True # ✅ (or False if Nginx terminates SSL)
SESSION_COOKIE_SECURE = True # ✅
CSRF_COOKIE_SECURE = True # ✅
SESSION_COOKIE_HTTPONLY = True # ✅
SESSION_COOKIE_SAMESITE = 'Lax' # ✅
CSRF_COOKIE_SAMESITE = 'Lax' # ✅
# HSTS
SECURE_HSTS_SECONDS = 31536000 # ✅
SECURE_HSTS_INCLUDE_SUBDOMAINS = True # ✅
SECURE_HSTS_PRELOAD = True # ✅
# Security headers
SECURE_BROWSER_XSS_FILTER = True # ✅
SECURE_CONTENT_TYPE_NOSNIFF = True # ✅
X_FRAME_OPTIONS = 'DENY' # ✅Rotate FERNET_KEY_PRIMARY pokud:
- ❌ Byl commitnutý do git (i když jen v historii)
- ❌ Byl leaked do logů
- ❌ Máš podezření na kompromis
- ❌ Používáš default/test key
# 1. Backup database
pg_dump quietpage_prod > backup_before_rotation.sql
# 2. Generate NEW key
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# 3. Run rotation command (from plan - Phase 4.1)
# NOTE: Tento command ještě neexistuje, implementuj podle plánu!
# python manage.py rotate_encryption_key --new-key=<NEW_KEY>
# 4. Update .env with new key
# 5. Restart application
# 6. Verify entries are readableexport DJANGO_SETTINGS_MODULE=config.settings.production
python manage.py collectstatic --noinput✅ Checklist:
- Media files (
media/avatars/) NEJSOU v git repository - Media files mají správná oprávnění (readable by web server)
- Media uploads jsou size-limited (max 5MB per avatar)
- Media folder má regular backups
python manage.py shellfrom django.core.mail import send_mail
send_mail(
'QuietPage Test Email',
'Pokud vidíš tento email, konfigurace je OK!',
'noreply@yourdomain.com',
['your@email.com'],
fail_silently=False,
)✅ Očekávaný výstup: Email delivered bez errors.
pip list | grep django-axes✅ Očekávaný výstup: django-axes==8.1.0 (nebo novější)
- Otevři
/accounts/login/v browseru - Zadej špatné heslo 5x po sobě
-
- pokus by měl vrátit 403 Forbidden
✅ Očekávaný výsledek: Locked out po 5 failed attempts.
# Test SSL certificate validity
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null✅ Checklist:
- Certificate je platný (not expired)
- Certificate je pro správnou doménu
- Certificate chain je complete
- Using TLS 1.2+ (ne SSL 3.0 nebo TLS 1.0)
DŮLEŽITÉ: HSTS musí být nakonfigurováno přes environment variable HSTS_HEADER v .env souboru.
Nastav pouze po získání validních SSL certifikátů:
# V .env souboru:
HSTS_HEADER=add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;Pak otestuj:
curl -I https://yourdomain.com | grep -i strict✅ Očekávaný výstup: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
export DJANGO_SETTINGS_MODULE=config.settings.production
python manage.py migrate✅ Očekávaný výstup: All migrations applied successfully.
python manage.py createsuperuser- Použij strong password (20+ chars, mixed case, numbers, symbols)
- NIKDY nepoužívej default
admin/admin123z dev environment! - Ulož credentials do password manageru
# Application code should be read-only for web server user
chown -R yourusername:www-data /path/to/QuietPage
chmod -R 755 /path/to/QuietPage
# Sensitive files
chmod 600 .env
chmod 600 config/settings/production.py# Media files writable by web server
chown -R www-data:www-data /path/to/QuietPage/media
chmod -R 755 /path/to/QuietPage/media
# Static files readable by web server
chmod -R 755 /path/to/QuietPage/staticfiles# Check logs directory exists
ls -la /path/to/QuietPage/logs/
# Test log rotation works
python manage.py check
tail -f /path/to/QuietPage/logs/django.log✅ Checklist:
- Logs jsou writable by Django
- Log rotation je configured (max 10MB per file)
- Security events jsou logged (viz
apps/accounts/middleware.py) - Logs NEOBSAHUJÍ sensitive data (passwords, encryption keys)
# Automated daily backups
0 2 * * * pg_dump quietpage_prod > /backups/quietpage_$(date +\%Y\%m\%d).sql✅ Checklist:
- Daily automated backups
- Backups jsou stored off-server
- Backups jsou encrypted
- Tested restore procedure (alespoň jednou!)
# Backup avatars weekly
0 3 * * 0 tar -czf /backups/media_$(date +\%Y\%m\%d).tar.gz /path/to/QuietPage/media/Projdi tenhle checklist těsně před launchemm:
- ✅ Všechny env variables jsou set v production
- ✅ Git history NEOBSAHUJE secrets
- ✅ SECRET_KEY je strong a unique
- ✅ FERNET_KEY_PRIMARY je strong a unique
- ✅ ALLOWED_HOSTS je správně set
- ✅ DEBUG = False v production
- ✅ SSL certificate je platný
- ✅ HSTS headers jsou enabled
- ✅ Database backups jsou automated
- ✅ Email sending funguje
- ✅ Rate limiting je functional
- ✅ All migrations applied
- ✅ Superuser account created (strong password!)
- ✅
python manage.py check --deployprošel bez errors - ✅ Static files collected
- ✅ Media folder permissions jsou correct
- ✅ Logs jsou writable a rotated
První 24 hodin po launch:
-
Monitor logs každou hodinu:
tail -f /path/to/QuietPage/logs/django.log tail -f /path/to/QuietPage/logs/security.log
-
Check for errors:
grep ERROR /path/to/QuietPage/logs/django.log
-
Monitor failed login attempts:
grep "axes" /path/to/QuietPage/logs/security.log -
Test critical paths:
- ✅ User registration works
- ✅ Email verification works
- ✅ Entry creation works
- ✅ Entry encryption/decryption works
- ✅ Password reset works
Pokud něco selže:
-
Encryption key compromised:
- Immediately rotate FERNET_KEY_PRIMARY (viz sekce 5)
- Notify all users to change passwords
-
Database compromised:
- Restore from latest backup
- Rotate ALL secrets
- Force password reset for all users
-
500 errors po deployment:
- Check logs:
tail -f logs/django.log - Verify env variables:
python manage.py check --deploy - Rollback to previous version if critical
- Check logs:
GDPR Considerations:
- User data deletion works (cascade deletes)
- Privacy policy je updated a dostupná
- Cookie consent je implemented (pokud používáš analytics)
- Users můžou exportovat svá data
Poslední update: 2025-12-28 Autor: Tomas Mach Status: Pre-launch security hardening complete ✅