nginx config to enable CORS with origin matching nginx config to enable CORS with origin matching nginx nginx

nginx config to enable CORS with origin matching


You can try to use map istead of the first if block:

map $http_origin $allow_origin {    ~^http://(www\.)?example.com$ $http_origin;}map $http_origin $allow_methods {    ~^http://(www\.)?example.com$ "OPTIONS, HEAD, GET";}server {    listen 80 default_server;    root /var/www;    location / {        add_header Access-Control-Allow-Origin $allow_origin;        add_header Access-Control-Allow-Methods $allow_methods;        # Handling preflight requests        if ($request_method = OPTIONS) {            add_header Content-Type text/plain;            add_header Content-Length 0;            return 204;        }    }}

nginx will refuse to add an empty HTTP headers, so they will be added only if Origin header is present in request and matched this regex.


The only solution I've found so far is a hack to use a variable to aggregate multiple conditions and then match it with only a single if statement, therefore duplicating some directives:

server {    listen 80 default_server;    root /var/www;    location / {        set $cors '';        set $cors_allowed_methods 'OPTIONS, HEAD, GET';        if ($http_origin ~ '^https?://(www\.)?example.com$') {            set $cors 'origin_matched';        }        # Preflight requests        if ($request_method = OPTIONS) {            set $cors '${cors} & preflight';        }        if ($cors = 'origin_matched') {            add_header Access-Control-Allow-Origin $http_origin;        }        if ($cors = 'origin_matched & preflight') {            add_header Access-Control-Allow-Origin $http_origin always;            add_header Access-Control-Allow-Methods $cors_allowed_methods;            add_header Content-Type text/plain;            add_header Content-Length 0;            return 204;        }    }}


Without getting into the details of your nginx setup, it's not going to work anyway, because the CORS header's you're returning are incorrect...

Specifically:

  • For preflight (OPTIONS) requests, the following are the only meaningful CORS response headers: Access-Control-Allow Origin, (required), Access-Control-Allow Credentials (optional), Access-Control-Allow-Methods, (required), Access-Control-Allow-Headers, (required) and Access-Control-Max-Age, (optional). Any others are ignored.

  • For regular (non-OPTIONS) requests, the following are the only meaningful CORS response headers: Access-Control-Allow Origin (required), Access-Control-Allow Credentials (optional) and Access-Control-Expose-Headers (optional). Any others are ignored.

Note those required headers for pre-flight requests - currently you're only passing two of them... Also, note that you don't need to return Access-Control-Allow-Methods for a non-OPTIONS request - it's not 'valid', so will be ignored.

As far as your specific nginx issue goes, I think @Slava Fomin II has the correct-est answer...