Configuring CORS in Nginx allows a browser application served from one origin to call an API on another origin without being blocked by the browser’s cross-site protections. Done correctly, cross-origin access becomes explicit and predictable instead of relying on trial-and-error header tweaks.
Browsers include an Origin request header and decide whether JavaScript can read the response based on CORS response headers like Access-Control-Allow-Origin. Requests that use non-simple methods, non-simple Content-Type values (such as application/json), or custom headers (such as Authorization) usually trigger a preflight OPTIONS request that must return the expected allow headers before the browser proceeds.
Overly broad CORS rules can expose authenticated responses to untrusted sites when cookies or other browser credentials are involved, even though server-side authentication still exists. Prefer a specific origin, keep rules scoped to only the location blocks that need cross-origin access, and use the always modifier so headers are present on error responses as well.
Related: How to secure Nginx web server
Related: How to add custom headers in Nginx
Steps to configure CORS headers in Nginx:
- Decide the exact allowed origin and whether the browser must send credentials.
The origin must match scheme, host, and port, such as https://app.example.com or http://localhost:3000.
- Add CORS headers and a preflight OPTIONS response in the relevant API location block.
location /api/ { add_header Access-Control-Allow-Origin "https://app.example.com" always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type" always; add_header Access-Control-Max-Age "86400" always; if ($request_method = OPTIONS) { return 204; } ##### snipped ##### }
Do not combine Access-Control-Allow-Credentials: true with Access-Control-Allow-Origin: *; browsers reject that combination, and overly permissive CORS can leak authenticated responses to malicious origins.
- Test the Nginx configuration for syntax errors.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
- Reload Nginx to apply the changes.
$ sudo systemctl reload nginx
- Verify the preflight response returns CORS headers for an OPTIONS request.
$ curl -i -X OPTIONS \ -H 'Origin: https://app.example.com' \ -H 'Access-Control-Request-Method: POST' \ -H 'Access-Control-Request-Headers: Authorization, Content-Type' \ http://127.0.0.1/api/ HTTP/1.1 204 No Content Server: nginx Date: Mon, 13 May 2024 10:15:01 GMT Connection: keep-alive Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Authorization, Content-Type Access-Control-Max-Age: 86400
If the browser requests additional headers in Access-Control-Request-Headers, add them to Access-Control-Allow-Headers or the preflight will fail.
- Verify a normal request includes Access-Control-Allow-Origin when an Origin header is present.
$ curl -i -H 'Origin: https://app.example.com' http://127.0.0.1/api/ HTTP/1.1 200 OK Server: nginx Date: Mon, 13 May 2024 10:15:07 GMT Content-Type: application/json Connection: keep-alive Access-Control-Allow-Origin: https://app.example.com ##### snipped #####
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
Comment anonymously. Login not required.
