Fix CORS With a Reverse Proxy — Nginx in Front of Node or Python
Updated April 2026
If Nginx sits in front of your Node.js or Python backend, CORS headers can be added at two levels — Nginx or the application. Adding them at both causes duplicate headers. Here is exactly where to put them.
The duplicate header problem
This happens when both Nginx and your application add Access-Control-Allow-Origin. The browser sees two values and rejects both.
Option A — CORS only at Nginx (recommended)
Remove CORS middleware from your application and let Nginx handle it:
# nginx.conf
server { listen 443 ssl http2; server_name api.yourapp.com; location / { # Handle OPTIONS preflight at Nginx — app never sees it if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://yourapp.com"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Authorization, Content-Type"; add_header Access-Control-Max-Age 86400; add_header Content-Length 0; return 204; } # Add CORS to all responses from the backend add_header Access-Control-Allow-Origin "https://yourapp.com" always; proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
}
Then in your Node.js/Python app — remove all CORS middleware. Nginx handles it.
Option B — CORS only at the application
Keep CORS in your app and tell Nginx not to add it:
# nginx.conf — plain reverse proxy, no CORS headers
location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; # No add_header CORS directives here
}
# Node.js — add CORS in app
app.use(cors({ origin: "https://yourapp.com" }));
# FastAPI — add CORS middleware
app.add_middleware(CORSMiddleware, allow_origins=["https://yourapp.com"])
Why duplicates happen
Nginx's add_header adds headers in addition to headers the upstream (your app) sends. It does not replace. If your app sends Access-Control-Allow-Origin: * and Nginx adds Access-Control-Allow-Origin: https://yourapp.com, the browser sees both and rejects them.
The proxy_hide_header workaround
# If you cannot remove CORS from the app:
# Strip app CORS headers at Nginx, then re-add correct ones
location / { proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Access-Control-Allow-Methods; proxy_hide_header Access-Control-Allow-Headers; proxy_hide_header Access-Control-Allow-Credentials; add_header Access-Control-Allow-Origin "https://yourapp.com" always; # etc. proxy_pass http://127.0.0.1:3000;
}
Test for duplicates
curl -H "Origin: https://yourapp.com" -v \ https://api.yourapp.com/endpoint 2>&1 | grep -i "access-control" # Should return exactly ONE Access-Control-Allow-Origin lineTest your reverse proxy CORS config → CORSFixer