nginx add_header not working
There were two issues for me.
One is that nginx only processes the last add_header
it spots down a tree. So if you have an add_header
in the server
context, then another in the location
nested context, it will only process the add_header
directive inside the location
context. Only the deepest context.
From the NGINX docs on add_header:
There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.
Second issue was that the location / {}
block I had in place was actually sending nginx to the other location ~* (\.php)$
block (because it would repath all requests through index.php
, and that actually makes nginx process this php
block). So, my add_header
directives inside the first location directive were useless, and it started working after I put all the directives I needed inside the php location directive.
Finally, here's my working configuration to allow CORS in the context of an MVC framework called Laravel (you could change this easily to fit any PHP framework that has index.php
as a single entry point for all requests).
server { root /path/to/app/public; index index.php; server_name test.dev; # redirection to index.php location / { try_files $uri $uri/ /index.php?$query_string; } # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; # cors configuration # whitelist of allowed domains, via a regular expression # if ($http_origin ~* (http://localhost(:[0-9]+)?)) { if ($http_origin ~* .*) { # yeah, for local development. tailor your regex as needed set $cors "true"; } # apparently, the following three if statements create a flag for "compound conditions" if ($request_method = OPTIONS) { set $cors "${cors}options"; } if ($request_method = GET) { set $cors "${cors}get"; } if ($request_method = POST) { set $cors "${cors}post"; } # now process the flag if ($cors = 'trueget') { add_header 'Access-Control-Allow-Origin' "$http_origin"; add_header 'Access-Control-Allow-Credentials' 'true'; } if ($cors = 'truepost') { add_header 'Access-Control-Allow-Origin' "$http_origin"; add_header 'Access-Control-Allow-Credentials' 'true'; } if ($cors = 'trueoptions') { add_header 'Access-Control-Allow-Origin' "$http_origin"; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since'; add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain charset=UTF-8'; return 204; } } error_log /var/log/nginx/test.dev.error.log; access_log /var/log/nginx/test.dev.access.log; }
The gist for the above is at: https://gist.github.com/adityamenon/6753574
When I test the above add_header
settings with:
# nginx -t && service nginx reload
I get
nginx: [emerg] directive "add_header" is not terminated by ";" in
/etc/nginx/enabled-sites/example.com.conf:21
nginx: configuration file /etc/nginx/nginx.conf test failed
So the complain is reagarding this line:
add_header PS 1
missing the semi-colon (;
)
To test the headers I like to use
# curl -I http://example.com
According to the ngx_http_headers_module manual
syntax: add_header name value;
default: —
context: http, server, location, if in location
I further tried
add_header X-test-A 1;
add_header "X-test-B" "2";
add_header 'X-test-C' '3';
in the context of http
, server
and location
, but it only showed up in the server
context.
I had the issue of not getting the response header due to the response code not within the allowed range, unless you specify the "always" keyword after the header value.
From the official docs:
Adds the specified field to a response header provided that the response code equals 200, 201, 204, 206, 301, 302, 303, 304, 307, or 308. The value can contain variables.
Firstly, let me say that after looking around the web, I found this answer popping up everywhere:
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 particular 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. Obviously, this answer is aimed at sharing fonts but it's worth noting that the MIME types may not be defined in Nginx.