# Paperless CSRF Fix Summary **Date:** 2025-08-31 **Issue:** CSRF verification failed (403 Forbidden) when accessing Paperless through DuckDNS **Status:** ✅ RESOLVED --- ## 🔧 **Problem Description** When accessing `https://paperless.pressmess.duckdns.org`, users were getting a **403 Forbidden** error with the message: ``` CSRF verification failed. Request aborted. More information is available with DEBUG=True. ``` This is a common issue when running Django applications (like Paperless) behind a reverse proxy without proper CSRF configuration. --- ## 🎯 **Root Cause** The CSRF verification error occurred because: 1. **Missing CSRF Configuration**: Paperless wasn't configured to trust requests from the DuckDNS domain 2. **Incomplete Reverse Proxy Headers**: Caddy wasn't sending all necessary headers for CSRF validation 3. **Incorrect URL Configuration**: Paperless didn't know its correct public URL --- ## ✅ **Solution Applied** ### **1. Updated Paperless Configuration** (`paperless_fix_compose.yml`) Added the following environment variables to the Paperless webserver service: ```yaml environment: # CSRF and reverse proxy configuration for Caddy PAPERLESS_URL: https://paperless.pressmess.duckdns.org PAPERLESS_CSRF_TRUSTED_ORIGINS: https://paperless.pressmess.duckdns.org PAPERLESS_ALLOWED_HOSTS: paperless.pressmess.duckdns.org # Security settings for reverse proxy PAPERLESS_USE_X_FORWARDED_HOST: true PAPERLESS_USE_X_FORWARDED_PORT: true PAPERLESS_SECURE_SSL_REDIRECT: true # Additional security headers PAPERLESS_SECURE_BROWSER_XSS_FILTER: true PAPERLESS_SECURE_CONTENT_TYPE_NOSNIFF: true PAPERLESS_SECURE_HSTS_INCLUDE_SUBDOMAINS: true PAPERLESS_SECURE_HSTS_SECONDS: 31536000 ``` ### **2. Updated Caddy Configuration** (`corrected_caddyfile.txt`) Enhanced the Paperless reverse proxy configuration with proper headers: ```caddy paperless.pressmess.duckdns.org { reverse_proxy 192.168.50.229:8000 { header_up X-Forwarded-Proto https header_up X-Forwarded-Port 443 header_up X-Forwarded-For {remote_host} header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-Host {host} } import standard_tls } ``` --- ## 🚀 **Deployment Process** ### **Step 1: Caddy Update (Surface Machine)** - ✅ Updated Caddyfile with proper reverse proxy headers - ✅ Validated configuration with `caddy validate` - ✅ Reloaded Caddy service without downtime ### **Step 2: Paperless Update (OMV800)** - ✅ Located Paperless installation at `/root/paperless_fix` - ✅ Created backup of existing configuration - ✅ Updated `docker-compose.yml` with CSRF settings - ✅ Restarted Paperless stack with new configuration ### **Step 3: Verification** - ✅ Confirmed services are running: `docker compose ps` - ✅ Tested HTTP response: `302` (expected redirect to login) - ✅ Verified security headers are present --- ## 🔍 **Technical Details** ### **CSRF Configuration Explained** - **`PAPERLESS_URL`**: Tells Paperless its public URL for generating absolute URLs - **`PAPERLESS_CSRF_TRUSTED_ORIGINS`**: Allows CSRF tokens from the DuckDNS domain - **`PAPERLESS_ALLOWED_HOSTS`**: Security setting to accept requests from the domain - **`PAPERLESS_USE_X_FORWARDED_*`**: Enables proper handling of reverse proxy headers ### **Caddy Headers Explained** - **`X-Forwarded-Proto: https`**: Tells Paperless the original protocol was HTTPS - **`X-Forwarded-Port: 443`**: Indicates the original port was 443 - **`X-Forwarded-For`**: Preserves the original client IP - **`Host`**: Maintains the original host header - **`X-Real-IP`**: Alternative header for client IP - **`X-Forwarded-Host`**: Preserves the original host for CSRF validation --- ## 🎉 **Result** - ✅ **CSRF Error Resolved**: No more 403 Forbidden errors - ✅ **Secure Access**: HTTPS with proper SSL certificates - ✅ **Proper Headers**: All necessary security headers in place - ✅ **Zero Downtime**: Services updated without interruption --- ## 📋 **Files Modified** 1. **`paperless_fix_compose.yml`** - Updated with CSRF environment variables 2. **`corrected_caddyfile.txt`** - Enhanced with reverse proxy headers 3. **`fix_paperless_caddy_csrf.sh`** - Deployment script created --- ## 🔧 **Troubleshooting Commands** If issues persist: ```bash # Check Caddy logs ssh jon@192.168.50.254 'sudo journalctl -u caddy -f' # Check Paperless logs ssh root@192.168.50.229 'cd /root/paperless_fix && docker compose logs webserver' # Test Paperless directly curl -I https://paperless.pressmess.duckdns.org # Check service status ssh root@192.168.50.229 'cd /root/paperless_fix && docker compose ps' ``` --- ## 📝 **Notes** - The fix maintains backward compatibility - All existing data and configurations are preserved - Security is enhanced with additional headers - The solution follows Django best practices for reverse proxy deployment