148

How do I set the Access-Control-Allow-Origin header so I can use web-fonts from my subdomain on my main domain?


Notes:

You'll find examples of this and other headers for most HTTP servers in the HTML5BP Server Configs projects https://github.com/h5bp/server-configs

170

Nginx has to be compiled with http://wiki.nginx.org/NginxHttpHeadersModule (default on Ubuntu and some other Linux distros). Then you can do this

location ~* \.(eot|ttf|woff|woff2)$ {
    add_header Access-Control-Allow-Origin *;
}
  • Follow this instructions in case you want want to implement the same solution on apache: stackoverflow.com/questions/11616306/… – camilo_u Feb 5 '13 at 16:46
  • 5
    That module seems to be compiled by default (at least on Ubuntu). – Steve Bennett Sep 8 '14 at 13:25
  • 1
    also compiled by default on amazon linux repo – Ross Sep 1 '15 at 21:16
  • 1
    In which file and location we should put this location directive ? – Sumit Arora Jan 17 '17 at 14:11
  • 1
    It doesn't work for me. Nginx 1.10.0, Ubuntu 16.04 – Omid Amraei Jun 17 '17 at 7:04
30

A more up-to-date answer:

#
# 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-CustomHeader,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-CustomHeader,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-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
}

source: https://michielkalkman.com/snippets/nginx-cors-open-configuration.html

You may also wish to add Access-Control-Expose-Headers (in the same format as Access-Control-Allow-Headers) in order to expose your custom and/or 'non-simple' headers to ajax requests.

Access-Control-Expose-Headers (optional) - The XMLHttpRequest 2 object has a 
getResponseHeader() method that returns the value of a particular response 
header. During a CORS request, the getResponseHeader() method can only access 
simple response headers. Simple response headers are defined as follows:

    Cache-Control
    Content-Language
    Content-Type
    Expires
    Last-Modified
    Pragma
 If you want clients to be able to access other headers, you have to use the
 Access-Control-Expose-Headers header. The value of this header is a comma-
 delimited list of response headers you want to expose to the client.

-http://www.html5rocks.com/en/tutorials/cors/

Configs for other web servers http://enable-cors.org/server.html

  • 1
    Any way to not have to repeat these lines for every location? Can we put it under the server {} block? – geoyws Oct 11 '15 at 5:05
  • @geoyws (without the @ I didnt get a notification); you could put it above location, thats fine :) – Chris McKee Dec 17 '15 at 15:12
  • access-control-expose-headers is missing here – chovy Dec 23 '15 at 19:45
  • @chovy its an optional header to expose non defaults to ajax requests but I can see it tripping people up so duly added. Ta – Chris McKee Jan 4 '16 at 10:13
  • 3
    Please avoid using if in nginx - even the official manual discourages it. – aggregate1166877 May 22 '18 at 10:43
10

Here is the article that I wrote which avoids some of the duplication for GET|POST. It should get you going with CORS in Nginx.

nginx access control allow origin

Here is the sample snippet from the post:

server {
  listen        80;
  server_name   api.test.com;


  location / {

    # Simple requests
    if ($request_method ~* "(GET|POST)") {
      add_header "Access-Control-Allow-Origin"  *;
    }

    # Preflighted requests
    if ($request_method = OPTIONS ) {
      add_header "Access-Control-Allow-Origin"  *;
      add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD";
      add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept";
      return 200;
    }

    ....
    # Handle request
    ....
  }
}
  • 2
    As per SF policy you need to copy the information into the post, not just link to it. Websites can disappear at any time, which would be loss of information. – Tim Apr 17 '17 at 22:07
  • 1
    Valid point @tim, updated to include the code – gansbrest Apr 17 '17 at 22:58
  • Consider using status code 204 No content as it seems more appropriate. – Slava Fomin II Jan 21 at 11:00
7

Firstly, let me say that @hellvinz answer is working for me:

location ~* \.(eot|ttf|woff|woff2)$ {
    add_header Access-Control-Allow-Origin *;
}

However, I have decided to answer this question with a separate answer as I only managed to get this solution working after putting in about ten more hours looking for a solution.

It seems that Nginx doesn't define any (correct) font MIME types by default. By following this tuorial I found I could add the following:

application/x-font-ttf           ttc ttf;
application/x-font-otf           otf;
application/font-woff            woff;
application/font-woff2           woff2;
application/vnd.ms-fontobject    eot;

To my etc/nginx/mime.types file. As stated, the above solution then worked.

2

Nginx's traditional add_header directive doesn't work with 4xx responses. As we still want to add custom headers to them, we need to install the ngx_headers_more module to be able to use the more_set_headers directive, which also works with 4xx responses.

sudo apt-get install nginx-extras

Then use more_set_headers in the nginx.conf file, i have pasted my sample below

server {
    listen 80;
    server_name example-site.com;
    root "/home/vagrant/projects/example-site/public";

    index index.html index.htm index.php;

    charset utf-8;

    more_set_headers 'Access-Control-Allow-Origin: $http_origin';
    more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE, HEAD';
    more_set_headers 'Access-Control-Allow-Credentials: true';
    more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept,Authorization';

    location / {
        if ($request_method = 'OPTIONS') {
            more_set_headers 'Access-Control-Allow-Origin: $http_origin';
            more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE, HEAD';
            more_set_headers 'Access-Control-Max-Age: 1728000';
            more_set_headers 'Access-Control-Allow-Credentials: true';
            more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept,Authorization';
            more_set_headers 'Content-Type: text/plain; charset=UTF-8';
            more_set_headers 'Content-Length: 0';
            return 204;
        }
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/example-site.com-error.log error;

    sendfile off;

    client_max_body_size 100m;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
    }

    location ~ /\.ht {
        deny all;
    }
}
0

In my case, using Rails 5, the only working solution has been adding the rack-cors gem. Like so:

in /Gemfile

# Gemfile
gem 'rack-cors'

in config/initializers/cors.rb

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:4200'
    resource '*',
      headers: :any,
      methods: %i(get post put patch delete options head)
  end
end

source: https://til.hashrocket.com/posts/4d7f12b213-rails-5-api-and-cors

  • how does that help nginx serve static files? – Walf Oct 3 '18 at 4:52
  • I was using nginx as a reverse proxy to serve the rails 5 app. This is a particular case where the CORS restriction was not coming from nginx but from the origin Rails App behind it. – xyz Oct 3 '18 at 10:39

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.