Files
encoach_backend_new_v2/deploy/nginx-vps.conf.example
Yamen Ahmad 75ee0f1fe0
Some checks failed
CI / Frontend — lint + build + e2e (pull_request) Has been cancelled
CI / Backend — Odoo HttpCase (pull_request) Has been cancelled
fix(ui): actionable 413/504/401 toasts + VPS nginx deploy template
Production QA reported "Submit failed 413" on /generation and plain
"Upload failed" (no detail) on resource upload. Root cause is the
outer reverse-proxy nginx on the VPS — still on default
`client_max_body_size 1m` — rejecting requests before they reach
Odoo. The inner docker-nginx and Odoo limits were already raised in
earlier commits; only the VPS proxy was left unpatched.

UI side
- Add `describeApiError(err, fallback, context)` helper in
  lib/api-client.ts. Maps common HTTP codes to human-readable,
  actionable toast descriptions (413 → "ask ops to raise nginx
  client_max_body_size", 504 → "server took too long, retry", 502
  → "Odoo is restarting", 401 → "sign in again", 4xx/5xx → server
  error body + status code).
- Use it in GenerationPage submit, ResourceManager upload,
  TeacherLibrary upload, CustomExamCreate save/publish. Replaces
  four slightly-different ad-hoc mappings with one source of truth.

Deploy side
- Add deploy/nginx-vps.conf.example: full TLS reverse-proxy template
  with the body/timeout knobs that must match Odoo's limit_request
  (128 MB) and limit_time_real (900 s).
- Add docs/DEPLOY_413_504_FIX.md: step-by-step remediation guide for
  the team lead covering the 3 layers that can block large bodies
  (outer nginx, Cloudflare, Odoo worker) and how to verify each.

Made-with: Cursor
2026-04-21 09:09:23 +04:00

86 lines
4.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 210 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;
}