How to Quickly Fix CORS Issues with Simple Nginx Configuration

This article walks through common CORS errors encountered when a frontend on http://localhost:8080 calls a backend on http://localhost:59200, explains the role of the four CORS response headers, the preflight OPTIONS request, and provides step‑by‑step Nginx configurations to resolve each case.

Linux Tech Enthusiast
Linux Tech Enthusiast
Linux Tech Enthusiast
How to Quickly Fix CORS Issues with Simple Nginx Configuration

When a frontend running at http://localhost:8080 accesses a backend at http://localhost:59200, browsers enforce the CORS policy. The article first ensures the backend itself does not handle CORS and that the API works with Postman.

Key CORS response headers

Access-Control-Allow-Origin

– specifies allowed request origins (validated for both preflight and actual requests). Access-Control-Allow-Headers – lists special request headers allowed (validated only for preflight). Access-Control-Allow-Methods – enumerates HTTP methods permitted (validated only for preflight). Access-Control-Allow-Credentials – indicates whether cookies can be sent; setting it to true is optional and may be unstable in some browsers.

The author notes that many online guides simply add these headers in Nginx, which works for most cases but can fail when the configuration is incomplete.

Understanding the preflight request

A preflight OPTIONS request is sent by the browser to verify that the server permits the requested origin, methods, and headers. If the server does not return a successful status (e.g., 204) or the required headers, the actual request is blocked.

Step‑by‑step Nginx configurations

Case 1 : Missing Access-Control-Allow-Origin in the preflight response.

server {
    listen 22222;
    server_name localhost;
    location / {
        add_header Access-Control-Allow-Origin 'http://localhost:8080';
        proxy_pass http://localhost:59200;
    }
}

After adding the header, the same error persisted, revealing that add_header only applies to certain status codes. Adding the always flag ensures the header is sent for all responses.

server {
    listen 22222;
    server_name localhost;
    location / {
        add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
        proxy_pass http://localhost:59200;
    }
}

Case 2 : Preflight request returns a non‑OK status. The solution is to return 204 for OPTIONS requests.

if ($request_method = 'OPTIONS') {
    return 204;
}

Case 3 : Missing Access-Control-Allow-Headers for the authorization header.

if ($request_method = 'OPTIONS') {
    add_header Access-Control-Allow-Headers 'authorization';
    return 204;
}

After fixing the header, the error reverted to Case 1, indicating that the OPTIONS block overrides other add_header directives. The Nginx documentation states that add_header directives are inherited only when none are defined at the current level.

Handling other methods and headers

Case 4 : Changing a request from GET to PUT triggers a Method PUT is not allowed error because Access-Control-Allow-Methods does not include PUT. Adding it resolves the issue.

add_header Access-Control-Allow-Methods 'PUT';

Case 5 : When the backend already sets CORS headers, Nginx may add duplicate Access-Control-Allow-Origin values (e.g., *, http://localhost:8080), which browsers reject. The fix is to let either the backend or Nginx handle CORS, but not both.

Final robust configuration

The author provides a complete configuration that distinguishes OPTIONS requests from others, adds the necessary headers, and returns 204 for preflight:

server {
    listen 22222;
    server_name localhost;
    location / {
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin 'http://localhost:8080';
            add_header Access-Control-Allow-Headers 'authorization';
            add_header Access-Control-Allow-Methods 'PUT';
            return 204;
        }
        if ($request_method != 'OPTIONS') {
            add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
        }
        proxy_pass http://localhost:59200;
    }
}

Alternatively, a more permissive version uses * for Access-Control-Allow-Headers and Access-Control-Allow-Methods, but keeps Access-Control-Allow-Origin restricted to the specific frontend domain for security.

By following the step‑by‑step analysis, readers can diagnose CORS errors, understand why each header matters, and apply the appropriate Nginx rules to resolve them.

CORSNginxhttp-headerspreflightreverse-proxyoptions-request
Linux Tech Enthusiast
Written by

Linux Tech Enthusiast

Focused on sharing practical Linux technology content, covering Linux fundamentals, applications, tools, as well as databases, operating systems, network security, and other technical knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.