Nginx CORS Configuration

Configure CORS headers in Nginx using add_header directives, map blocks for multiple origins, and proper OPTIONS handling. Production-ready snippets included.

Framework Config

Detailed Explanation

Nginx CORS — Production Configuration

Nginx is commonly used as a reverse proxy in front of application servers. Adding CORS headers at the Nginx layer means your application code does not need to handle CORS at all.

Simple Configuration — Single Origin

server {
    listen 443 ssl;
    server_name api.example.com;

    location /api/ {
        add_header Access-Control-Allow-Origin "https://app.example.com" always;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
        add_header Access-Control-Max-Age 3600 always;
        add_header Access-Control-Allow-Credentials "true" always;
        add_header Vary Origin always;

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

        proxy_pass http://backend;
    }
}

Multiple Origins with map

map $http_origin $cors_origin {
    default "";
    "https://app.example.com"   "$http_origin";
    "https://admin.example.com" "$http_origin";
    "https://staging.example.com" "$http_origin";
}

server {
    location /api/ {
        if ($cors_origin != "") {
            add_header Access-Control-Allow-Origin $cors_origin always;
            add_header Access-Control-Allow-Credentials "true" always;
            add_header Vary Origin always;
        }

        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin $cors_origin always;
            add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
            add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
            add_header Access-Control-Max-Age 3600 always;
            return 204;
        }

        proxy_pass http://backend;
    }
}

The always Parameter

The always parameter ensures headers are added even for error responses (4xx, 5xx). Without it, Nginx only adds custom headers to 2xx and 3xx responses, which means CORS errors during 401/403 responses will not include the correct headers — making debugging much harder.

Common Mistakes

  1. Missing always — Headers not sent on error responses.
  2. Duplicate headers — If both Nginx and the backend set CORS headers, the browser sees duplicate values and may reject them. Handle CORS in one layer only.
  3. if directive limitations — Nginx's if is evaluated in the rewrite phase. Complex conditionals should use map instead.

Use Case

An operations engineer deploying a microservices architecture behind Nginx needs to add CORS headers at the reverse proxy layer so that individual backend services do not need to implement CORS logic.

Try It — CORS Header Builder

Open full tool