packages feed

craft-0.0.0.1: src/Craft/Nginx.hs

module Craft.Nginx where

import           Control.Lens

import           Craft
import           Craft.Internal.Helpers
import qualified Craft.SysV             as SysV


setup :: Craft ()
setup =
  craft_ $ package "nginx"


baseDir, sitesDir :: Path Abs Dir
baseDir = $(mkAbsDir "/etc/nginx")
sitesDir = baseDir </> $(mkRelDir "sites-enabled")


data Config
  = Config
    { _configName       :: Name
    , _configDirectives :: [Directive]
    , _configServers    :: Servers
    , _configPriority   :: Int
    }


type Servers   = [Server]


data Server
  = Server
    { _serverNames      :: [Name]
    , _listen           :: (Address, Port, Args)
    , _serverDirectives :: [Directive]
    , _locations        :: [Location]
    }


data SSL
  = SSL
    { _sslKey  :: File
    , _sslCert :: File
    }


data Address
  = Address String
  | AnyAddress


instance Show Address where
  show AnyAddress  = "*"
  show (Address t) = t


type Port      = Int
data Location  = Location URL [Directive] [Location]
type URL       = String
type Directive = (Name, Args)
type Name      = String


makeLenses ''Config
makeLenses ''Server
makeLenses ''SSL


config :: Name -> Config
config name =
  Config
  { _configName       = name
  , _configPriority   = 10
  , _configDirectives = []
  , _configServers    = []
  }


server :: Server
server =
  Server
    { _serverNames      = []
    , _listen           = (AnyAddress, 80, [])
    , _serverDirectives = []
    , _locations        = []
    }


sslServer :: SSL -> Server
sslServer ssl =
  Server
  { _serverNames      = []
  , _listen           = (AnyAddress, 443, ["ssl"])
  , _serverDirectives =
      [ ("ssl",                       ["on"])
      , ("ssl_certificate",           [fromAbsFile $ ssl^.sslCert.path])
      , ("ssl_certificate_key",       [fromAbsFile $ ssl^.sslKey.path])
      , ("ssl_session_cache",         ["shared:SSL:10m"])
      , ("ssl_session_timeout",       ["5m"])
      , ("ssl_protocols",             ["TLSv1", "TLSv1.1", "TLSv1.2"])
      , ("ssl_ciphers",               ["ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"])
      , ("ssl_prefer_server_ciphers", ["on"])
      ]
  , _locations = []
  }



redirectWWWtoNoWWW :: [Server] -> [Server]
redirectWWWtoNoWWW servers =
  map go servers ++ servers
 where
  go s =
    s & serverNames .~ map ("www." ++) (s ^. serverNames)
      & locations   .~ []
      & serverDirectives .~ s ^. serverDirectives ++
        [ ("return", ["301", "http://" ++ s ^. serverNames . _head ++ "$uri"]) ]


logs :: Path Abs Dir -> Path Rel FileP -> [Directive]
logs logdir name =
  [ ("access_log", [ logprefix ++ ".access.log", "combined"])
  , ("error_log",  [ logprefix ++ ".error.log" ])
  ]
 where
  logprefix = fromAbsFile $ logdir </> name


root :: [Directive] -> Location
root dirs = Location "/" dirs []


instance Show Config where
  show cfg = dirs ++ servers
   where
    dirs = concatMap showDirective $ cfg ^. configDirectives
    servers = concatMap show $ cfg ^. configServers


showDirective :: Directive -> String
showDirective (name, args) =
  name ++ " " ++ unwords args ++ ";"


instance Show Server where
  show Server{..} = "\n" ++
    "server {\n" ++ indent 2 (
      "listen " ++ showListen _listen ++ ";\n" ++
      "server_name " ++ unwords _serverNames ++ ";\n" ++
      unlines ( map showDirective _serverDirectives ++ map show _locations)) ++
    "}\n"


instance Show Location where
  show (Location fp dirs sublocations) =
    "location " ++ fp ++ " {\n" ++ indent 2 (
        unlines $ map showDirective dirs
               ++ map show sublocations) ++
    "}\n"


showListen :: (Address, Port, Args) -> String
showListen (addr, port, args) =
  show addr ++ ":" ++ show port ++ " " ++ unwords args


toFile :: Config -> Craft File
toFile c = do
  fn <- parseRelFile $ (show $ c^.configPriority)++"_"++(c^.configName)++".conf"
  return $ file (sitesDir</>fn)
           & strContent .~ show c


reload :: Craft ()
reload = SysV.reload $ SysV.service "nginx"