Bird
Raised Fist0
Nginxdevops~15 mins

CORS configuration in Nginx - Deep Dive

Choose your learning style10 modes available
Overview - CORS configuration
What is it?
CORS stands for Cross-Origin Resource Sharing. It is a security feature in web browsers that controls how resources on a web server can be requested from another domain. Configuring CORS in nginx means setting rules to allow or restrict which external websites can access your server's resources. This helps protect your server from unauthorized or harmful cross-site requests.
Why it matters
Without proper CORS configuration, your web server might block legitimate requests from other domains or, worse, allow malicious sites to access sensitive data. This can break your web applications or expose users to security risks like data theft. Proper CORS setup ensures smooth, secure communication between your server and trusted external websites.
Where it fits
Before learning CORS configuration, you should understand basic web server setup and HTTP headers. After mastering CORS, you can explore advanced web security topics like authentication, HTTPS, and API gateway configurations.
Mental Model
Core Idea
CORS configuration in nginx is like setting guest list rules for who can enter your server's party from other websites.
Think of it like...
Imagine your server is hosting a party and only wants to let in friends from certain neighborhoods (domains). CORS is the doorman's list that checks each guest's address before allowing entry.
┌───────────────┐
│ Client Browser│
└──────┬────────┘
       │ Sends request with Origin header
       ▼
┌───────────────┐
│   nginx Server│
│  CORS Config  │
│ Checks Origin │
└──────┬────────┘
       │ If allowed, adds Access-Control-Allow-Origin header
       ▼
┌───────────────┐
│ Response sent │
Build-Up - 7 Steps
1
FoundationUnderstanding Cross-Origin Requests
🤔
Concept: Learn what cross-origin requests are and why browsers restrict them.
When a web page tries to request data from a different domain than the one it came from, it's called a cross-origin request. Browsers block many of these requests by default to protect users from malicious sites stealing data. This is called the Same-Origin Policy.
Result
You understand that browsers limit cross-domain requests to protect users.
Knowing the browser's default restriction explains why CORS is needed to allow safe cross-domain communication.
2
FoundationRole of HTTP Headers in CORS
🤔
Concept: CORS uses special HTTP headers to communicate permissions between client and server.
The browser sends an Origin header with the request showing where it came from. The server responds with Access-Control-Allow-Origin to say which origins are allowed. Other headers control methods, credentials, and headers allowed.
Result
You see how headers act as permission notes between browser and server.
Understanding these headers is key to configuring CORS correctly in nginx.
3
IntermediateBasic nginx CORS Configuration
🤔
Concept: Learn how to add simple CORS headers in nginx to allow specific origins.
In nginx, you add headers using the add_header directive inside a server or location block. For example: add_header 'Access-Control-Allow-Origin' 'https://example.com'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Content-Type'; This allows only https://example.com to access resources with specified methods and headers.
Result
nginx sends CORS headers allowing trusted origins to access resources.
Knowing how to add headers in nginx lets you control who can access your server's resources.
4
IntermediateHandling Preflight OPTIONS Requests
🤔Before reading on: do you think nginx automatically handles OPTIONS requests for CORS? Commit to yes or no.
Concept: Preflight requests use the OPTIONS method to check permissions before the actual request.
Browsers send an OPTIONS request before certain cross-origin requests to ask if the real request is safe. nginx must respond with correct CORS headers and a 204 status without forwarding the request. Example: location /api/ { if ($request_method = OPTIONS ) { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Content-Type'; add_header 'Access-Control-Max-Age' 1728000; return 204; } # normal processing }
Result
nginx correctly responds to preflight OPTIONS requests, enabling browsers to proceed.
Handling OPTIONS requests prevents failed CORS checks and broken cross-origin calls.
5
IntermediateAllowing Multiple Origins Dynamically
🤔Before reading on: can nginx natively set Access-Control-Allow-Origin to multiple domains at once? Commit to yes or no.
Concept: nginx cannot list multiple origins directly; it requires conditional logic to allow multiple trusted domains.
You can use nginx variables and if statements to check the Origin header and set Access-Control-Allow-Origin dynamically: set $cors ''; if ($http_origin ~* (https?://(example1.com|example2.com))) { set $cors $http_origin; } add_header 'Access-Control-Allow-Origin' $cors; This allows only example1.com and example2.com dynamically.
Result
nginx sends Access-Control-Allow-Origin matching the request origin if trusted.
Knowing nginx's limitations and workarounds helps implement flexible CORS policies.
6
AdvancedSecuring CORS with Credentials
🤔Before reading on: does setting Access-Control-Allow-Origin to '*' allow credentials like cookies? Commit to yes or no.
Concept: Allowing credentials requires specific origin values and additional headers.
To allow cookies or authorization headers, you must: - Set Access-Control-Allow-Origin to the exact origin (not '*') - Add Access-Control-Allow-Credentials: true Example: add_header 'Access-Control-Allow-Origin' $http_origin; add_header 'Access-Control-Allow-Credentials' 'true'; This ensures only trusted origins can send credentials securely.
Result
Cross-origin requests can include credentials safely when configured properly.
Understanding credential rules prevents security holes and broken authentication.
7
ExpertPerformance and Security Tradeoffs in CORS
🤔Before reading on: does enabling CORS with '*' always improve performance? Commit to yes or no.
Concept: CORS settings affect caching, security, and server load; careful tuning is needed in production.
Using '*' for Access-Control-Allow-Origin is easy but risky for sensitive data. Setting specific origins improves security but requires more config. Also, Access-Control-Max-Age controls how long browsers cache preflight responses, affecting performance. Overly long caching can cause stale permissions; too short increases OPTIONS requests. Balancing these factors is key in real-world deployments.
Result
You can tune CORS for optimal security and performance in production.
Knowing these tradeoffs helps avoid common pitfalls that cause security breaches or slow user experience.
Under the Hood
When a browser makes a cross-origin request, it sends an Origin header indicating the source domain. nginx reads this header and, based on its configuration, decides whether to include Access-Control-Allow-Origin and other CORS headers in the response. For certain requests, browsers send a preflight OPTIONS request to check permissions. nginx must respond directly to these OPTIONS requests with appropriate headers and a 204 status to approve the actual request. This handshake ensures that only allowed domains can access resources, enforcing browser security policies.
Why designed this way?
CORS was designed to balance security and flexibility. Browsers enforce the Same-Origin Policy to prevent malicious cross-site attacks but needed a way to allow legitimate cross-domain interactions like APIs and fonts. The header-based approach lets servers explicitly declare trusted origins without breaking existing web standards. nginx implements this by allowing header manipulation and request handling to fit diverse application needs while maintaining performance and security.
┌───────────────┐
│ Browser sends │
│ Origin header │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ nginx receives│
│ request       │
│ Checks Origin │
└──────┬────────┘
       │
       ▼
┌─────────────────────────────┐
│ If OPTIONS (preflight)       │
│ ┌─────────────────────────┐ │
│ │ Respond with 204 + CORS │ │
│ └─────────────────────────┘ │
│ Else                       │
│ ┌─────────────────────────┐ │
│ │ Add CORS headers if OK  │ │
│ │ Forward request         │ │
│ └─────────────────────────┘ │
└─────────────────────────────┘
       │
       ▼
┌───────────────┐
│ Browser checks │
│ CORS headers  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does setting Access-Control-Allow-Origin to '*' allow cookies to be sent? Commit to yes or no.
Common Belief:Setting Access-Control-Allow-Origin to '*' allows any site to send cookies and credentials.
Tap to reveal reality
Reality:Browsers block credentials if Access-Control-Allow-Origin is '*'. You must specify the exact origin and set Access-Control-Allow-Credentials to true.
Why it matters:Misconfiguring this causes authentication failures or exposes sensitive data unintentionally.
Quick: Does nginx automatically handle OPTIONS preflight requests for CORS? Commit to yes or no.
Common Belief:nginx automatically responds to OPTIONS requests needed for CORS preflight without extra config.
Tap to reveal reality
Reality:nginx requires explicit configuration to respond to OPTIONS requests with correct headers and status; otherwise, preflight fails.
Why it matters:Without this, cross-origin requests that need preflight will fail, breaking client applications.
Quick: Can you list multiple origins directly in Access-Control-Allow-Origin header? Commit to yes or no.
Common Belief:You can list multiple domains separated by commas in Access-Control-Allow-Origin to allow them all.
Tap to reveal reality
Reality:Access-Control-Allow-Origin accepts only one origin or '*'. To allow multiple, you must dynamically set it based on the request origin.
Why it matters:Incorrectly listing multiple origins causes browsers to ignore the header, blocking legitimate requests.
Quick: Does CORS protect servers from all types of attacks? Commit to yes or no.
Common Belief:CORS fully protects servers from all cross-site attacks.
Tap to reveal reality
Reality:CORS only controls browser behavior for cross-origin requests; it does not protect servers from direct attacks or non-browser clients.
Why it matters:Relying solely on CORS for security can leave servers vulnerable to other attack vectors.
Expert Zone
1
nginx's add_header directive only adds headers on successful responses by default; to add headers on errors, you must use always parameter.
2
Dynamic origin matching in nginx can be tricky due to lack of native regex support in add_header; using map blocks improves maintainability.
3
Preflight caching duration (Access-Control-Max-Age) affects how often browsers send OPTIONS requests, impacting server load and user experience.
When NOT to use
Avoid using broad CORS settings like '*' in production APIs that handle sensitive data. Instead, use API gateways or authentication tokens to control access. For internal services, consider network-level controls or VPNs rather than CORS.
Production Patterns
In production, nginx often uses map directives to whitelist allowed origins dynamically. Preflight OPTIONS requests are handled with dedicated location blocks returning 204 status. Credentials are enabled only for trusted domains with exact origin matching. Access-Control-Max-Age is tuned to balance performance and security. Logs monitor CORS failures to detect misconfigurations.
Connections
HTTP Headers
CORS configuration builds directly on HTTP header manipulation.
Understanding HTTP headers deeply helps configure CORS precisely and troubleshoot issues effectively.
Web Security
CORS is a part of broader web security mechanisms.
Knowing CORS helps grasp how browsers enforce security policies and how servers can safely share resources.
Access Control Lists (ACLs)
CORS acts like an ACL for web resources, controlling who can access what.
Recognizing CORS as a form of access control clarifies its role in protecting resources and parallels security concepts in networking.
Common Pitfalls
#1Allowing all origins with '*' while enabling credentials.
Wrong approach:add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Credentials' 'true';
Correct approach:add_header 'Access-Control-Allow-Origin' $http_origin; add_header 'Access-Control-Allow-Credentials' 'true';
Root cause:Misunderstanding that '*' cannot be used with credentials leads to broken authentication or security risks.
#2Not handling OPTIONS preflight requests explicitly.
Wrong approach:location /api/ { proxy_pass http://backend; }
Correct approach:location /api/ { if ($request_method = OPTIONS ) { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Content-Type'; add_header 'Access-Control-Max-Age' 1728000; return 204; } proxy_pass http://backend; }
Root cause:Assuming nginx automatically handles OPTIONS requests causes preflight failures.
#3Listing multiple origins separated by commas in Access-Control-Allow-Origin.
Wrong approach:add_header 'Access-Control-Allow-Origin' 'https://example1.com, https://example2.com';
Correct approach:set $cors ''; if ($http_origin ~* (https?://(example1.com|example2.com))) { set $cors $http_origin; } add_header 'Access-Control-Allow-Origin' $cors;
Root cause:Not knowing the header accepts only one origin causes browsers to ignore the header.
Key Takeaways
CORS is a browser security feature controlled by HTTP headers that lets servers specify which external domains can access their resources.
nginx configures CORS by adding specific headers and handling preflight OPTIONS requests to enable safe cross-origin communication.
Proper CORS setup requires exact origin matching when credentials are involved; using '*' disables credential support.
Misconfigurations in CORS can break applications or expose security risks, so understanding headers and nginx behavior is essential.
Advanced CORS tuning balances security, performance, and flexibility, making it a critical skill for production web servers.

Practice

(1/5)
1. What is the main purpose of configuring CORS in an nginx server?
easy
A. To control which websites can access server resources
B. To improve server performance by caching
C. To encrypt data between client and server
D. To block all incoming traffic

Solution

  1. Step 1: Understand CORS purpose

    CORS (Cross-Origin Resource Sharing) controls which external websites can request resources from your server.
  2. Step 2: Identify correct purpose in options

    Only To control which websites can access server resources describes controlling access from other websites, which matches CORS functionality.
  3. Final Answer:

    To control which websites can access server resources -> Option A
  4. Quick Check:

    CORS controls access = D [OK]
Hint: Remember CORS controls cross-site resource sharing [OK]
Common Mistakes:
  • Confusing CORS with encryption or caching
  • Thinking CORS blocks all traffic
  • Assuming CORS improves performance
2. Which of the following is the correct syntax to add a CORS header allowing all origins in an nginx configuration?
easy
A. add_header "Access-Control-Allow-Origin" "*";
B. add_header "Access-Control-Allow-Origin" *;
C. add_header Access-Control-Allow-Origin "*";
D. add_header Access-Control-Allow-Origin *;

Solution

  1. Step 1: Understand nginx add_header syntax

    The header name does not require quotes unless it contains spaces or special characters. The value must be quoted if it is a string like "*".
  2. Step 2: Identify correct quoting

    add_header Access-Control-Allow-Origin "*"; correctly quotes the value and does not quote the header name, which is the recommended syntax.
  3. Final Answer:

    add_header Access-Control-Allow-Origin "*"; -> Option C
  4. Quick Check:

    Proper quoting for header value only = B [OK]
Hint: Quote header value for safety in nginx, header name usually unquoted [OK]
Common Mistakes:
  • Quoting header name unnecessarily
  • Using * without quotes
  • Misplacing semicolons
3. Given this nginx snippet inside a location block:
if ($request_method = 'OPTIONS') {
  add_header Access-Control-Allow-Origin "*";
  add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
  add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range";
  add_header Access-Control-Max-Age 1728000;
  add_header Content-Type "text/plain charset=UTF-8";
  add_header Content-Length 0;
  return 204;
}
What will be the HTTP status code returned for an OPTIONS request?
medium
A. 200
B. 204
C. 400
D. 500

Solution

  1. Step 1: Analyze the if block for OPTIONS method

    The configuration checks if the request method is OPTIONS, then sets headers and returns status code 204.
  2. Step 2: Identify the return status code

    The line return 204; explicitly sends HTTP status 204 (No Content) for OPTIONS requests.
  3. Final Answer:

    204 -> Option B
  4. Quick Check:

    OPTIONS returns 204 No Content = B [OK]
Hint: Look for return statement inside OPTIONS check [OK]
Common Mistakes:
  • Assuming default 200 OK instead of 204
  • Confusing OPTIONS with GET method
  • Ignoring explicit return codes
4. You added this to your nginx config to allow CORS:
add_header Access-Control-Allow-Origin *;
But browsers still block cross-origin requests. What is the likely problem?
medium
A. The add_header directive is inside a location block without 'always' parameter
B. The header is missing quotes around '*', causing syntax error
C. nginx does not support CORS headers
D. You need to restart the browser to apply changes

Solution

  1. Step 1: Understand add_header behavior in nginx

    By default, add_header only adds headers on successful (2xx) responses. For OPTIONS or error responses, headers may be missing unless 'always' is used.
  2. Step 2: Identify missing 'always' parameter

    Without 'always', CORS headers may not be sent on OPTIONS or error responses, causing browser blocks.
  3. Final Answer:

    The add_header directive is inside a location block without 'always' parameter -> Option A
  4. Quick Check:

    Missing 'always' causes headers to be skipped = A [OK]
Hint: Use 'always' with add_header to send headers on all responses [OK]
Common Mistakes:
  • Not using 'always' with add_header
  • Assuming nginx lacks CORS support
  • Forgetting to reload nginx after config changes
5. You want to configure nginx to allow CORS only from https://example.com and support preflight OPTIONS requests. Which configuration snippet correctly achieves this?
hard
A. add_header "Access-Control-Allow-Origin" "*"; add_header "Access-Control-Allow-Methods" "GET, POST"; return 204;
B. add_header Access-Control-Allow-Origin *; if ($request_method = 'OPTIONS') { return 200; }
C. add_header "Access-Control-Allow-Origin" "https://example.com"; add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS"; add_header "Access-Control-Allow-Headers" "Content-Type"; return 200;
D. add_header "Access-Control-Allow-Origin" "https://example.com" always; if ($request_method = 'OPTIONS') { add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS" always; add_header "Access-Control-Allow-Headers" "Content-Type" always; add_header "Access-Control-Max-Age" 1728000 always; return 204; }

Solution

  1. Step 1: Check origin restriction

    Only add_header "Access-Control-Allow-Origin" "https://example.com" always; if ($request_method = 'OPTIONS') { add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS" always; add_header "Access-Control-Allow-Headers" "Content-Type" always; add_header "Access-Control-Max-Age" 1728000 always; return 204; } restricts origin to "https://example.com" correctly with proper quoting and 'always' parameter.
  2. Step 2: Verify OPTIONS preflight handling

    The configuration handles OPTIONS requests by returning 204 with required CORS headers and 'always' to ensure headers are sent.
  3. Step 3: Eliminate incorrect options

    Snippets using '*' allow all origins instead of restricting to https://example.com; those lacking full OPTIONS handling, 'always' parameter, or returning 200 instead of 204 fail preflight checks.
  4. Final Answer:

    Correctly restricts origin and handles OPTIONS with headers and 204 -> Option D
  5. Quick Check:

    Restrict origin + OPTIONS 204 + always = C [OK]
Hint: Use 'always' and return 204 for OPTIONS with restricted origin [OK]
Common Mistakes:
  • Using wildcard '*' instead of specific origin
  • Not handling OPTIONS preflight properly
  • Missing 'always' causing headers to be skipped
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard