Removed SECURE_CONTENT_TYPE_NOSNIFF and SECURE_BROWSER_XSS_FILTER
from Django settings to prevent duplicate headers. These headers are
now exclusively managed in Nginx Proxy Manager's Advanced config.
This fixes Mozilla Observatory error: "X-Content-Type-Options header
cannot be recognized" which was caused by the header being sent twice
(once from Django, once from NPM).
Security headers now managed in NPM:
- Content-Security-Policy
- X-Content-Type-Options
- X-XSS-Protection
- Referrer-Policy
- Permissions-Policy
X-Frame-Options kept in Django for defense-in-depth (doesn't conflict).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Since Nginx Proxy Manager is handling Content Security Policy headers
at the reverse proxy level, removed django-csp from Django to avoid
duplication and simplify configuration.
Changes:
- Removed django-csp from requirements.txt
- Removed CSPMiddleware from middleware stack
- Removed CSP_* settings from selfhosted.py
- Added comment noting CSP is configured in NPM
CSP is now exclusively managed in NPM's Advanced configuration with:
- default-src 'self'
- script-src/style-src 'self' 'unsafe-inline' (for Django admin)
- img-src 'self' data: https:
- frame-ancestors 'none'
- And other security directives
This keeps configuration in one place (NPM) and eliminates
dependency on django-csp package.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements CSP to prevent XSS attacks and complete Mozilla Observatory
security requirements.
Changes:
- Added django-csp>=3.8 to requirements.txt
- Added CSPMiddleware to middleware stack
- Configured CSP directives in selfhosted.py:
- default-src 'self' (only load resources from same origin)
- script-src/style-src allow 'unsafe-inline' (needed for Django admin)
- img-src allows https: and data: URIs
- frame-ancestors 'none' (prevent clickjacking)
- form-action 'self' (prevent form hijacking)
This policy balances security with Django admin functionality.
After deployment, Mozilla Observatory should show all green checks.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added SILENCED_SYSTEM_CHECKS to suppress warnings for:
- security.W004: HSTS (handled by NPM with HSTS Enabled)
- security.W008: SSL redirect (handled by NPM with Force SSL)
These warnings are intentionally suppressed because the security
features are properly configured at the reverse proxy level.
After redeploying, 'manage.py check --deploy' will show:
"System check identified no issues (0 silenced)."
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Since Nginx Proxy Manager handles SSL termination, Force SSL, and HSTS:
- Set SECURE_HSTS_SECONDS = 0 (NPM sends HSTS headers)
- Added SECURE_PROXY_SSL_HEADER to trust X-Forwarded-Proto from NPM
- Added SESSION_COOKIE_HTTPONLY for additional session security
- Documented NPM configuration: Force SSL = On, HSTS Enabled = On
This prevents duplicate HSTS headers and ensures Django correctly
detects HTTPS connections behind the reverse proxy.
Cookie security (SESSION/CSRF_COOKIE_SECURE) remains enabled as these
are application-level settings independent of the reverse proxy.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Django requires CSRF_TRUSTED_ORIGINS to be set for POST requests
(including login) when using HTTPS or non-standard ports. Without
this setting, login attempts fail with "CSRF verification failed".
The setting is now configurable via CSRF_TRUSTED_ORIGINS environment
variable, similar to CORS_ALLOWED_ORIGINS.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add Dockerfile for production (multi-stage build)
- Add Dockerfile.dev for development with hot reload
- Add docker-compose.yml with 5 services (web, mariadb, redis, celery-worker, celery-beat)
- Add docker-compose.dev.yml for development overrides
- Add .dockerignore for optimized builds
- Add docker/entrypoint.sh startup script
- Add .env.docker.example template
- Add Makefile for common commands
- Add deploy.sh for one-command deployment
- Update config/settings/selfhosted.py to support MariaDB via DATABASE_URL
- Add mysqlclient to requirements.txt for MariaDB support
- Update .gitignore to exclude .env.docker
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Security improvements:
- selfhosted.py: Require SECRET_KEY environment variable (raises ValueError if not set)
- selfhosted.py: Validate SECRET_KEY length (minimum 50 characters)
- selfhosted.py: Warn if DEBUG=True in self-hosted mode
- development.py: Auto-generate random SECRET_KEY on each startup if not provided
- development.py: Remove production domain from ALLOWED_HOSTS
- development.py: Make CSRF_TRUSTED_ORIGINS environment-only
This prevents weak/default SECRET_KEYs from being used in production.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Features:
- Django-based REST API with web interface
- Task management with tags, priorities, and due dates
- Time tracking with start/stop timers
- Subtasks support
- Task filtering (all, today, upcoming, overdue, completed)
- Tag-based organization with color coding
- Sorting by due date and priority
- Auto-assign tags when filtering
- Responsive 3-pane layout (sidebar, task list, detail panel)
- Task sharing between users
- Mobile-responsive design with dark mode support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>