{"id":326,"date":"2015-03-12T15:18:22","date_gmt":"2015-03-12T15:18:22","guid":{"rendered":"https:\/\/www.peopleperhour.com\/engineering\/?p=326"},"modified":"2015-03-12T16:03:22","modified_gmt":"2015-03-12T16:03:22","slug":"nginx-enable-cors-for-specific-domains","status":"publish","type":"post","link":"https:\/\/www.peopleperhour.com\/engineering\/2015\/03\/12\/nginx-enable-cors-for-specific-domains\/","title":{"rendered":"nginx &#8211; enable cors for specific domains"},"content":{"rendered":"<p>Enabling cors using nginx is simple&#8230; if you have done it once.<\/p>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<h3>Gotcha &#8211; SOS (read this if you want to keep sane)<\/h3>\n<p>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 <a title=\"nginx ifisevil\" href=\"http:\/\/wiki.nginx.org\/IfIsEvil\" target=\"_blank\">nginx ifisevil<\/a>.<\/p>\n<p>The below code causes nginx to return a 404.<\/p>\n<pre class=\"lang:sh decode:true \" title=\"nginx if is evil demonstration\">location \/ {\r\n    if ($http_origin ~* (https?:\/\/[^\/]*\\.example\\.com(:[0-9]+)?)) {\r\n        add_header 'Access-Control-Allow-Origin' \"$http_origin\";\r\n    }\r\n\r\n    try_files $uri $uri\/ \/index.php?$args;\r\n}<\/pre>\n<p>The reason is that nginx &#8220;if statements&#8221; are vicious and should only be used inside a location context using a return or rewrite directive.<\/p>\n<p>&nbsp;<\/p>\n<h3>Alternative (that works)<\/h3>\n<p>Instead of using the &#8220;if statement&#8221; in the location context to evaluate http_origin we use a map directive in our http context.<\/p>\n<pre class=\"lang:sh decode:true \" title=\"nginx map directive usage to detect subdomains\">http {\r\n    map $http_origin $cors_header {\r\n\r\n        default     \"\"; #empty causes the Access-Control-Allow-Origin header to be empty\r\n\r\n        ~*localhost:8001 \"$http_origin\";\r\n        ~*.example.com   \"$http_origin\";\r\n   \r\n    }\r\n}<\/pre>\n<p>Then we use the value of the map ($cors_header) in our location context.<\/p>\n<pre class=\"lang:php decode:true\" title=\"nginx location context to allow access-control-allow-origin\">location \/ {\r\n\r\n    add_header 'Access-Control-Allow-Origin' $cors_header;\r\n\r\n    try_files $uri $uri\/ \/index.php?$args;\r\n}<\/pre>\n<p>Apart from the Access-Control-Allow-Origin header one can also include the Access-Control-Allow-Credentials and Access-Control-Expose-Headers .<\/p>\n<p><strong>Complete code example:<\/strong><\/p>\n<pre class=\"lang:sh decode:true \" title=\"complete nginx sample to allow cors from specific domains\">user www-data;\r\nworker_processes 4;\r\npid \/run\/nginx.pid;\r\n\r\ndaemon off;\r\n\r\nevents {\r\n\tworker_connections 2048;\r\n\tmulti_accept on;\r\n\tuse epoll;\r\n}\r\n\r\nhttp {\r\n\tserver_tokens off;\r\n\tsendfile on;\r\n\ttcp_nopush on;\r\n\ttcp_nodelay on;\r\n\tkeepalive_timeout 15;\r\n\ttypes_hash_max_size 2048;\r\n\tinclude \/etc\/nginx\/mime.types;\r\n\tdefault_type application\/octet-stream;\r\n\r\n\tgzip on;\r\n\tgzip_disable \"msie6\";\r\n\r\n\r\n        map $http_origin $cors_header {\r\n\r\n           default     \"\"; #empty causes the Access-Control-Allow-Origin header to be empty\r\n\r\n           ~*localhost:8001 \"$http_origin\";\r\n           ~*.example.com   \"$http_origin\";\r\n\r\n        }\r\n\r\n\topen_file_cache max=100;\r\n}\r\n\r\nserver {\r\n\r\n    charset utf-8;\r\n    client_max_body_size 128M;\r\n\r\n    listen 80;\r\n    root \/var\/www\/web\/;\r\n    index index.php;\r\n\r\n    server_name localhost;\r\n\r\n    location \/ {\r\n\r\n        add_header 'Access-Control-Allow-Origin' $cors_header;\r\n\r\n        try_files $uri $uri\/ \/index.php?$args;\r\n    }\r\n\r\n    location ~ \\.php$ {\r\n\r\n        # NOTE: You should have \"cgi.fix_pathinfo = 0;\" in php.ini\r\n        fastcgi_pass php-fpm:9000;\r\n        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\r\n        fastcgi_index index.php;\r\n        include fastcgi_params;\r\n    }\r\n\r\n    location ~ \/\\.(ht|svn|git) {\r\n        deny all;\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Enabling cors using nginx is simple&#8230; 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. &nbsp; Gotcha &#8211; SOS (read this if you want&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[23,33],"tags":[35,34],"class_list":["post-326","post","type-post","status-publish","format-standard","hentry","category-devops-2","category-nginx","tag-cors","tag-nginx"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p2CA4w-5g","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/posts\/326","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/comments?post=326"}],"version-history":[{"count":9,"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/posts\/326\/revisions"}],"predecessor-version":[{"id":335,"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/posts\/326\/revisions\/335"}],"wp:attachment":[{"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/media?parent=326"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/categories?post=326"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.peopleperhour.com\/engineering\/wp-json\/wp\/v2\/tags?post=326"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}