2

My nginx version: nginx/1.4.6

I have an issue enabling CORS for multiple subdomains. I checked https://gist.github.com/algal/5480916 and http://rustyrazorblade.com/post/2013/2013-10-31-cors-with-wildcard-domains-and-nginx/ but both solutions doesn't work for me.

It looks like the regex

if ($http_origin ~* (.*\.mydomain.com)) {
    set $cors "true";
}

is not matching and $cors is not set to "true" and therefor add_header 'Access-Control-Allow-Origin' "$http_origin" won't be executed.

I also tried with regex

$http_origin ~* (https?://.*.mydomain.com)

or

$http_origin ~* https?://.*.mydomain.com

But in either case the regex doesn't match and $cors will never set to "true".

What am I missing?

My nginx configuration - domain name in curly braces (is getting replaced by Ansible):

upstream varnish {
  server localhost:80;
}

server {
    listen 443 default;
    server_name {{vhost}};

    ssl                  on;
    ssl_certificate      /etc/ssl/certs/ssl.{{domain}}.crt;
    ssl_certificate_key  /etc/ssl/private/{{domain}}.key;

    ssl_session_timeout  5m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    #ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    #ssl_prefer_server_ciphers   on;

    # workaround remote exploit. Fixed in 1.5.0, 1.4.1
    #
    # http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
        return 444;
    }

    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;

    proxy_redirect off;

    # CORS
    set $cors "";
    if ($http_origin ~* (.*\.{{domain}})) {
        set $cors "true";
    }

    location / {
            # Set the max size for file uploads (/admin, /webmail)
            client_max_body_size 10G;

            proxy_pass http://varnish;
            if ($cors = "true") {
                add_header 'Access-Control-Allow-Origin' "$http_origin";
                add_header 'Access-Control-Allow_Credentials' 'true';
                add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range, X-CSRF-Token';
                add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
            }

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

    }

    location = /50x.html {
        root   html;
    }

}
  • could you show us how the config looks like when Ansible replaced the variables? – unNamed Mar 29 '19 at 7:32
  • Did you test it with a POST instead of a GET? See my answer below! – Matthias Bohlen Aug 11 at 15:03
3

You can get around the limitation of only one subdomain by using this clever workaround that will allow all subdomains:

server {

    root /path/to/your/stuff;

    index index.html index.htm;

     set $cors "";

    if ($http_origin ~* (.*\.yoursweetdomain.com)) {
        set $cors "true";
    }

    server_name yoursweetdomain.com;

    location / {

        if ($cors = "true") {
            add_header 'Access-Control-Allow-Origin' "$http_origin";
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type';
        }


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

    }
}

Credit: http://rustyrazorblade.com/post/2013/2013-10-31-cors-with-wildcard-domains-and-nginx/

| improve this answer | |
  • did you read my original post/question? In my first phrase I mentioned that this link/source doesn't work for me. – StandardNerd Apr 1 '19 at 8:00
  • 1
    Nginx if is evil. – rafi Jul 24 '19 at 9:37
1

its been a year but, here is the solution that worked for me.

location / {
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  
    # Nginx doesn't support nested If statements, so we
    # concatenate compound conditions on the $cors variable
    # and process later

    # If request comes from allowed subdomain
    # (*.mckinsey.com) then we enable CORS
    if ($http_origin ~* (https?://.*\.mckinsey\.com(:[0-9]+)?$)) {
       set $cors "1";
    }
  
    # OPTIONS indicates a CORS pre-flight request
    if ($request_method = 'OPTIONS') {
       set $cors "${cors}o";
    }
  
    # Append CORS headers to any request from 
    # allowed CORS domain, except OPTIONS
    if ($cors = "1") {
       more_set_headers 'Access-Control-Allow-Origin: $http_origin';
       more_set_headers 'Access-Control-Allow-Credentials: true';
       proxy_pass      http://serverIP:serverPort;
    }
  
    # OPTIONS (pre-flight) request from allowed 
    # CORS domain. return response directly
    if ($cors = "1o") {
       more_set_headers 'Access-Control-Allow-Origin: $http_origin';
       more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE';
       more_set_headers 'Access-Control-Allow-Credentials: true';
       more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept';
       add_header Content-Length 0;
       add_header Content-Type text/plain;
       return 204;
    }
  
    # Requests from non-allowed CORS domains
       proxy_pass      http://serverIP:serverPort;
  }

Source: https://gist.github.com/bramswenson/51f0721dec22b9b258aea48b59e9a32c

| improve this answer | |
0

Try moving the check for $http_origin into your location block.

You can see the same in the first example link you gave.

The variable is probably first filled when the location block is called.

| improve this answer | |
  • moving the check for $http_origin into your location block doesn't change anything – StandardNerd Mar 28 '19 at 16:05
0

$http_origin contains the value of the "origin" field in the request header.

The reason why you might have the impression that it does not work is that you tested it with a request where the "origin" header field is empty. Example: Browsers do not set the origin field on GET requests, only on POST and maybe more...

For exact info, see https://stackoverflow.com/questions/42239643/when-do-browsers-send-the-origin-header-when-do-browsers-set-the-origin-to-null

So, the code above works perfectly OK because your GET requests do not need the CORS fields in the response header. GET works without those fields!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.