Elastic Beanstalk: заголовки Cache-Control не установлены для ресурсов Rails (автономная версия Passenger)

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.

Я заметил, что заголовки управления кешем не установлены для статических ресурсов (css, js). Я ожидаю чего-то вроде public, max-age=31557600 или чего-то подобного, но вместо этого получаю следующее:

> 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

Установка заголовков в Rails и указание ему обслуживать ресурсы через приложение, например

# production.rb
config.static_cache_control = "public, max-age=#{1.year.to_i}"
config.serve_static_files = true

не имеет значения, ресурсы по-прежнему обслуживаются nginx.

В /tmp/passenger-standalone.1d76nuz/config (хотя не уверен, что это активная конфигурация) я вижу следующее:

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;
    }
}

Буду признателен за любой совет. Я пытаюсь использовать CloudFront для обслуживания ресурсов, но он намного менее эффективен без правильных заголовков управления кешем.

Спасибо! И счастливого 2016 года!


person Elder    schedule 07.01.2016    source источник


Ответы (2)


Файл, который вы должны переопределить, находится на /opt/elasticbeanstalk/support/conf/nginx_config.erb.

Для этого просто создайте файлы ebextensions, как показано ниже.

  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 %>
        }

Надеюсь, это поможет людям, столкнувшимся с подобной проблемой. С Уважением

person Slamet Kristanto Tirto Utomo    schedule 05.06.2016

Для меня это было результатом использования звездочки 3 с пассажиром 4, поскольку они перешли на 64-байтовые дайджесты.

 location ~ "^/assets/.+-[0-9a-f]{32}\..+" {

следует изменить на

  location ~ "^/assets/.+-([0-9a-f]{32}|[0-9a-f]{64})\..+" {

https://github.com/phusion/passenger/commit/1df42bb4d02de92837f05fba0d68622fe34a08bb#diff-145654601fa1feaf56f581962f35367d

Вы должны уметь использовать это

# .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
person throttleup    schedule 23.05.2018