warp-tlsでそのままwebサーバを立てるとSSL Server Testで評価がAとなる.
評価をA+にするにはHTTPヘッダにHSTS(HTTP Strict Transport Security)を追加すればいい.

コード

{-# LANGUAGE OverloadedStrings #-}
module Lib
  ( runService
  ) where

-- wai
import Network.Wai
  ( Application
  , responseLBS
  )

-- http-types
import Network.HTTP.Types
  ( status200
  , hContentType
  , Header
  , ResponseHeaders
  )

-- warp
import Network.Wai.Handler.Warp
  ( setServerName
  , setPort
  , defaultSettings
  , Settings
  , runSettings
  , Port
  )

-- warp-tls
import Network.Wai.Handler.WarpTLS
  ( tlsSettingsChain
  , runTLS
  , defaultTlsSettings
  )

-- base
import Control.Concurrent(forkIO)

hstsHeader :: Header
hstsHeader = (s, t)
  where s = "Strict-Transport-Security"
        t = "max-age=63072000; includeSubdomains; preload"

htmlHeaders :: ResponseHeaders
htmlHeaders = [ (hContentType, "text/html"), hstsHeader ]

app :: Application
app req f = f $ responseLBS status200 htmlHeaders s
  where s = "<!DOCTYPE html>\n<html><body>Hello, world</body></html>"

settings :: Port -> Settings
settings port = setServerName "Warp" $ setPort port defaultSettings

runService :: IO ()
runService = do
  forkIO $ runSettings (settings 80) app
  runTLS tlsSettings'' (settings 443) app
  where tlsSettings'' = tlsSettingsChain cert chain privkey
        cert    = "/etc/letsencrypt/live/example.com/cert.pem"
        chain   = ["/etc/letsencrypt/live/example.com/chain.pem"]
        privkey = "/etc/letsencrypt/live/example.com/privkey.pem"

解説

HSTSヘッダとしてhstsHeaderを書いた.
responseLBSで指定するヘッダに追加することでHSTSヘッダを送るようにしている.

参考文献