Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Wide-open CORS config for nginx
#
# Wide-open CORS config for nginx
#
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
@epicserve

This comment has been minimized.

Copy link

commented Feb 27, 2012

This doesn't seem to work for me ... I'm uisng nginx/1.0.5. For testing I replaced http://10.140.10.40 with *.

@jaseemabid

This comment has been minimized.

Copy link

commented Apr 12, 2012

Thanks a lot. This saved my day :)

@yishenggudou

This comment has been minimized.

Copy link

commented Apr 16, 2012

good example for config options

@Nek

This comment has been minimized.

Copy link

commented May 23, 2012

If only I could see this before wasting 5 hours of time... Thanks a lot for saving the rest of my day! :)

@mrdevin

This comment has been minimized.

Copy link

commented Aug 2, 2012

For me I hade to return 204 otherwise the browser would hang and then timeout on the option request:
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;

    return 204;
 }
@michiel

This comment has been minimized.

Copy link
Owner Author

commented Sep 13, 2012

Updated with 204 return for OPTIONS (mrdevin) and wildcard '*' for Access-Control-Allow-Origin (epicserve).

@alexjs

This comment has been minimized.

Copy link

commented Nov 28, 2012

I've updated this in https://gist.github.com/4165271 to add a poor man's whitelist. I'm not really sure where having Access-Control-Allow-Origin as wildcard would cause too many issues, but some people may be extra conscious. We use a simple-ish regexp to match valid URLs. Please note that I haven't load tested this, so I don't know what kind of effect it'll have.

@remoe

This comment has been minimized.

Copy link

commented Dec 18, 2012

Thanks for this. I use:

add_header "Access-Control-Allow-Origin" $http_origin;

@nanonyme

This comment has been minimized.

Copy link

commented Feb 11, 2013

FWIW HTTP/1.1 RFC says response from OPTIONS is not cacheable. Doesn't that mean a browser must ignore your Access-Control-Max-Age header?

@kamoljan

This comment has been minimized.

Copy link

commented May 30, 2013

Thanks a lot!

@andreparames

This comment has been minimized.

Copy link

commented Oct 22, 2013

From MDN:

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding.

I've confirmed that at least Firefox will block a request with cookies if the Access-Control-Allow-Origin is set to '*'.

@puppeteer701

This comment has been minimized.

Copy link

commented Jul 8, 2014

This does not work for me

location / {
             add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

        root   share/nginx/html;
        proxy_pass         https://dddd.dd.com;
        proxy_set_header   Host dddd.dd.com;  

    }
@Meekohi

This comment has been minimized.

Copy link

commented Aug 18, 2014

You cannot use a wildcard Access-Control-Allow-Origin if you want to use xhrFields: {withCredentials:true} to send cookies/basicauth. In that case you must use the exact origin:

add_header "Access-Control-Allow-Origin" $http_origin;

@meawoppl

This comment has been minimized.

Copy link

commented Aug 22, 2014

When starting to use this Chrome will cache the earlier (CORS failed) requests. Reset the cache to get things working!

@TimmyCP

This comment has been minimized.

Copy link

commented Sep 20, 2014

Place this in nginx.conf or server blocks?

@aronwoost

This comment has been minimized.

Copy link

commented Jun 26, 2015

As stated in the docs add_header does not have any effect on 4xx and 5xx responses.

So save the two hours I just wasted and add always to your add_header (works with nginx 1.7.5+).

@brupm

This comment has been minimized.

Copy link

commented Jul 1, 2015

By adding this CORS block to my nginx config I now see my initial OPTIONS request followed by an identical GET request (incorrect duplicate) - Any idea what could be causing this?

https://gist.github.com/brupm/1b2c69cbf8f9612ee304

I suspect it's the return 204 line.

@niksmac

This comment has been minimized.

Copy link

commented Aug 18, 2015

There is a better page http://enable-cors.org/server.html

@GromNaN

This comment has been minimized.

Copy link

commented Dec 11, 2015

If you use a cache server, you must add a Vary: Origin to the response.

add_header "Access-Control-Allow-Origin" $http_origin;
add_header "Vary" "Origin";
@yinyanfr

This comment has been minimized.

Copy link

commented Feb 3, 2016

where do i put them?

@hasangilak

This comment has been minimized.

Copy link

commented May 11, 2016

for anybody on ubuntu first install
sudo apt-get install nginx-extras
and then
more_set_headers 'Access-Control-Allow-Origin: *';
more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS';
more_set_headers 'Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

turn all add_header into more_set_headers
and it will work ;)

@rowen17

This comment has been minimized.

Copy link

commented May 17, 2016

On add_header, if your server will intentionally throw status code other than 200, 201, 204, 206, 301, 302, 303, 304, or 307 (Ex. 400 or 422) you should add always on each line

So instead of

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';

Use

add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;

Source

@maxim25

This comment has been minimized.

Copy link

commented Jun 2, 2016

When I add

add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;

I get:
nginx: [emerg] invalid number of arguments in "add_header" directive in /etc/nginx/sites-enabled/foobar:12
nginx: configuration file /etc/nginx/nginx.conf test failed

Any idea?

@Skydev0h

This comment has been minimized.

Copy link

commented Jun 5, 2016

@maxim25, Are you sure that your nginx is 1.7.5 or newer?

@marianacristina666

This comment has been minimized.

Copy link

commented Sep 2, 2016

If 'Access-Control-Allow-Credentials' is set "TRUE"
the wildcard (*) in the Allow-Origin dont work!

@loustler

This comment has been minimized.

Copy link

commented Sep 5, 2016

Thanks.
It is so useful and helpful for me.

@tomleader

This comment has been minimized.

Copy link

commented Oct 12, 2016

Line 28

add_header 'Content-Type' 'text/plain charset=UTF-8';

It seems the semicolon is missing, maybe ' text/plain; charset=UTF-8' is more standard

@Cervenka

This comment has been minimized.

Copy link

commented Oct 18, 2016

In case you want to use the wildcard origin where possible but also allow credentials if the origin was sent along use following:

set $acac true;
if ($http_origin = ''){
    set $acac false;
    set $http_origin "*";
 }
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials $acac;
@x2es

This comment has been minimized.

Copy link

commented Oct 24, 2016

why do you specify content-type related headers if no body for 204 response?
https://gist.github.com/michiel/1064640#file-cors-nginx-conf-L28-L29

@gansbrest

This comment has been minimized.

Copy link

commented Apr 17, 2017

Here is shorter version of access control allow origin for Nginx that should get you started.

@GraniteConsultingReviews

This comment has been minimized.

Copy link

commented Sep 1, 2017

I having problem in this code This giving me error.

@defaultwp

This comment has been minimized.

Copy link

commented Nov 4, 2017

I have put this code in location inside /site-enabled/ but its still giving error on http://defaultwallpaper.com Please help.

@hasangilak

This comment has been minimized.

Copy link

commented May 5, 2018

syntax error. missing closing ' in checking OPTIONS. 'Content-Length should be 'Content-Length'
add_header 'Content-Length 0;

@hasantayyar

This comment has been minimized.

Copy link

commented Jun 14, 2018

@nikitasius

This comment has been minimized.

Copy link

commented Jan 30, 2019

set $cors_origin "https://your.domain";

if ($http_origin ~* ^(https?://[\w\.\-]+(:\d+)?)/?.*?$  ) {
	set $cors_origin $1;
}
	
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header Access-Control-Allow-Headers 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
  • Access-Control-Allow-Methods/Access-Control-Allow-Headers use what you prefer.
  • this way (as all ways with http_origin) required Origin header to be sent to server.
  • if no Origin or trash values - it will use default (the hardcoded value https://your.domain)
@joeyhub

This comment has been minimized.

Copy link

commented May 21, 2019

set $cors_origin "https://your.domain";

If you want a wild card domain, I'd set the default to that. The problem is, the origin header isn't always set from what I'm seeing. Vary seems to fix that.

The always directive just means use it for any status code.

That can be some confusion as not everyone who wants "withCredentials" actually wants anything to do with credentials so the security concern goes poof.

There's another option not included of also falling back to the referrer. It's really hard to find out how if actually works in nginx. Nginx configuration doesn't appear to make use of an ordered map or ordered list and the most prevalent documentation on the matter is confusing.

Once you need to go into if space, you might find yourself really wanting a module for this. If the sample you posted goes into something with another if statement then it can be wiped out if another if matches.

My instinct for security also tells me that you might want to validate the origin header though I have to wonder how far to really go with this. Can the user inject anything malicious? If they try to inject a new line then they'll just be sending another header rather than injecting a response header. I suppose the only thing they might do with something reflecting what's sent is try to exploit some client header handling exploit which seems a bit far fetched (and the use of . doesn't do much to prevent that).

if ($http_origin ~* ^(https?://[\w\.\-]+(:\d+)?)/?.*?$ ) { isn't even valid nginx syntax. I don't know what regex it's supporting but it looks like it's bailing on valid perl/pcre regex for this line.

@alexisrolland

This comment has been minimized.

Copy link

commented May 26, 2019

I'm facing the following error message. Any idea how to solve it please?

Access to XMLHttpRequest at 'https://localhost:8080/sockjs-node/info?t=1558864429094' from origin 'https://localhost' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Here is my config:

location /sockjs-node/ {
        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;
        }
        if ($request_method = 'POST') {
          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-Expose-Headers' 'Content-Length,Content-Range';
        }
        if ($request_method = 'GET') {
          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-Expose-Headers' 'Content-Length,Content-Range';
        }

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://app/sockjs-node;
      }

I have also tried with the following in all 3 "if" blocks:

add_header "Access-Control-Allow-Origin" $http_origin;

I get the same error message as above.

I ahve also added the following in all 3 "if" blocks in addition to "$http_origin":

add_header 'Access-Control-Allow-Credentials' 'true';

I get the following error message:

sockjs.js?3600:1605 POST https://localhost:8080/sockjs-node/718/n0jb5hss/xhr_streaming?t=1558864860566 404

Access to XMLHttpRequest at 'https://localhost:8080/sockjs-node/718/n0jb5hss/xhr_streaming?t=1558864860566' from origin 'https://localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

GET https://localhost:8080/sockjs-node/718/2rgh44pm/eventsource 404

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.