Blog

nginx – enable cors for specific domains

Enabling cors using nginx is simple… if you have done it once.

This is a small and quick-start example of how it can be done and how you can restrict access to a specific number domains.

 

Gotcha – SOS (read this if you want to keep sane)

Browsing around we found a number of ways to enable cors using nginx but they had a very nasty gotcha which has been described as nginx ifisevil.

The below code causes nginx to return a 404.

location / {
    if ($http_origin ~* (https?://[^/]*\.example\.com(:[0-9]+)?)) {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
    }

    try_files $uri $uri/ /index.php?$args;
}

The reason is that nginx “if statements” are vicious and should only be used inside a location context using a return or rewrite directive.

 

Alternative (that works)

Instead of using the “if statement” in the location context to evaluate http_origin we use a map directive in our http context.

http {
    map $http_origin $cors_header {

        default     ""; #empty causes the Access-Control-Allow-Origin header to be empty

        ~*localhost:8001 "$http_origin";
        ~*.example.com   "$http_origin";
   
    }
}

Then we use the value of the map ($cors_header) in our location context.

location / {

    add_header 'Access-Control-Allow-Origin' $cors_header;

    try_files $uri $uri/ /index.php?$args;
}

Apart from the Access-Control-Allow-Origin header one can also include the Access-Control-Allow-Credentials and Access-Control-Expose-Headers .

Complete code example:

user www-data;
worker_processes 4;
pid /run/nginx.pid;

daemon off;

events {
	worker_connections 2048;
	multi_accept on;
	use epoll;
}

http {
	server_tokens off;
	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 15;
	types_hash_max_size 2048;
	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	gzip on;
	gzip_disable "msie6";


        map $http_origin $cors_header {

           default     ""; #empty causes the Access-Control-Allow-Origin header to be empty

           ~*localhost:8001 "$http_origin";
           ~*.example.com   "$http_origin";

        }

	open_file_cache max=100;
}

server {

    charset utf-8;
    client_max_body_size 128M;

    listen 80;
    root /var/www/web/;
    index index.php;

    server_name localhost;

    location / {

        add_header 'Access-Control-Allow-Origin' $cors_header;

        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {

        # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
        fastcgi_pass php-fpm:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ /\.(ht|svn|git) {
        deny all;
    }

}

 

 

Tags > ,

No Comment

Post A Comment