How to Configure NGINX for Precise CORS Control and Secure Cross‑Origin Requests
This tutorial explains the fundamentals of same‑origin policy, demonstrates how to allow all origins or restrict methods in NGINX, shows how to handle pre‑flight OPTIONS requests, and provides complete configuration examples for secure CORS header management.
1. Introduction
NGINX is a versatile server that can act as a forward proxy, reverse proxy, mail proxy, or load balancer, and it supports all modern HTTP(S) features expected from a web server.
In this tutorial we explore how to control origin restrictions in NGINX. We first review the concept of origins and related issues, then present a quick example that allows requests from any origin, followed by a configuration that limits permissions to simple requests, and finally we show how to narrow the scope further and query the current configuration.
The code tested in this article runs on Debian 12 (Bookworm) with GNU Bash 5.2.15 and should work in most POSIX‑compatible environments unless otherwise noted.
2. Web Origin Issues
The Same‑Origin Policy (SOP) was introduced to control how one origin interacts with another, i.e., the cross‑origin policy.
For example, a script from http://gerganov.com needs special permission to request data from https://gerganov.com . Without proper settings the request fails and browsers show an error in the console.
Typical JavaScript error:
Cross Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://gerganov.com/.Similarly, an XMLHttpRequest may produce:
Access to XMLHttpRequest at 'https://gerganov.com' from origin 'http://gerganov.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.To enable or disable cross‑origin data access, the Cross‑Origin Resource Sharing (CORS) policy sends the necessary HTTP headers. In NGINX these headers are added with the add_header directive, which requires the headers module.
Note that different request types may require different headers.
3. NGINX Allow All Origins
Although it goes against best practices, many servers are configured to grant a blanket permission for all cross‑origin requests.
In NGINX this can be done with a simple location block. Crucially, NGINX uses only one location directive, so configurations with multiple location blocks can be ambiguous.
$ cat /etc/nginx/conf.d/default.conf
location / {
add_header 'Access-Control-Allow-Origin' '*';
}Opening NGINX to all origins exposes content to abuse and the server to attacks, which is why adhering to SOP is important.
It is essential to decide on specific origins or use server‑side scripts to dynamically set the Origin header value and take appropriate actions.
If the Access-Control-Allow-Origin header is missing, the server does not permit CORS.
Simple HTTP requests (GET, POST) are a direct way to test cross‑origin policies, but they may be rejected if not explicitly allowed:
GET
POST
Our responsibility is to check the response for CORS‑specific issues.
To allow only GET and POST cross‑origin requests, we again use location but restrict the methods:
$ cat /etc/nginx/conf.d/default.conf
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST';
}Thus we ensure two important headers exist with correct values:
Access-Control-Allow-Origin expected to be * (any origin)
Access-Control-Allow-Methods allowed only GET and POST
We can also limit CORS headers by pattern‑matching locations:
location ~* \.(x|ox|0x)$ {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST';
}However, this approach may be limited for newer request methods.
Before communication begins, browsers may send a pre‑flight request using the OPTIONS method to query the server’s supported features and cross‑origin policy.
We can retrieve this information so the server can share it before the actual resource request:
OPTIONS / HTTP/1.1
Host: gerganov.com:443
...
Origin: http://gerganov.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-requested-withWhen the server receives such an OPTIONS request, it can respond with the appropriate CORS headers without returning any content:
$ cat /etc/nginx/conf.d/default.conf
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, HEAD, OPTIONS';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 57542400;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}This if statement inside the location block checks for the OPTIONS method and adds additional headers:
Access-Control-Allow-Methods now permits OPTIONS requests (crucial)
Access-Control-Allow-Credentials allows credentials as part of cross‑origin requests
Access-Control-Allow-Headers permits a standard set of headers
Finally, the response returns a 204 No Content status to indicate success.
6. Summary
In this article we discussed NGINX header configurations related to the Same‑Origin Policy (SOP).
Because CORS headers are an important security measure and permission mechanism, understanding how to configure them for a widely used web server like NGINX is essential.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
