# EnCoach — example VPS reverse-proxy config # # Sits in front of the docker-compose stack (frontend:80 + backend:8069). # Copy to /etc/nginx/sites-available/encoach, edit server_name / TLS paths, # symlink to sites-enabled, then `nginx -t && systemctl reload nginx`. # # The inner frontend container already raises its own nginx limits # (see frontend/Dockerfile). If THIS outer proxy isn't raised too, the # outer layer returns 413/504 before traffic ever reaches Odoo, and users # see "Submit failed 413" or "Upload failed" with no server-side log entry. # ───────────────────────────────────────────────────────────────── # HTTP → HTTPS redirect (remove if you're not terminating TLS here) server { listen 80; listen [::]:80; server_name encoach.example.com; return 301 https://$host$request_uri; } # ───────────────────────────────────────────────────────────────── # Main TLS vhost server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name encoach.example.com; ssl_certificate /etc/letsencrypt/live/encoach.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/encoach.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # ── CRITICAL ──────────────────────────────────────────────── # Default nginx caps request bodies at 1 MB, which triggers # HTTP 413 on: # * /api/resources (PDF / audio / image uploads) # * /api/exam/generation/submit (full module payload — can # easily be 2–10 MB when all tasks are filled) # * /api/approval-requests (attachments on approval flow) # Match this value to Odoo's `limit_request` (128 MB). client_max_body_size 128m; client_body_buffer_size 1m; client_body_timeout 900s; large_client_header_buffers 4 16k; # ── Static / SPA served by the frontend container ─────────── location / { proxy_pass http://127.0.0.1:8080; # docker-compose: frontend:80 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; } # ── Odoo API: AI calls can take minutes, needs long timeouts ─ # Must exceed Odoo's limit_time_real (900s in odoo-docker.conf). # proxy_request_buffering off streams the body to Odoo instead of # buffering it entirely on disk → less chance of hitting the 413 # when uploading big resources. location /api/ { proxy_pass http://127.0.0.1:8069/api/; 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; proxy_http_version 1.1; proxy_read_timeout 900s; proxy_send_timeout 900s; proxy_connect_timeout 60s; proxy_request_buffering off; proxy_buffering off; # stream AI responses to the client } # ── Odoo web client + longpolling (optional, for /web/* URLs) ─ location /longpolling/ { proxy_pass http://127.0.0.1:8069/longpolling/; proxy_http_version 1.1; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } # Access / error logs — keep them separate so 413s are easy to spot access_log /var/log/nginx/encoach.access.log; error_log /var/log/nginx/encoach.error.log warn; }