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