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;
}
}
No Comment