V2.1: Using a CDN


Content delivery network (CDN)

You can configure Hanami to serve your assets from a content delivery network (CDN). This approach is useful in production to improve the performance of serving your static assets.

To configure an assets CDN, use config.assets.base_url in your app class.

# config/app.rb

module Bookshelf
  class App < Hanami::App
    environment :production do
      config.assets.base_url = "https://some-cdn.net/my-site"
    end
  end
end

Once you have configured this base_url, all assets helpers will return absolute URLs prefixed by this base URL.

asset_url("app.js")
# => "https://some-cdn.net/my-site/assets/app-LSLFPUMX.js"

Content Security Policy (CSP)

By default, Hanami sets a Content-Security-Policy header that does not allow for the execution of external JavaScript code.

To permit code hosted on your CDN, use config.actions.content_security_policy in your app class.

# config/app.rb

module Bookshelf
  class App < Hanami::App
    environment :production do
      config.actions.content_security_policy[:script_src] += " https://some-cdn.net"
      config.assets.base_url = "https://some-cdn.net/my-site"
    end
  end
end

Subresource integrity

A CDN can dramatically improve page speed, but it can potentially open a security breach. If the CDN that is compromised and serves bad JavaScript files or stylesheets, we expose our users to security attacks like Cross-Site Scripting (XSS).

To solve this problem, browser vendors use a defense called Subresource Integrity. When enabled, the browser verifies that the checksum of the downloaded file matches a checksum in the HTML document requesting it.

To enable subresource integrity, use config.assets.subresource_integrity in your app class, choosing one or more checksum algorithms.

# config/app.rb

module Bookshelf
  class App < Hanami::App
    environment :production do
      config.assets.subresource_integrity = [:sha256, :sha512]
    end
  end
end

With this config, the javascript_tag and stylesheet_tag assets helpers will return tags with integrity and crossorigin attributes.

<script
  src="/assets/app-LSLFPUMX.js"
  type="text/javascript"
  integrity="sha256-WB2pRuy8LdgAZ0aiFxLN8DdfRjKJTc4P4xuEw31iilM= sha512-4gegSER1uqxBvmlb/O9CJypUpRWR49SniwUjOcK2jifCRjFptwGKplFWGlGJ1yms+nSlkjpNCS/Lk9GoKI1Kew=="
  crossorigin="anonymous"
></script>

Checksum calculations are CPU intensive, so adding additional subresource_integrity schemes will extend the time it takes to compile assests, and therefore deploy your app. We suggest using :sha256 for starters.