Reputation: 447
Given: 64bit Amazon Linux 2015.09 v2.0.4 running Ruby 2.2 (Passenger Standalone) behind ELB. Rails 4.25 in production with default asset pipeline settings.
I have noticed that cache control headers aren't set for the static assets (css, js). I expect something like
public, max-age=31557600
or similar, instead i get the following:
> curl -I http://xxx.elasticbeanstalk.com/assets/application-7e1554f74fd0352dbb5ccdbba5d50d1c1f28a4ca751e9ec8371bd55e28885f77.css
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 16557
Content-Type: text/css
Date: Tue, 05 Jan 2016 21:16:53 GMT
ETag: "568bde8a-40ad"
Last-Modified: Tue, 05 Jan 2016 15:17:30 GMT
Server: nginx/1.6.2
Connection: keep-alive
Setting headers in Rails and instructing it to serve assets through the app, e.g.
# production.rb
config.static_cache_control = "public, max-age=#{1.year.to_i}"
config.serve_static_files = true
doesn't make any difference, assets are still served by nginx.
In /tmp/passenger-standalone.1d76nuz/config
(not sure if thats the active config though) i see the following:
server {
...
# Rails asset pipeline support.
location ~ "^/assets/.+-[0-9a-f]{32}\..+" {
error_page 490 = @static_asset;
error_page 491 = @dynamic_request;
recursive_error_pages on;
if (-f $request_filename) {
return 490;
}
if (!-f $request_filename) {
return 491;
}
}
location @static_asset {
gzip_static on;
expires max;
add_header Cache-Control public;
add_header ETag "";
}
location @dynamic_request {
passenger_enabled on;
}
}
Would appreciate any advice. I'm trying to leverage CloudFront to serve assets, but it is a lot less efficient without proper cache control headers.
Thanks! And Happy 2016!
Upvotes: 0
Views: 1539
Reputation: 11
For me it was a result of using sprockets 3 with passenger 4 as they switched to 64 byte digests
location ~ "^/assets/.+-[0-9a-f]{32}\..+" {
should be changed to
location ~ "^/assets/.+-([0-9a-f]{32}|[0-9a-f]{64})\..+" {
You should be able to use this
# .ebextensions/fix-passenger-nginx.config
commands:
fixup_passenger_nginx:
command: |
set -xe
EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
cp $EB_SUPPORT_DIR/conf/nginx_config.erb $EB_SUPPORT_DIR/conf/nginx_config.erb.bak
perl -pe 's/\Q^\/assets\/.+-[0-9a-f]{32}\..+/\^\/assets\/.+-([0-9a-f]{32}|[0-9a-f]{64})\\..+\E/g' < $EB_SUPPORT_DIR/conf/nginx_config.erb.bak > $EB_SUPPORT_DIR/conf/nginx_config.erb
cp $EB_SUPPORT_DIR/conf/nginx_config_healthd.erb $EB_SUPPORT_DIR/conf/nginx_config_healthd.erb.bak
perl -pe 's/\Q^\/assets\/.+-[0-9a-f]{32}\..+/\^\/assets\/.+-([0-9a-f]{32}|[0-9a-f]{64})\\..+\E/g' < $EB_SUPPORT_DIR/conf/nginx_config_healthd.erb.bak > $EB_SUPPORT_DIR/conf/nginx_config_healthd.erb
Upvotes: 0
Reputation: 13
The file that you should override is on
/opt/elasticbeanstalk/support/conf/nginx_config.erb
.
To do it, just create ebextensions files like below.
files:
'/opt/elasticbeanstalk/support/conf/nginx_config.erb':
mode: '644'
owner: 'root'
group: 'root'
content: |
#!/bin/ruby
master_process on;
worker_processes auto;
daemon on;
error_log '<%= @options[:log_file] %>' <% if debugging? %>info<% end %>;
pid '<%= @options[:pid_file] %>';
<% if Process.euid == 0 %>
<% if @options[:user] %>
<%# Run workers as the given user. The master process will always run as root and will be able to bind to any port. %>
user <%= @options[:user] %> <%= default_group_for(@options[:user]) %>;
<% else %>
<%# Prevent running Nginx workers as nobody. %>
user <%= current_user %> <%= default_group_for(current_user) %>;
<% end %>
<% end %>
events {
worker_connections 1024;
}
http {
log_format debug '[$time_local] $msec "$request" $status conn=$connection sent=$bytes_sent body_sent=$body_bytes_sent';
include '<%= PhusionPassenger.resources_dir %>/mime.types';
passenger_ruby <%= PlatformInfo.ruby_command %>;
passenger_root '<%= location_config_filename %>';
passenger_abort_on_startup_error on;
passenger_ctl cleanup_pidfiles <%= serialize_strset("#{@temp_dir}/temp_dir_toucher.pid") %>;
passenger_user_switching off;
passenger_max_pool_size <%= @options[:max_pool_size] %>;
passenger_min_instances <%= @options[:min_instances] %>;
log_format healthd '$msec"$uri"'
'$status"$request_time"$upstream_response_time"'
<% if @options[:user] %>
passenger_user <%= @options[:user] %>;
passenger_default_user <%= @options[:user] %>;
passenger_analytics_log_user <%= @options[:user] %>;
<% else %>
passenger_user <%= current_user %>;
passenger_default_user <%= current_user %>;
passenger_analytics_log_user <%= current_user %>;
<% end %>
<% if debugging? %>passenger_log_level 2;<% end %>
<% if @options[:temp_dir] %>passenger_temp_dir '<%= @options[:temp_dir] %>';<% end %>
<% if @options[:rolling_restarts] %>passenger_rolling_restarts on;<% end %>
<% if @options[:resist_deployment_errors] %>passenger_resist_deployment_errors on;<% end %>
<% if !@options[:load_shell_envvars] %>passenger_load_shell_envvars off;<% end %>
<% if !@options[:friendly_error_pages].nil? -%>
passenger_friendly_error_pages <%= boolean_config_value(@options[:friendly_error_pages]) %>;
<% end %>
<% if @options[:union_station_gateway_address] %>
union_station_gateway_address <%= @options[:union_station_gateway_address] %>;
union_station_gateway_port <%= @options[:union_station_gateway_port] %>;
union_station_gateway_cert -;
<% end %>
default_type application/octet-stream;
types_hash_max_size 2048;
server_names_hash_bucket_size 64;
client_max_body_size 1024m;
access_log off;
keepalive_timeout 60;
underscores_in_headers on;
gzip on;
gzip_comp_level 4;
gzip_proxied any;
gzip_types text/html text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
<% if @apps.size > 1 %>
server {
<% if @options[:ssl] %>
<% if @options[:ssl_port] %>
listen <%= nginx_listen_address %>;
listen <%= nginx_listen_address_with_ssl_port %> ssl;
<% else %>
listen <%= nginx_listen_address %> ssl;
<% end %>
<% else %>
listen <%= nginx_listen_address %>;
<% end %>
root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
}
<% end %>
<% if @options[:ping_port] %>
server {
listen <%= nginx_listen_address(@options, true) %>;
root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
}
<% end %>
<% for app in @apps %>
server {
access_log '<%= @options[:log_file].sub('passenger.log','access.log') %>' combined;
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
}
access_log /var/app/support/logs/healthd/application.log.$year-$month-$day-$hour healthd;
<% if app[:ssl] %>
<% if app[:ssl_port] %>
listen <%= nginx_listen_address(app) %>;
listen <%= nginx_listen_address_with_ssl_port(app) %> ssl;
<% else %>
listen <%= nginx_listen_address(app) %> ssl;
<% end %>
<% else %>
listen <%= nginx_listen_address(app) %>;
<% end %>
server_name <%= app[:server_names].join(' ') %>;
<% if app[:static_files_dir] %>
root '<%= app[:static_files_dir] %>';
<% else %>
root '<%= app[:root] %>/public';
<% end %>
passenger_app_root '<%= app[:root] %>';
passenger_enabled on;
passenger_app_env <%= app[:environment] %>;
passenger_spawn_method <%= app[:spawn_method] %>;
<% if app[:app_type] %>passenger_app_type <%= app[:app_type] %>;<% end %>
<% if app[:startup_file] %>passenger_startup_file <%= app[:startup_file] %>;<% end %>
<% if app[:concurrency_model] != DEFAULT_CONCURRENCY_MODEL %>passenger_concurrency_model <%= app[:concurrency_model] %>;<% end %>
<% if app[:thread_count] != DEFAULT_THREAD_COUNT %>passenger_thread_count <%= app[:thread_count] %>;<% end %>
<% if app[:min_instances] %>passenger_min_instances <%= app[:min_instances] %>;<% end %>
<% if app[:restart_dir] %>passenger_restart_dir '<%= app[:restart_dir] %>';<% end %>
<% if @options[:sticky_sessions] %>passenger_sticky_sessions on;<% end %>
<% if @options[:sticky_sessions_cookie_name] %>passenger_sticky_sessions_cookie_name '<%= sticky_sessions_cookie_name %>';<% end %>
<% if app[:union_station_key] %>
union_station_support on;
union_station_key <%= app[:union_station_key] %>;
<% end %>
<% if app[:ssl] %>
ssl_certificate <%= app[:ssl_certificate] %>;
ssl_certificate_key <%= app[:ssl_certificate_key] %>;
<% end %>
location ~ "^/assets/.+-[0-9a-f]{32}\..+" {
error_page 490 = @static_asset;
error_page 491 = @dynamic_request;
recursive_error_pages on;
if (-f $request_filename) {
return 490;
}
if (!-f $request_filename) {
return 491;
}
}
location ~ ^/assets/ {
gzip_static on;
add_header Cache-Control 'public,max-age=31536000';
add_header ETag "";
}
location @static_asset {
gzip_static on;
expires max;
add_header Cache-Control 'public, max-age=10800';
add_header ETag "";
}
location @dynamic_request {
passenger_enabled on;
}
}
passenger_pre_start http://<%= nginx_listen_address(app) %>;
<% end %>
}
I hope it can help people that facing similar problem. Regards
Upvotes: 1