docs: document nginx routing rules to prevent SPA fallback hiding API 404s
TASK-006: Document the nginx routing configuration that ensures API requests returning 404 from FastAPI are not intercepted by the SPA wildcard fallback rule. This prevents development bugs from being masked by 200 responses containing HTML instead of 404 errors. Added section 9.2 in Architekture.md covering: - nginx location block priority (longest-prefix matching) - Routing configuration for /api/, /assets/, and / - Detailed routing behavior diagrams - Critical implementation notes to prevent regressions The current nginx.conf is already correct: - /api/ location has no try_files and proxies directly to backend - /assets/ location uses try_files with =404 - / catch-all uses SPA fallback to index.html This ensures: ✓ API typos like /api/jailss return 404, not SPA HTML ✓ Frontend routes serve SPA HTML for client-side routing ✓ Static assets properly return 404 when missing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -768,7 +768,67 @@ APScheduler 4.x (async mode) manages recurring background tasks.
|
||||
|
||||
---
|
||||
|
||||
## 9.2 Deployment Constraints
|
||||
## 9.2 nginx Routing Rules
|
||||
|
||||
The reverse proxy (nginx) must route requests correctly to prevent frontend SPA fallback rules from hiding backend 404 errors. The following location blocks ensure proper behavior:
|
||||
|
||||
### Location Block Priority
|
||||
|
||||
nginx uses **longest-prefix matching** to determine which location block handles a request:
|
||||
1. Exact matches (`location =`) — highest priority
|
||||
2. Regular expression matches (`location ~`) — second priority
|
||||
3. Prefix matches (`location /prefix`) — matched in order of specificity (longest first)
|
||||
4. Catch-all (`location /`) — lowest priority
|
||||
|
||||
### Routing Configuration
|
||||
|
||||
| Location Block | Rule | Purpose |
|
||||
|---|---|---|
|
||||
| `location /api/` | `proxy_pass http://backend:8000;` — **no `try_files`** | Proxy all API requests to FastAPI backend. Any unmatched API route (typos, invalid paths) returns 404 from the backend. |
|
||||
| `location /assets/` | `try_files $uri =404;` | Serve static assets with long-term caching. Return 404 if file doesn't exist. |
|
||||
| `location /` | `try_files $uri $uri/ /index.html;` | SPA fallback: serve `index.html` for all unmatched routes (client-side routing). |
|
||||
|
||||
### Routing Behavior
|
||||
|
||||
```
|
||||
Request → /api/some-endpoint
|
||||
↓
|
||||
nginx matches location /api/ (longest prefix)
|
||||
↓
|
||||
proxy_pass → backend:8000
|
||||
↓
|
||||
Backend returns 404 if endpoint doesn't exist (✓ correct)
|
||||
Client sees 404, not SPA HTML
|
||||
|
||||
Request → /some-page
|
||||
↓
|
||||
nginx matches location / (catch-all)
|
||||
↓
|
||||
try_files looks for file, then directory, then /index.html
|
||||
↓
|
||||
Serves /index.html (React Router handles client-side routing)
|
||||
↓
|
||||
Client sees 200 with HTML (✓ correct for SPA)
|
||||
|
||||
Request → /api/typos
|
||||
↓
|
||||
nginx matches location /api/ (longest prefix, NOT catch-all)
|
||||
↓
|
||||
proxy_pass → backend:8000
|
||||
↓
|
||||
FastAPI returns 404 (✓ correct, not caught by SPA fallback)
|
||||
```
|
||||
|
||||
### Critical Implementation Notes
|
||||
|
||||
- **Never add `try_files` to the `/api/` location block** — this would hide backend 404s.
|
||||
- **The `/api/` location must come before the `/` catch-all** in the config (this is automatically respected via longest-prefix matching).
|
||||
- **No inherited `try_files` rules** — the `/api/` location has no global `try_files` that could affect it.
|
||||
- **Backend 404 responses pass through nginx unchanged** — nginx does not rewrite 404 responses from the backend.
|
||||
|
||||
---
|
||||
|
||||
## 9.3 Deployment Constraints
|
||||
|
||||
### Single-Worker Requirement
|
||||
|
||||
|
||||
Reference in New Issue
Block a user