So I've replaced Passenger with Puma for a Rails app, and i just noticed that i now have issues with the cdn assets, they now give CORS errors.
Back when i was using Passenger i had the following configs for Nginx:
server {
server_name mysite.com;
root /var/www/mysite.com/public;
client_max_body_size 4000M;
passenger_enabled on;
rails_env production;
location ~* ^/cdn/ {
add_header Access-Control-Allow-Origin *;
expires 364d;
add_header Pragma public;
add_header Cache-Control "public";
break;
}
location ~* ^/assets/ {
# Per RFC2616 - 1 year maximum expiry
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
expires 1y;
add_header Cache-Control public;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
listen 443 ssl; # managed by Certbot
#the rest of the certbot ssl stuff
}
I then changed the configs to this to make it work with Puma and unix sockets:
upstream puma {
server unix:///var/www/mysite.com/shared/sockets/puma.sock;
}
server {
server_name mysite.com;
root /var/www/mysite.com/public;
client_max_body_size 4000M;
location / {
try_files $uri @app;
}
location ~* ^/cdn/ {
add_header Access-Control-Allow-Origin *;
expires 364d;
add_header Pragma public;
add_header Cache-Control "public";
break;
}
location ~* ^/assets/ {
# Per RFC2616 - 1 year maximum expiry
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
expires 1y;
add_header Cache-Control public;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
listen 443 ssl; # managed by Certbot
#ssl stuff
location @app {
proxy_pass http://puma;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_headers_hash_max_size 512;
proxy_headers_hash_bucket_size 128;
proxy_redirect off;
}
}
This works fine but then i noticed that the cdn urls were giving 404, so i updated the cdn location to this (i added try_files $uri @app;
):
location ~* ^/cdn/ {
add_header Access-Control-Allow-Origin *;
expires 364d;
add_header Pragma public;
add_header Cache-Control "public";
try_files $uri @app;
break;
}
This now works but i get CORS errors so it seems the headers are not getting set.
My guess is the try_files
ignores what was set before it is called, so i tried setting the proxy header for access control inside the location @app
(by adding proxy_set_header Access-Control-Allow-Origin *;
) but i still get the errors.
What's the correct way to go about this?
CodePudding user response:
There is no sense in trying to add the response headers with the proxy_set_header
directive - it is designed for adding/changing headers for the request that will be sent to the upstream. To add the response headers, no matter is it a static or a proxied location, use the add_header
one. To add headers conditionally, lets say depending on a request URI, you can use the map
block(s):
map $uri $expires {
~^/cdn/ 1y;
default off;
}
map $uri $cache_control {
~^/cdn/ public;
# default will be an empty value
}
map $uri $allow_origin {
~^/cdn/ *;
# default will be an empty value
}
However in terms of performance, since all the map
-derived variables are evaluated only once per request, matching regex pattern only once can be slightly more performant:
map $cache $expires {
1 1y;
default off;
}
map $cache $cache_control {
1 public;
}
map $cache $allow_origin {
1 *;
}
map $uri $cache {
~^/cdn/ 1;
}
Next, in your @app
location you can use the following:
location @app {
proxy_pass http://puma;
expires $expires;
add_header Cache-Control $cache_control;
add_header Access-Control-Allow-Origin $allow_origin;
# ... proxy_set_... and other upstream setup here
}
If evaluated variable used in an add_header
directive will be empty, nginx won't add a header with an empty value - instead it won't add such a header at all.
A few notes about your current config:
Using those kind of regex locations like
location ~ ^/cdn/ { ... }
orlocation ~ ^/assets/ { ... }
in favor of prefix locationslocation /cdn/ { ... }
orlocation /assets/ { ... }
makes no sense and only a performance impact (due to the PCRE library is involved when it isn't nessesary).That
break
directive at the end of static locations does nothing since there are no any directives from the rewrite module there which execution should be stopped.