CDN configuration for static files in Yesod

Posted on  by 

Recently we switched our blog to use a Content Delivery Network (KeyCDN) to deliver static content (images, javascript, CSS files, icons). By default, this seems not that easy because there is no clear documentation about this topic. In some articles, it's mentioned that it can be done but it is not mentioned how.

So let's start to do it step-by-step. We will create a new configuration option in our settings file. This option will point to our CDN location. We will use this location later to override the default behavior of Yesod.

Step 1: Creating a new configuration option

-- | Runtime settings to configure this application. These settings can be
-- loaded from various sources: defaults, environment variables, config files,
-- theoretically even a database.
data AppSettings = AppSettings
    { appStaticDir              :: String
    -- ^ Directory from which to serve static files.

    -- more settings here which were removed for demonstration 

    , appStaticRoot       :: Maybe Text
    -- ^ CDN location configuration

We added a new option appStaticRoot which has the type Maybe Text. If this option is defined (in production environments) we will use this location to serve static files. If it is not defined (test, development) we will ignore it and use the default rendering.

We need to tell Yesod how to fill appStaticRoot. We need to add the following line to instance FromJSON AppSettings where inside the parseJSON function:

appStaticRoot        <- o .:? "staticroot"

Step 2: Overriding default rendering

In our Foundation.hs we can now easily use this new configuration option like this:

-- Set up urlRenderOverride to point to the static domain name
    urlRenderOverride a (StaticR s) =
      case appStaticRoot $ appSettings a of
        Just configuredCDN ->
          Just $ uncurry (joinPath a configuredCDN) $ renderRoute s
        Nothing -> Nothing
    urlRenderOverride _ _ = Nothing

Only in the case of a static resource StaticR we check for the configuration option appStaticRoot and apply the configured value for route rendering. In any other case, the default rendering is applied. Great!

Important: You can still configure your CDN zones to to pull static files from your application. We only changed the rendering, not the routing itself!

I hope this post saved you a couple of minutes of work. If you have any thought, comments or questions please feel free to use the section below.