diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,6 +2,15 @@
 
 `tmp-proc` uses [PVP Versioning][1].
 
+## 0.6.2.0 -- 2024-04-19
+
+* Introduce the Preparer typeclass that allows dynamic setup of resources for
+  containers
+
+* Relax the upper version bounds of connection to allow 3.2
+
+* Reenable the SSL integration tests using [test-certs][2]
+
 ## 0.6.1.0 -- 2024-03-14
 
 * Extend the version bounds of tls to allow 2.1
@@ -87,3 +96,4 @@
 * First version. Extracted from some a non-public test library
 
 [1]: https://pvp.haskell.org
+[2]: https://hackage.haskell.org/package/test-certs
diff --git a/src/System/TmpProc/Docker.hs b/src/System/TmpProc/Docker.hs
--- a/src/System/TmpProc/Docker.hs
+++ b/src/System/TmpProc/Docker.hs
@@ -3,12 +3,14 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE InstanceSigs #-}
 {-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE TypeFamilyDependencies #-}
@@ -41,8 +43,15 @@
 * A /'Proc'/ specifies a docker image that provides a service and other details
   related to its use in tests.
 
+* @'Proc's@ may need additional setup before the docker command runs, this can
+  be done using by providing a specific /'Preparer'/ instance for it
+
+* @'Proc's@ may need additional arguments in the docker command that launches
+  it; this can be done using by providing a specific /'ToRunCmd'/ instance for
+  it
+
 * A /'ProcHandle'/ is created whenever a service specifed by a /'Proc'/ is
-started, and is used to access and eventually terminate the running service.
+started, and is used to access and eventually terminate the service.
 
 * Some @'Proc's@ will also be /'Connectable'/; these specify how access the
 service via some /'Conn'-ection/ type.
@@ -58,23 +67,35 @@
   , uriOf'
   , runArgs'
 
-    -- * @'ToRunCmd'@
+    -- * customize docker startup
   , ToRunCmd (..)
+  , Preparer (..)
 
-    -- * @'ProcHandle'@
-  , ProcHandle (..)
-  , Proc2Handle
-  , HandlesOf
+    -- * start/stop multiple procs
   , startupAll
+  , startupAll'
   , terminateAll
+  , netwTerminateAll
+  , netwStartupAll
   , withTmpProcs
-  , manyNamed
+
+    -- * access a started @'Proc'@
+  , ProcHandle (..)
+  , SlimHandle (..)
+  , Proc2Handle
+  , HasHandle
+  , HasNamedHandle
+  , slim
   , handleOf
   , ixReset
   , ixPing
   , ixUriOf
-  , HasHandle
-  , HasNamedHandle
+
+    -- * access multiple procs
+  , HandlesOf
+  , NetworkHandlesOf
+  , manyNamed
+  , genNetworkName
   , SomeNamedHandles
 
     -- * @'Connectable'@
@@ -112,11 +133,13 @@
 import qualified Data.ByteString.Char8 as C8
 import Data.Kind (Type)
 import Data.List (dropWhileEnd)
-import Data.Maybe (isJust)
+import Data.Maybe (fromMaybe, isJust)
 import Data.Proxy (Proxy (..))
 import Data.Text (Text)
 import qualified Data.Text as Text
 import qualified Data.Text.IO as Text
+import Data.Word (Word16)
+import Fmt ((+|), (|+))
 import GHC.TypeLits
   ( CmpSymbol
   , KnownSymbol
@@ -139,6 +162,7 @@
   , waitForProcess
   , withCreateProcess
   )
+import System.Random (randomIO)
 import System.TmpProc.TypeLevel
   ( Drop
   , HList (..)
@@ -179,11 +203,13 @@
 
 -- | Set up some @'Proc's@, run an action that uses them, then terminate them.
 withTmpProcs ::
-  AreProcs procs =>
+  (AreProcs procs) =>
   HList procs ->
   (HandlesOf procs -> IO b) ->
   IO b
-withTmpProcs procs = bracket (startupAll procs) terminateAll
+withTmpProcs procs action =
+  let wrapAction f (_, ps) = f ps
+   in bracket (netwStartupAll procs) netwTerminateAll $ wrapAction action
 
 
 -- | Provides access to a 'Proc' that has been started.
@@ -195,30 +221,97 @@
   }
 
 
+-- | Provides an untyped view of the data in a 'ProcHandle'
+data SlimHandle = SlimHandle
+  { shName :: !Text
+  , shIpAddress :: !HostIpAddress
+  , shPid :: !String
+  , shUri :: !SvcURI
+  }
+  deriving (Eq, Show)
+
+
+-- | Obtain the 'SlimHandle'.
+slim :: (Proc a) => ProcHandle a -> SlimHandle
+slim x =
+  SlimHandle
+    { shName = nameOf $ hProc x
+    , shIpAddress = hAddr x
+    , shPid = hPid x
+    , shUri = hUri x
+    }
+
+
+slimMany :: (AreProcs procs) => HandlesOf procs -> [SlimHandle]
+slimMany =
+  let step x acc = slim x : acc
+   in foldProcs step []
+
+
 -- | Start up processes for each 'Proc' type.
-startupAll :: AreProcs procs => HList procs -> IO (HandlesOf procs)
-startupAll = go procProof
+startupAll :: (AreProcs procs) => HList procs -> IO (HandlesOf procs)
+startupAll ps = snd <$> startupAll' Nothing ps
+
+
+-- | Like 'startupAll' but creates a new docker network and that the processes use
+netwStartupAll :: (AreProcs procs) => HList procs -> IO (NetworkHandlesOf procs)
+netwStartupAll ps = do
+  netwName <- genNetworkName
+  startupAll' (Just netwName) ps
+
+
+foldProcs ::
+  forall procs b.
+  (AreProcs procs) =>
+  (forall a. (Proc a) => ProcHandle a -> b -> b) ->
+  b ->
+  HandlesOf procs ->
+  b
+foldProcs f acc = go procProof
   where
-    go :: Uniquely Proc AreProcs as -> HList as -> IO (HandlesOf as)
-    go UniquelyNil HNil = pure HNil
-    go (UniquelyCons cons) (x `HCons` y) = do
+    go :: SomeProcs as -> HandlesOf as -> b
+    go SomeProcsNil HNil = acc
+    go (SomeProcsCons cons) (x `HCons` y) = f x $ go cons y
+
+
+-- | Start up processes for each 'Proc' type.
+startupAll' :: (AreProcs procs) => Maybe Text -> HList procs -> IO (NetworkHandlesOf procs)
+startupAll' ntwkMb ps =
+  let
+    mayCreateNetwork = case ntwkMb of
+      Nothing -> pure ()
+      Just name -> void $ readProcess "docker" (createNetworkArgs $ Text.unpack name) ""
+    wrap x = (fromMaybe "" ntwkMb, x)
+
+    go :: SomeProcs as -> HList as -> IO (HandlesOf as)
+    go SomeProcsNil HNil = pure HNil
+    go (SomeProcsCons cons) (x `HCons` y) = do
       others <- go cons y
-      h <- startup x `onException` terminateAll others
-      -- others <- go cons y `onException` terminate h
+      h <- startup' ntwkMb (slimMany others) x `onException` terminateAll others
       pure $ h `HCons` others
+   in
+    do
+      mayCreateNetwork
+      wrap <$> go procProof ps
 
 
 -- | Terminate all processes owned by some @'ProcHandle's@.
-terminateAll :: AreProcs procs => HandlesOf procs -> IO ()
-terminateAll = go $ p2h procProof
-  where
-    go :: SomeHandles as -> HList as -> IO ()
-    go SomeHandlesNil HNil = pure ()
-    go (SomeHandlesCons cons) (x `HCons` y) = do
-      terminate x
-      go cons y
+terminateAll :: (AreProcs procs) => HandlesOf procs -> IO ()
+terminateAll =
+  let step x acc = terminate x >> acc
+   in foldProcs step $ pure ()
 
 
+{- | Like 'terminateAll', but also removes the docker network connecting the
+processes.
+-}
+netwTerminateAll :: (AreProcs procs) => NetworkHandlesOf procs -> IO ()
+netwTerminateAll (ntwk, ps) = do
+  let name' = Text.unpack ntwk
+  terminateAll ps
+  void $ readProcess "docker" (removeNetworkArgs name') ""
+
+
 -- | Terminate the process owned by a @'ProcHandle's@.
 terminate :: ProcHandle p -> IO ()
 terminate handle = do
@@ -227,25 +320,53 @@
   void $ readProcess "docker" ["rm", pid] ""
 
 
+{- | Prepare resources for use by a  @'Proc'@
+
+ Preparation occurs before the @Proc's @docker container is a launched, and
+ resources generated are made accessible via the @prepared@ data type.
+
+ Usually, it will be used by @'toRunCmd'@ to provide additional arguments to the
+ docker command
+
+ There is an @Overlappable@ fallback instance that works for any @'Proc'@,
+ so this typeclass need only be specified for @'Proc'@ that require some
+ setup
+
+ The 'prepare' method is given a list of 'SlimHandle' that represent preceding
+ @tmp-proc@ managed containers, to allow preparation to establish links to these
+ containers when necessary
+-}
+class Preparer a prepared | a -> prepared where
+  -- * Generate a @prepared@ before the docker container is started
+  prepare :: [SlimHandle] -> a -> IO prepared
+
+
+instance {-# OVERLAPPABLE #-} (a ~ a', Proc a) => Preparer a a' where
+  prepare :: [SlimHandle] -> a -> IO a'
+  prepare _ = pure
+
+
 {- | Allow customization of the docker command that launches a @'Proc'@
-|
-| The full command is
-|   `docker run -d <optional-args> $(imageText a)`
-|
-| A fallback instance is provided that works for any instance of @Proc a@
-| Specify a new instance of @ToRunCmd@ to control <optional-args>
+
+ The full command is
+   `docker run -d <optional-args> --name $(name a) $(imageText a)`
+ Specify a new instance of @ToRunCmd@ to control <optional-args>
+
+ There is an @Overlappable@ fallback instance that works for any @'Proc'@,
+ so this typeclass need only be specified for @'Proc'@ that need extra
+ args in the docker command
 -}
-class ToRunCmd a where
-  -- * Generate args that follow the initial ['docker', 'run', '-d']
-  toRunCmd :: a -> [Text]
+class (Preparer a prepared) => ToRunCmd a prepared where
+  -- * Generate docker command args to immeidately an initial ['docker', 'run', '-d']
+  toRunCmd :: a -> prepared -> [Text]
 
 
-instance {-# OVERLAPPABLE #-} (Proc a) => ToRunCmd a where
-  toRunCmd _ = runArgs @a
+instance {-# OVERLAPPABLE #-} (a ~ a', Proc a) => ToRunCmd a a' where
+  toRunCmd _ _ = runArgs @a
 
 
 -- | Specifies how to a get a connection to a 'Proc'.
-class Proc a => Connectable a where
+class (Proc a) => Connectable a where
   -- | The connection type.
   type Conn a = (conn :: Type) | conn -> a
 
@@ -343,14 +464,21 @@
 
 
 -- | The full args of a @docker run@ command for starting up a 'Proc'.
-dockerCmdArgs :: forall a. (Proc a, ToRunCmd a) => a -> [Text]
-dockerCmdArgs x = ["run", "-d"] <> toRunCmd x <> [imageText' @a]
+dockerCmdArgs :: forall a prepared. (Proc a, ToRunCmd a prepared) => a -> prepared -> Maybe Text -> [Text]
+dockerCmdArgs x prep ntwkMb =
+  let toNetworkArgs n = ["--network", n]
+      networkArg = maybe mempty toNetworkArgs ntwkMb
+   in ["run", "-d"] <> nameArg @a <> networkArg <> toRunCmd x prep <> [imageText' @a]
 
 
 imageText' :: forall a. (Proc a) => Text
-imageText' = Text.pack $ symbolVal (Proxy :: Proxy (Image a))
+imageText' = Text.pack $ symbolVal $ Proxy @(Image a)
 
 
+nameArg :: forall a. (Proc a) => [Text]
+nameArg = ["--name", Text.pack $ symbolVal $ Proxy @(Name a)]
+
+
 -- | The IP address of the docker host.
 type HostIpAddress = Text
 
@@ -366,12 +494,27 @@
 
 Returns the 'ProcHandle' used to control the 'Proc' once a ping has succeeded.
 -}
-startup :: (Proc a, ToRunCmd a) => a -> IO (ProcHandle a)
-startup x = do
-  let fullArgs = map Text.unpack $ dockerCmdArgs x
+startup :: (ProcPlus a prepared) => a -> IO (ProcHandle a)
+startup = startup' Nothing mempty
+
+
+-- | A @Constraint@ that combines @'Proc'@  and its supporting typeclasses
+type ProcPlus a prepared = (Proc a, ToRunCmd a prepared, Preparer a prepared)
+
+
+startup' ::
+  (ProcPlus a prepared) =>
+  Maybe Text ->
+  [SlimHandle] ->
+  a ->
+  IO (ProcHandle a)
+startup' ntwkMb addrs x = do
+  x' <- prepare addrs x
+  let fullArgs = map Text.unpack $ dockerCmdArgs x x' ntwkMb
       isGarbage = flip elem ['\'', '\n']
       trim = dropWhileEnd isGarbage . dropWhile isGarbage
-  runCmd <- dockerRun fullArgs
+  printDebug $ Text.pack $ show fullArgs
+  runCmd <- createDockerCmdProcess fullArgs
   hPid <- trim <$> readCreateProcess runCmd ""
   hAddr <-
     Text.pack . trim
@@ -391,7 +534,7 @@
       fail $ pingedMsg x pinged
 
 
-pingedMsg :: Proc a => a -> Pinged -> String
+pingedMsg :: (Proc a) => a -> Pinged -> String
 pingedMsg _ OK = ""
 pingedMsg p NotOK = "tmp proc:" ++ Text.unpack (nameOf p) ++ ":could not be pinged"
 pingedMsg p (PingFailed err) =
@@ -402,12 +545,16 @@
 
 
 -- | Use an action that might throw an exception as a ping.
-toPinged :: forall e a. Exception e => Proxy e -> IO a -> IO Pinged
-toPinged _ action = (action >> pure OK) `catch` (\(_ :: e) -> pure NotOK)
+toPinged :: forall e a. (Exception e) => Proxy e -> IO a -> IO Pinged
+toPinged _ action =
+  let handler (ex :: e) = do
+        printDebug $ "toPinged:" <> Text.pack (show ex)
+        pure NotOK
+   in (action >> pure OK) `catch` handler
 
 
 -- | Ping a 'ProcHandle' several times.
-nPings :: Proc a => ProcHandle a -> IO Pinged
+nPings :: (Proc a) => ProcHandle a -> IO Pinged
 nPings h@ProcHandle {hProc = p} =
   let
     count = fromEnum $ pingCount' p
@@ -462,7 +609,7 @@
 
 
 -- | Run an action on a 'Connectable' handle as a callback on its 'Conn'
-withTmpConn :: Connectable a => ProcHandle a -> (Conn a -> IO b) -> IO b
+withTmpConn :: (Connectable a) => ProcHandle a -> (Conn a -> IO b) -> IO b
 withTmpConn handle = bracket (openConn handle) closeConn
 
 
@@ -484,7 +631,7 @@
 
 -- | Select the named @'ProcHandle's@ from an 'HList' of @'ProcHandle'@.
 manyNamed ::
-  SomeNamedHandles names namedProcs someProcs sortedProcs =>
+  (SomeNamedHandles names namedProcs someProcs sortedProcs) =>
   Proxy names ->
   HandlesOf someProcs ->
   HandlesOf namedProcs
@@ -593,7 +740,7 @@
 
 
 -- | Convert a 'ProcHandle' to a 'KV'.
-toKV :: Proc a => ProcHandle a -> KV (Name a) (ProcHandle a)
+toKV :: (Proc a) => ProcHandle a -> KV (Name a) (ProcHandle a)
 toKV = V
 
 
@@ -607,6 +754,10 @@
 type HandlesOf procs = HList (Proc2Handle procs)
 
 
+-- | A list of @'ProcHandle'@ values with the docker network of their processes
+type NetworkHandlesOf procs = (Text, HandlesOf procs)
+
+
 -- | Converts list of 'Proc' the corresponding @'Name'@ symbols.
 type family Proc2Name (as :: [Type]) = (nameTys :: [Symbol]) | nameTys -> as where
   Proc2Name '[] = '[]
@@ -621,35 +772,40 @@
 
 -- | Declares a proof that a list of types only contains @'Proc's@.
 class AreProcs as where
-  procProof :: Uniquely Proc AreProcs as
+  procProof :: SomeProcs as
 
 
 instance AreProcs '[] where
-  procProof = UniquelyNil
+  procProof = SomeProcsNil
 
 
 instance
-  ( Proc a
-  , ToRunCmd a
+  ( ProcPlus a prepared
   , AreProcs as
   , IsAbsent a as
   ) =>
   AreProcs (a ': as)
   where
-  procProof = UniquelyCons procProof
+  procProof = SomeProcsCons procProof
 
 
 -- | Used to prove a list of types just contains @'ProcHandle's@.
 data SomeHandles (as :: [Type]) where
   SomeHandlesNil :: SomeHandles '[]
-  SomeHandlesCons :: Proc a => SomeHandles as -> SomeHandles (ProcHandle a ': as)
+  SomeHandlesCons :: (ProcPlus a prepared) => SomeHandles as -> SomeHandles (ProcHandle a ': as)
 
 
-p2h :: Uniquely Proc AreProcs as -> SomeHandles (Proc2Handle as)
-p2h UniquelyNil = SomeHandlesNil
-p2h (UniquelyCons cons) = SomeHandlesCons (p2h cons)
+p2h :: SomeProcs as -> SomeHandles (Proc2Handle as)
+p2h SomeProcsNil = SomeHandlesNil
+p2h (SomeProcsCons cons) = SomeHandlesCons (p2h cons)
 
 
+-- | Used to prove a list of types just contains @'Proc's@.
+data SomeProcs (as :: [Type]) where
+  SomeProcsNil :: SomeProcs '[]
+  SomeProcsCons :: (ProcPlus a prepared, AreProcs as, IsAbsent a as) => SomeProcs as -> SomeProcs (a ': as)
+
+
 -- | Declares a proof that a list of types only contains @'Connectable's@.
 class Connectables as where
   connProof :: Uniquely Connectable Connectables as
@@ -670,7 +826,7 @@
 
 
 -- | Open all the 'Connectable' types to corresponding 'Conn' types.
-openAll :: Connectables xs => HandlesOf xs -> IO (HList (ConnsOf xs))
+openAll :: (Connectables xs) => HandlesOf xs -> IO (HList (ConnsOf xs))
 openAll = go connProof
   where
     go :: Uniquely Connectable Connectables as -> HandlesOf as -> IO (HList (ConnsOf as))
@@ -682,7 +838,7 @@
 
 
 -- | Close some 'Connectable' types.
-closeAll :: Connectables procs => HList (ConnsOf procs) -> IO ()
+closeAll :: (Connectables procs) => HList (ConnsOf procs) -> IO ()
 closeAll = go connProof
   where
     go :: Uniquely Connectable Connectables as -> HList (ConnsOf as) -> IO ()
@@ -692,7 +848,7 @@
 
 -- | Open some connections, use them in an action; close them.
 withConns ::
-  Connectables procs =>
+  (Connectables procs) =>
   HandlesOf procs ->
   (HList (ConnsOf procs) -> IO b) ->
   IO b
@@ -781,8 +937,8 @@
 devNull = openBinaryFile "/dev/null" WriteMode
 
 
-dockerRun :: [String] -> IO CreateProcess
-dockerRun args = do
+createDockerCmdProcess :: [String] -> IO CreateProcess
+createDockerCmdProcess args = do
   devNull' <- devNull
   pure $ (proc "docker" args) {std_err = UseHandle devNull'}
 
@@ -799,3 +955,20 @@
 printDebug t = do
   canPrint <- showDebug
   when canPrint $ Text.hPutStrLn stderr t
+
+
+-- | generate a random network name
+genNetworkName :: IO Text
+genNetworkName = networkNameOf <$> randomIO
+
+
+networkNameOf :: Word16 -> Text
+networkNameOf suffix = "tmp-proc-" +| suffix |+ ""
+
+
+createNetworkArgs :: String -> [String]
+createNetworkArgs name = ["network", "create", "-d", "bridge", name]
+
+
+removeNetworkArgs :: String -> [String]
+removeNetworkArgs name = ["network", "remove", "-f", name]
diff --git a/src/System/TmpProc/Warp.hs b/src/System/TmpProc/Warp.hs
--- a/src/System/TmpProc/Warp.hs
+++ b/src/System/TmpProc/Warp.hs
@@ -1,15 +1,15 @@
 {-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE LambdaCase       #-}
-{-# LANGUAGE NamedFieldPuns   #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE NamedFieldPuns #-}
 {-# OPTIONS_HADDOCK prune not-home #-}
-{-|
+
+{- |
 Copyright   : (c) 2020-2021 Tim Emiola
 SPDX-License-Identifier: BSD3
 Maintainer  : Tim Emiola <adetokunbo@users.noreply.github.com>
 
 Provides functions that make it easy to run /'Application's/
  that access services running as @tmp@ @procs@ in integration tests.
-
 -}
 module System.TmpProc.Warp
   ( -- * Continuation-style setup
@@ -31,100 +31,120 @@
     -- * Health check support
   , checkHealth
   )
-
 where
 
-import           Control.Concurrent          (myThreadId, newEmptyMVar, putMVar,
-                                              readMVar, takeMVar, threadDelay,
-                                              throwTo)
-import           Control.Exception           (ErrorCall (..))
-import           Control.Monad               (void, when)
-import           Control.Monad.Cont          (cont, runCont)
-import           Network.Socket              (Socket, close)
-import           Network.Wai                 (Application)
-import qualified Network.Wai.Handler.Warp    as Warp
+import Control.Concurrent
+  ( myThreadId
+  , newEmptyMVar
+  , putMVar
+  , readMVar
+  , takeMVar
+  , threadDelay
+  , throwTo
+  )
+import Control.Exception (ErrorCall (..))
+import Control.Monad (void, when)
+import Control.Monad.Cont (cont, runCont)
+import Data.Text (Text)
+import Network.Socket (Socket, close)
+import Network.Wai (Application)
+import qualified Network.Wai.Handler.Warp as Warp
 import qualified Network.Wai.Handler.WarpTLS as Warp
-import           UnliftIO                    (Async, async, bracket, cancel,
-                                              catch, onException, race, throwIO,
-                                              waitEither)
-
-import           System.TmpProc.Docker       (AreProcs, HList (..), HandlesOf,
-                                              startupAll, terminateAll,
-                                              withTmpProcs)
+import System.TmpProc.Docker
+  ( AreProcs
+  , HList (..)
+  , HandlesOf
+  , netwStartupAll
+  , netwTerminateAll
+  , withTmpProcs
+  )
+import UnliftIO
+  ( Async
+  , async
+  , bracket
+  , cancel
+  , catch
+  , onException
+  , race
+  , throwIO
+  , waitEither
+  )
 
 
 -- | Represents a started Warp application and any 'AreProcs' dependencies.
 data ServerHandle procs = ServerHandle
-  { shServer  :: !(Async ())
-  , shPort    :: !Warp.Port
-  , shSocket  :: !Socket
+  { shServer :: !(Async ())
+  , shPort :: !Warp.Port
+  , shSocket :: !Socket
   , shHandles :: !(HandlesOf procs)
+  , shNetwork :: !Text
   }
 
+
 -- | Runs an 'Application' with @ProcHandle@ dependencies on a free port.
-runServer
-  :: AreProcs procs
-  => HList procs
-  -> (HandlesOf procs -> IO Application)
-  -> IO (ServerHandle procs)
+runServer ::
+  (AreProcs procs) =>
+  HList procs ->
+  (HandlesOf procs -> IO Application) ->
+  IO (ServerHandle procs)
 runServer = runReadyServer doNothing
 
 
-{-| Like 'runServer'; with an additional @ready@ that determines if the server is ready.'. -}
-runReadyServer
-  :: AreProcs procs
-  => (Warp.Port -> IO ())       --  ^ throws an exception if the server is not ready
-  -> HList procs                --  ^ defines the dependent @Proc@s
-  -> (HandlesOf procs -> IO Application)
-  -> IO (ServerHandle procs)
+-- | Like 'runServer'; with an additional @ready@ that determines if the server is ready.'.
+runReadyServer ::
+  (AreProcs procs) =>
+  (Warp.Port -> IO ()) -> --  ^ throws an exception if the server is not ready
+  HList procs -> --  ^ defines the dependent @Proc@s
+  (HandlesOf procs -> IO Application) ->
+  IO (ServerHandle procs)
 runReadyServer = runReadyServer' Warp.runSettingsSocket
 
 
-{-| Like 'runServer'; the port is secured with 'Warp.TLSSettings'. -}
-runTLSServer
-  :: AreProcs procs
-  => Warp.TLSSettings
-  -> HList procs
-  -> (HandlesOf procs -> IO Application)
-  -> IO (ServerHandle procs)
-runTLSServer tlsSettings = runReadyServer' (Warp.runTLSSocket tlsSettings)  doNothing
+-- | Like 'runServer'; the port is secured with 'Warp.TLSSettings'.
+runTLSServer ::
+  (AreProcs procs) =>
+  Warp.TLSSettings ->
+  HList procs ->
+  (HandlesOf procs -> IO Application) ->
+  IO (ServerHandle procs)
+runTLSServer tlsSettings = runReadyServer' (Warp.runTLSSocket tlsSettings) doNothing
 
 
-{-| Like 'runReadyServer'; the port is secured with 'Warp.TLSSettings'. -}
-runReadyTLSServer
-  :: AreProcs procs
-  => Warp.TLSSettings
-  -> (Warp.Port -> IO ())       --  ^ throws an exception if the server is not ready
-  -> HList procs                --  ^ defines the dependent @Proc@s
-  -> (HandlesOf procs -> IO Application)
-  -> IO (ServerHandle procs)
+-- | Like 'runReadyServer'; the port is secured with 'Warp.TLSSettings'.
+runReadyTLSServer ::
+  (AreProcs procs) =>
+  Warp.TLSSettings ->
+  (Warp.Port -> IO ()) -> --  ^ throws an exception if the server is not ready
+  HList procs -> --  ^ defines the dependent @Proc@s
+  (HandlesOf procs -> IO Application) ->
+  IO (ServerHandle procs)
 runReadyTLSServer tlsSettings = runReadyServer' (Warp.runTLSSocket tlsSettings)
 
 
 -- | Used to implement 'runReadyServer'
-runReadyServer'
-  :: AreProcs procs
-  => (Warp.Settings -> Socket -> Application -> IO ())
-  -> (Warp.Port -> IO ())       --  ^ throws an exception if the server is not ready
-  -> HList procs                   --  ^ defines the dependent @Proc@s
-  -> (HandlesOf procs -> IO Application)
-  -> IO (ServerHandle procs)
+runReadyServer' ::
+  (AreProcs procs) =>
+  (Warp.Settings -> Socket -> Application -> IO ()) ->
+  (Warp.Port -> IO ()) -> --  ^ throws an exception if the server is not ready
+  HList procs -> --  ^ defines the dependent @Proc@s
+  (HandlesOf procs -> IO Application) ->
+  IO (ServerHandle procs)
 runReadyServer' runApp check procs mkApp = do
   callingThread <- myThreadId
-  h <- startupAll procs
+  (netw, h) <- netwStartupAll procs
   (p, sock) <- Warp.openFreePort
   signal <- newEmptyMVar
-  let settings = readySettings(putMVar signal ())
+  let settings = readySettings (putMVar signal ())
   app <- mkApp h
   let wrappedApp request respond =
-        app request respond `catch` \ e -> do
+        app request respond `catch` \e -> do
           when
             (Warp.defaultShouldDisplayException e)
             (throwTo callingThread e)
           throwIO e
-  s <- async (pure wrappedApp >>= runApp settings sock)
+  s <- async $ runApp settings sock wrappedApp
   aConfirm <- async (takeMVar signal)
-  let result = ServerHandle s p sock h
+  let result = ServerHandle s p sock h netw
   waitEither s aConfirm >>= \case
     Left _ -> do
       shutdown result
@@ -135,16 +155,16 @@
 
 
 -- | Shuts down the 'ServerHandle' server and its @tmp proc@ dependencies.
-shutdown :: AreProcs procs => ServerHandle procs -> IO ()
+shutdown :: (AreProcs procs) => ServerHandle procs -> IO ()
 shutdown h = do
-  let ServerHandle { shServer, shSocket, shHandles } = h
-  terminateAll shHandles
+  let ServerHandle {shServer, shSocket, shHandles, shNetwork} = h
+  netwTerminateAll (shNetwork, shHandles)
   cancel shServer
   close shSocket
 
 
 -- | The @'ServerHandle's@  @ProcHandles@.
-handles :: AreProcs procs => ServerHandle procs -> HandlesOf procs
+handles :: (AreProcs procs) => ServerHandle procs -> HandlesOf procs
 handles = shHandles
 
 
@@ -153,7 +173,7 @@
 serverPort = shPort
 
 
-{-| Set up some @ProcHandles@ then run an 'Application' that uses them on a free
+{- | Set up some @ProcHandles@ then run an 'Application' that uses them on a free
    port.
 
 Allows the app to configure itself using the @tmp procs@, then provides a
@@ -161,33 +181,33 @@
 
 The @tmp procs@ are shut down when the application is shut down.
 -}
-testWithApplication
-  :: AreProcs procs
-  => HList procs
-  -> (HandlesOf procs -> IO Application)
-  -> ((HandlesOf procs, Warp.Port) -> IO a)
-  -> IO a
+testWithApplication ::
+  (AreProcs procs) =>
+  HList procs ->
+  (HandlesOf procs -> IO Application) ->
+  ((HandlesOf procs, Warp.Port) -> IO a) ->
+  IO a
 testWithApplication procs mkApp = runCont $ do
   oh <- cont $ withTmpProcs procs
   p <- cont $ Warp.testWithApplication $ mkApp oh
   pure (oh, p)
 
 
-{-| Like 'testWithApplication', but the port is secured using a 'Warp.TLSSettings. '-}
-testWithTLSApplication
-  :: AreProcs procs
-  =>  Warp.TLSSettings
-  -> HList procs
-  -> (HandlesOf procs -> IO Application)
-  -> ((HandlesOf procs, Warp.Port) -> IO a)
-  -> IO a
+-- | Like 'testWithApplication', but the port is secured using a 'Warp.TLSSettings. '
+testWithTLSApplication ::
+  (AreProcs procs) =>
+  Warp.TLSSettings ->
+  HList procs ->
+  (HandlesOf procs -> IO Application) ->
+  ((HandlesOf procs, Warp.Port) -> IO a) ->
+  IO a
 testWithTLSApplication tlsSettings procs mkApp = runCont $ do
   oh <- cont $ withTmpProcs procs
   p <- cont $ withTLSApplicationSettings tlsSettings Warp.defaultSettings $ mkApp oh
   pure (oh, p)
 
 
-{-| Set up some @ProcHandles@ then run an 'Application' that uses them on a free
+{- | Set up some @ProcHandles@ then run an 'Application' that uses them on a free
    port.
 
 Allows the app to configure itself using the @tmp procs@, then provides a
@@ -198,13 +218,13 @@
 
 The @tmp procs@ are shut down when the application is shut down.
 -}
-testWithReadyApplication
-  :: AreProcs procs
-  => (Warp.Port -> IO ()) -- throws an exception if the server is not ready
-  -> HList procs
-  -> (HandlesOf procs -> IO Application)
-  -> ((HandlesOf procs, Warp.Port) -> IO a)
-  -> IO a
+testWithReadyApplication ::
+  (AreProcs procs) =>
+  (Warp.Port -> IO ()) -> -- throws an exception if the server is not ready
+  HList procs ->
+  (HandlesOf procs -> IO Application) ->
+  ((HandlesOf procs, Warp.Port) -> IO a) ->
+  IO a
 testWithReadyApplication check procs mkApp = runCont $ do
   oh <- cont $ withTmpProcs procs
   w <- cont $ bracket (mkWaiter check) doNothing
@@ -213,15 +233,15 @@
   return (oh, p)
 
 
-{-| Like 'testWithReadyApplication'; the port is secured with 'Warp.TLSSettings'. -}
-testWithReadyTLSApplication
-  :: AreProcs procs
-  => Warp.TLSSettings
-  -> (Warp.Port -> IO ()) -- throws an exception if the server is not ready
-  -> HList procs
-  -> (HandlesOf procs -> IO Application)
-  -> ((HandlesOf procs, Warp.Port) -> IO a)
-  -> IO a
+-- | Like 'testWithReadyApplication'; the port is secured with 'Warp.TLSSettings'.
+testWithReadyTLSApplication ::
+  (AreProcs procs) =>
+  Warp.TLSSettings ->
+  (Warp.Port -> IO ()) -> -- throws an exception if the server is not ready
+  HList procs ->
+  (HandlesOf procs -> IO Application) ->
+  ((HandlesOf procs, Warp.Port) -> IO a) ->
+  IO a
 testWithReadyTLSApplication tlsSettings check procs mkApp = runCont $ do
   oh <- cont $ withTmpProcs procs
   w <- cont $ bracket (mkWaiter check) doNothing
@@ -235,32 +255,31 @@
 checkHealth tries h = go tries
   where
     go 0 = error "healthy: server isn't healthy"
-    go n = h >>= \case
-      Left  _ -> threadDelay pingPeriod >> go (n - 1)
-      Right _ -> pure ()
+    go n =
+      h >>= \case
+        Left _ -> threadDelay pingPeriod >> go (n - 1)
+        Right _ -> pure ()
 
 
+{- | A 'Warp.Settings' configured with a ready action.
 
--- | A 'Warp.Settings' configured with a ready action.
---
--- The ready action is used to check if a server is healthy.
+The ready action is used to check if a server is healthy.
+-}
 readySettings :: IO () -> Warp.Settings
 readySettings ready = Warp.setBeforeMainLoop ready Warp.defaultSettings
 
 
+{- | A 'Warp.Settings' configured with a ready action.
 
--- | A 'Warp.Settings' configured with a ready action.
---
--- The ready action is used to check if a server is healthy.
+The ready action is used to check if a server is healthy.
+-}
 waiterSettings :: PortWaiter () -> Warp.Settings
 waiterSettings w = Warp.setBeforeMainLoop (notify w ()) Warp.defaultSettings
 
 
-
 -- | Simplifies creation of a ready action.
-data PortWaiter a =
-  PortWaiter
-  { notify  :: a -> IO ()
+data PortWaiter a = PortWaiter
+  { notify :: a -> IO ()
   , waitFor :: Warp.Port -> IO a
   }
 
@@ -273,10 +292,11 @@
         res <- readMVar mvar
         void $ check p
         pure res
-  pure PortWaiter
-    { notify = putMVar mvar
-    , waitFor
-    }
+  pure
+    PortWaiter
+      { notify = putMVar mvar
+      , waitFor
+      }
 
 
 -- | Gap between service pings in milliseconds.
@@ -284,22 +304,24 @@
 pingPeriod = 1000000
 
 
--- | Like 'Warp.testWithApplicationSettings' , but the port is secured using the
--- provided 'Warp.TLSSettings'.
-withTLSApplicationSettings
-  :: Warp.TLSSettings
-  -> Warp.Settings
-  -> IO Application
-  -> (Warp.Port -> IO a)
-  -> IO a
+{- | Like 'Warp.testWithApplicationSettings' , but the port is secured using the
+provided 'Warp.TLSSettings'.
+-}
+withTLSApplicationSettings ::
+  Warp.TLSSettings ->
+  Warp.Settings ->
+  IO Application ->
+  (Warp.Port -> IO a) ->
+  IO a
 withTLSApplicationSettings tlsSettings settings mkApp action = do
   app <- mkApp
-  withFreePort $ \ (p, sock) -> do
+  withFreePort $ \(p, sock) -> do
     started <- mkWaiter doNothing
     let settings' = Warp.setBeforeMainLoop (notify started ()) settings
-    result <- race
-      (Warp.runTLSSocket tlsSettings settings' sock app)
-      (waitFor started p >> action p)
+    result <-
+      race
+        (Warp.runTLSSocket tlsSettings settings' sock app)
+        (waitFor started p >> action p)
     case result of
       Left () -> throwIO $ ErrorCall "Unexpected: runSettingsSocket exited"
       Right x -> return x
diff --git a/templates/nginx-test.conf.mustache b/templates/nginx-test.conf.mustache
new file mode 100644
--- /dev/null
+++ b/templates/nginx-test.conf.mustache
@@ -0,0 +1,42 @@
+server {
+  listen 80;
+  listen [::]:80;
+  server_name {{common_name}};
+  location / {
+    rewrite ^ https://$host$request_uri? permanent;
+  }
+}
+
+server {
+  listen 443 ssl;
+  listen [::]:443 ssl;
+  server_name {{commonName}};
+  server_tokens off;
+  ssl_certificate /etc/tmp-proc/certs/certificate.pem;
+  ssl_certificate_key /etc/tmp-proc/certs/key.pem;
+  ssl_buffer_size 8k;
+  ssl_protocols TLSv1.2;
+  ssl_prefer_server_ciphers on;
+  ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
+  ssl_ecdh_curve secp384r1;
+  ssl_session_tickets off;
+  ssl_stapling on;
+  ssl_stapling_verify on;
+  resolver 8.8.8.8;
+
+  location / {
+    try_files $uri @tmp-proc-target;
+  }
+
+  location @tmp-proc-target {
+    proxy_pass http://{{targetName}}:{{targetPort}};
+    add_header X-Frame-Options "SAMEORIGIN" always;
+    add_header X-XSS-Protection "1; mode=block" always;
+    add_header X-Content-Type-Options "nosniff" always;
+    add_header Referrer-Policy "no-referrer-when-downgrade" always;
+    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
+  }
+
+  root /var/www/html;
+  index index.html index.htm index.nginx-debian.html;
+}
diff --git a/test/Test/HttpBin.hs b/test/Test/HttpBin.hs
--- a/test/Test/HttpBin.hs
+++ b/test/Test/HttpBin.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
@@ -19,35 +21,26 @@
   , Proc (..)
   , ProcHandle (..)
   , SvcURI
-  , ToRunCmd (..)
   , manyNamed
   , startupAll
   , toPinged
   , (&:)
   , (&:&)
   )
-
-
-setupHandles :: IO (HandlesOf '[HttpBinTest, NginxTest, HttpBinTest3])
-setupHandles = startupAll $ HttpBinTest &: NginxTest &:& HttpBinTest3
-
-
--- | A data type representing a connection to an Nginx server.
-data NginxTest = NginxTest
+import Test.NginxGateway (NginxGateway (..))
 
 
--- | Run Nginx as temporary process.
-instance Proc NginxTest where
-  type Image NginxTest = "nginx:1.25.1"
-  type Name NginxTest = "nginx-test"
-  uriOf = mkUri'
-  runArgs = []
-  reset _ = pure ()
-  ping = ping'
+anNginxGateway :: NginxGateway
+anNginxGateway =
+  NginxGateway
+    { ngCommonName = "localhost"
+    , ngTargetPort = 80
+    , ngTargetName = "http-bin-test-3"
+    }
 
 
-instance ToRunCmd NginxTest where
-  toRunCmd _ = []
+setupHandles :: IO (HandlesOf '[HttpBinTest, NginxGateway, HttpBinTest3])
+setupHandles = startupAll $ HttpBinTest &: anNginxGateway &:& HttpBinTest3
 
 
 -- | A data type representing a connection to a HttpBin server.
@@ -58,10 +51,10 @@
 instance Proc HttpBinTest where
   type Image HttpBinTest = "kennethreitz/httpbin"
   type Name HttpBinTest = "http-bin-test"
-  uriOf = mkUri'
+  uriOf = httpUri
   runArgs = []
   reset _ = pure ()
-  ping = ping'
+  ping = pingHttp
 
 
 {- | Another data type representing a connection to a HttpBin server.
@@ -76,10 +69,10 @@
 instance Proc HttpBinTest2 where
   type Image HttpBinTest2 = "kennethreitz/httpbin"
   type Name HttpBinTest2 = "http-bin-test-2"
-  uriOf = mkUri'
+  uriOf = httpUri
   runArgs = []
   reset _ = pure ()
-  ping = ping'
+  ping = pingHttp
 
 
 {- | Yet another data type representing a connection to a HttpBin server.
@@ -94,26 +87,26 @@
 instance Proc HttpBinTest3 where
   type Image HttpBinTest3 = "kennethreitz/httpbin"
   type Name HttpBinTest3 = "http-bin-test-3"
-  uriOf = mkUri'
+  uriOf = httpUri
   runArgs = []
   reset _ = pure ()
-  ping = ping'
+  ping = pingHttp
 
 
 -- | Make a uri access the http-bin server.
-mkUri' :: HostIpAddress -> SvcURI
-mkUri' ip = "http://" <> C8.pack (Text.unpack ip) <> "/"
+httpUri :: HostIpAddress -> SvcURI
+httpUri ip = "http://" <> C8.pack (Text.unpack ip) <> "/"
 
 
-ping' :: ProcHandle a -> IO Pinged
-ping' handle = toPinged @HC.HttpException Proxy $ do
-  gotStatus <- handleGet handle "/status/200"
+pingHttp :: ProcHandle a -> IO Pinged
+pingHttp handle = toPinged @HC.HttpException Proxy $ do
+  gotStatus <- httpGet handle "/status/200"
   if gotStatus == 200 then pure OK else pure NotOK
 
 
--- | Determine the status from a Get on localhost.
-handleGet :: ProcHandle a -> Text -> IO Int
-handleGet handle urlPath = do
+-- | Determine the status from a Get.
+httpGet :: ProcHandle a -> Text -> IO Int
+httpGet handle urlPath = do
   let theUri = "http://" <> hAddr handle <> "/" <> Text.dropWhile (== '/') urlPath
   manager <- HC.newManager HC.defaultManagerSettings
   getReq <- HC.parseRequest $ Text.unpack theUri
@@ -139,7 +132,7 @@
   pure $ manyNamed @'["http-bin-test-3", "http-bin-test"] Proxy allHandles
 
 
-typeLevelCheck4 :: IO (HandlesOf '[HttpBinTest3, NginxTest, HttpBinTest])
+typeLevelCheck4 :: IO (HandlesOf '[HttpBinTest3, NginxGateway, HttpBinTest])
 typeLevelCheck4 = do
   allHandles <- setupHandles
   pure $ manyNamed @'["http-bin-test-3", "nginx-test", "http-bin-test"] Proxy allHandles
diff --git a/test/Test/NginxGateway.hs b/test/Test/NginxGateway.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/NginxGateway.hs
@@ -0,0 +1,240 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+
+{- |
+Module      : Test.NginxGateway
+Copyright   : (c) 2022 Tim Emiola
+Maintainer  : Tim Emiola <adetokunbo@emio.la>
+SPDX-License-Identifier: BSD3
+-}
+module Test.NginxGateway
+  ( -- * data types
+    NginxGateway (..)
+  , NginxPrep (..)
+
+    -- * ping via https
+  , pingHttps
+  )
+where
+
+import qualified Data.ByteString.Char8 as C8
+import Data.Data (Proxy (..))
+import Data.Default (Default (..))
+import Data.List (find)
+import Data.Text (Text)
+import qualified Data.Text as Text
+import qualified Data.Text.IO as Text
+import Network.Connection (TLSSettings (..))
+import qualified Network.HTTP.Client as HC
+import qualified Network.HTTP.Client.TLS as HC
+import Network.HTTP.Types.Header (hHost)
+import Network.HTTP.Types.Status (statusCode)
+import Network.TLS (ClientParams (..), HostName, Shared (..), Supported (..), defaultParamsClient)
+import Network.TLS.Extra (ciphersuite_default)
+import Paths_tmp_proc (getDataDir)
+import System.Directory (createDirectory)
+import System.FilePath ((</>))
+import System.IO.Temp (createTempDirectory, getCanonicalTemporaryDirectory)
+import System.Posix.ByteString (getEffectiveGroupID, getEffectiveUserID)
+import System.Posix.Types (GroupID, UserID)
+import System.TmpProc
+  ( HostIpAddress
+  , Pinged (..)
+  , Preparer (..)
+  , Proc (..)
+  , ProcHandle (..)
+  , SlimHandle (..)
+  , SvcURI
+  , ToRunCmd (..)
+  , toPinged
+  )
+import System.X509 (getSystemCertificateStore)
+import Test.Certs.Temp (CertPaths (..), defaultConfig, generateAndStore)
+import Text.Mustache
+  ( ToMustache (..)
+  , automaticCompile
+  , object
+  , substitute
+  , (~>)
+  )
+
+
+-- | Run Nginx as a temporary process.
+instance Proc NginxGateway where
+  -- use this linuxserver.io nginx as it is setup to allow easy override of
+  -- config
+  type Image NginxGateway = "lscr.io/linuxserver/nginx"
+  type Name NginxGateway = "nginx-test"
+  uriOf = httpUri
+  runArgs = []
+  reset _ = pure ()
+  ping = pingHttps
+
+
+instance ToRunCmd NginxGateway NginxPrep where
+  toRunCmd = toRunCmd'
+
+
+instance Preparer NginxGateway NginxPrep where
+  prepare = prepare'
+
+
+{- | Configures launch of a container thats uses nginx as a gateway (a.k.a
+reverse proxy).
+-}
+data NginxGateway = NginxGateway
+  { ngCommonName :: !Text
+  , ngTargetPort :: !Int
+  , ngTargetName :: !Text
+  }
+  deriving (Eq, Show)
+
+
+instance ToMustache NginxGateway where
+  toMustache nt =
+    object
+      [ "commonName" ~> ngCommonName nt
+      , "targetPort" ~> ngTargetPort nt
+      , "targetName" ~> ngTargetName nt
+      ]
+
+
+-- | Values obtained while preparing to launch the nginx container
+data NginxPrep = NginxPrep
+  { npUserID :: !UserID
+  , npGroupID :: !GroupID
+  , npVolumeRoot :: !FilePath
+  }
+  deriving (Eq, Show)
+
+
+instance ToMustache NginxPrep where
+  toMustache np =
+    object
+      [ "targetDir" ~> npVolumeRoot np
+      ]
+
+
+templateName :: FilePath
+templateName = "nginx-test.conf.mustache"
+
+
+toConfCertsDirs :: FilePath -> (FilePath, FilePath)
+toConfCertsDirs topDir = (topDir </> "conf", topDir </> "certs")
+
+
+dockerCertsDir :: FilePath
+dockerCertsDir = "/etc/tmp-proc/certs"
+
+
+dockerConf :: FilePath
+dockerConf = "/data/conf/nginx.conf"
+
+
+createWorkingDirs :: IO FilePath
+createWorkingDirs = do
+  tmpDir <- getCanonicalTemporaryDirectory
+  topDir <- createTempDirectory tmpDir "nginx-test"
+  let (confDir, certsDir) = toConfCertsDirs topDir
+  createDirectory confDir
+  createDirectory certsDir
+  pure topDir
+
+
+toRunCmd' :: NginxGateway -> NginxPrep -> [Text]
+toRunCmd' _ np =
+  -- specify user ID and group ID to fix volume mount permissions
+  -- mount volume /etc/tmp-proc/certs as target-dir/certs
+  -- mount volume /etc/tmp-proc/nginx as target-dir/nginx
+  let (confDir, certsDir) = toConfCertsDirs $ npVolumeRoot np
+      confPath = confDir </> "nginx.conf"
+      envArg name v =
+        [ "-e"
+        , name ++ "=" ++ show v
+        ]
+      volumeArg actualPath hostedPath =
+        [ "-v"
+        , actualPath ++ ":" ++ hostedPath
+        ]
+      confArg = volumeArg confPath $ dockerConf ++ ":ro"
+      certsArg = volumeArg certsDir dockerCertsDir
+      puidArg = envArg "PUID" $ npUserID np
+      guidArg = envArg "GUID" $ npGroupID np
+   in Text.pack <$> confArg ++ certsArg ++ puidArg ++ guidArg
+
+
+-- Prepare
+-- expand the template with commonName to target-dir/nginx
+-- create certs with commonName to target-dir/certs
+-- used fixed cert basenames (certificate.pem and key.pem)
+prepare' :: [SlimHandle] -> NginxGateway -> IO NginxPrep
+prepare' views nt@NginxGateway {ngTargetName = name} = do
+  case find ((== name) . shName) views of
+    Nothing -> error $ "could not find host " <> show name
+    Just _ -> do
+      templateDir <- (</> "templates") <$> getDataDir
+      compiled <- automaticCompile [templateDir] templateName
+      case compiled of
+        Left err -> error $ "the template did not compile:" ++ show err
+        Right template -> do
+          npVolumeRoot <- createWorkingDirs
+          npUserID <- getEffectiveUserID
+          npGroupID <- getEffectiveGroupID
+          let (confDir, cpDir) = toConfCertsDirs npVolumeRoot
+              cp =
+                CertPaths
+                  { cpKey = "key.pem"
+                  , cpCert = "certificate.pem"
+                  , cpDir
+                  }
+              np = NginxPrep {npUserID, npGroupID, npVolumeRoot}
+          generateAndStore cp defaultConfig
+          Text.writeFile (confDir </> "nginx.conf") $ substitute template (nt, np)
+          pure np
+
+
+-- | Make a uri access the http-bin server.
+httpUri :: HostIpAddress -> SvcURI
+httpUri ip = "http://" <> C8.pack (Text.unpack ip) <> "/"
+
+
+pingHttps :: ProcHandle a -> IO Pinged
+pingHttps handle = toPinged @HC.HttpException Proxy $ do
+  gotStatus <- httpsGet handle "/status/200"
+  if gotStatus == 200 then pure OK else pure NotOK
+
+
+-- | Determine the status from a secure Get to host localhost.
+httpsGet :: ProcHandle a -> Text -> IO Int
+httpsGet handle urlPath = do
+  -- _tlsSettings <- TLSSettings <$> _mkClientParams "localHost"
+  let theUri = "https://" <> hAddr handle <> "/" <> Text.dropWhile (== '/') urlPath
+      -- use TLS settings that disable hostname verification. What's not
+      -- currently possible is to actually specify the hostname to use for SNI
+      -- that differs from the connection IP address, that's not supported by
+      -- http-client-tls
+      tlsSettings = TLSSettingsSimple True False False
+  manager <- HC.newTlsManagerWith $ HC.mkManagerSettings tlsSettings Nothing
+  getReq <- HC.parseRequest $ Text.unpack theUri
+  let withHost = getReq {HC.requestHeaders = [(hHost, "localhost")]}
+  statusCode . HC.responseStatus <$> HC.httpLbs withHost manager
+
+
+-- currently unused, since the server specified in ClientParams for SNI is
+-- overridden by Connection, which resets it to the connection hostname
+_mkClientParams :: HostName -> IO ClientParams
+_mkClientParams server = do
+  cs <- getSystemCertificateStore
+  pure $
+    (defaultParamsClient server "")
+      { clientSupported =
+          def
+            { supportedCiphers = ciphersuite_default
+            }
+      , clientShared = def {sharedCAStore = cs}
+      , clientUseServerNameIndication = True
+      }
diff --git a/test/Test/SimpleServer.hs b/test/Test/SimpleServer.hs
--- a/test/Test/SimpleServer.hs
+++ b/test/Test/SimpleServer.hs
@@ -1,14 +1,18 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE OverloadedStrings #-}
 
-module Test.SimpleServer (
-  -- * functions
-  statusOfGet,
-) where
+module Test.SimpleServer
+  ( -- * functions
+    statusOfGet
+  , statusOfGet'
+  )
+where
 
 import Data.Text (Text)
 import qualified Data.Text as Text
+import qualified Network.Connection as HC
 import qualified Network.HTTP.Client as HC
+import Network.HTTP.Client.TLS (mkManagerSettings)
 import Network.HTTP.Types.Status (statusCode)
 import qualified Network.Wai.Handler.Warp as Warp
 
@@ -29,17 +33,18 @@
   let theReq = getReq {HC.port = p}
   statusCode . HC.responseStatus <$> HC.httpLbs theReq manager
 
--- statusOfGet' :: Int -> Text -> IO Int
--- statusOfGet' p path = do
---   manager <- mkSimpleTLSManager
---   runReq (defaultHttpConfig { httpConfigAltManager = Just manager }) $ do
---     r <- req GET (localHttpsUrl path) NoReqBody ignoreResponse $ port p
---     return $ responseStatusCode r
 
--- localHttpsUrl :: Text -> Url 'Https
--- localHttpsUrl p = foldl' (/:) (https "localhost")
---   $ Text.splitOn "/" $ Text.dropWhile (== '/') p
+-- | Determine the status from a Get on localhost.
+statusOfGet' :: Warp.Port -> Text -> IO Int
+statusOfGet' p urlPath = do
+  let theUri = "GET https://localhost/" <> Text.dropWhile (== '/') urlPath
+  manager <- mkSimpleTLSManager
+  getReq <- HC.parseRequest $ Text.unpack theUri
+  let theReq = getReq {HC.port = p}
+  statusCode . HC.responseStatus <$> HC.httpLbs theReq manager
 
--- mkSimpleTLSManager :: IO HC.Manager
--- mkSimpleTLSManager = HC.newManager
---   $ mkManagerSettings (HC.TLSSettingsSimple True False False) Nothing
+
+mkSimpleTLSManager :: IO HC.Manager
+mkSimpleTLSManager =
+  HC.newManager $
+    mkManagerSettings (HC.TLSSettingsSimple True False False) Nothing
diff --git a/test/Test/System/TmpProc/HttpBinSpec.hs b/test/Test/System/TmpProc/HttpBinSpec.hs
--- a/test/Test/System/TmpProc/HttpBinSpec.hs
+++ b/test/Test/System/TmpProc/HttpBinSpec.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
@@ -14,9 +13,11 @@
   , ixReset
   , terminateAll
   )
+import System.TmpProc.Docker (ProcHandle, hOf)
 import Test.Hspec
 import Test.Hspec.TmpProc (tdescribe)
 import Test.HttpBin
+import Test.NginxGateway (NginxGateway, pingHttps)
 
 
 spec :: Spec
@@ -25,7 +26,7 @@
     context "When accessing the services in the list of test tmp procs" $ do
       context "ixPing" $ do
         it "should succeed when accessing the nginx proc by name" $ \hs ->
-          ixPing @"nginx-test" Proxy hs `shouldReturn` OK
+          pingHttps (hOf @(ProcHandle NginxGateway) Proxy hs) `shouldReturn` OK
 
         it "should succeed when accessing the http-bin proc by name" $ \hs ->
           ixPing @"http-bin-test" Proxy hs `shouldReturn` OK
@@ -44,4 +45,4 @@
           ixReset @HttpBinTest Proxy hs `shouldReturn` ()
 
         it "should succeed when accessing the nginx proc by type" $ \hs ->
-          ixReset @NginxTest Proxy hs `shouldReturn` ()
+          ixReset @NginxGateway Proxy hs `shouldReturn` ()
diff --git a/test/Test/System/TmpProc/WarpSpec.hs b/test/Test/System/TmpProc/WarpSpec.hs
--- a/test/Test/System/TmpProc/WarpSpec.hs
+++ b/test/Test/System/TmpProc/WarpSpec.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -15,6 +16,9 @@
 import qualified Network.HTTP.Client as HC
 import Network.HTTP.Types (status200, status400)
 import Network.Wai (Application, pathInfo, responseLBS)
+import Network.Wai.Handler.WarpTLS (tlsSettings)
+import qualified Network.Wai.Handler.WarpTLS as Warp
+import System.IO.Temp (createTempDirectory, getCanonicalTemporaryDirectory)
 import System.TmpProc.Docker
   ( HList (..)
   , HandlesOf
@@ -34,37 +38,70 @@
   , testWithApplication
   , testWithTLSApplication
   )
+import Test.Certs.Temp (CertPaths (..), certificatePath, defaultConfig, generateAndStore, keyPath, withCertPathsInTmp')
 import Test.Hspec
 import Test.Hspec.TmpProc (tdescribe)
 import Test.HttpBin
-import Test.SimpleServer (statusOfGet)
+import Test.NginxGateway (NginxGateway (..))
+import Test.SimpleServer (statusOfGet, statusOfGet')
 
 
 spec :: Spec
 spec = tdescribe "Tmp.Proc: Warp server with Tmp.Proc dependency" $ do
-  beforeAllSpec >> aroundSpec
+  checkBeforeAll prefixHttp setupBeforeAll statusOfGet
+  checkBeforeAll prefixHttps setupBeforeAllTls statusOfGet'
+  httpSpec prefixHttp setupAround statusOfGet
+  httpSpec prefixHttps setupAroundTls statusOfGet'
 
 
-testProcs :: HList '[HttpBinTest]
+type TmpProcs = '[HttpBinTest]
+
+
+testProcs :: HList TmpProcs
 testProcs = only HttpBinTest
 
 
-testApp :: HandlesOf '[HttpBinTest] -> IO Application
+theGateway :: NginxGateway
+theGateway =
+  NginxGateway
+    { ngCommonName = "localhost"
+    , ngTargetPort = 80
+    , ngTargetName = "http-bin-test"
+    }
+
+
+testApp :: HandlesOf TmpProcs -> IO Application
 testApp hs =
   mkTestApp'
     (pingOrFail $ handleOf @"http-bin-test" Proxy hs)
     (pingOrFail $ handleOf @"http-bin-test" Proxy hs)
 
 
-setupBeforeAll :: IO (ServerHandle '[HttpBinTest])
+setupBeforeAll :: IO (ServerHandle TmpProcs)
 setupBeforeAll = runServer testProcs testApp
 
 
--- setupBeforeAllTls :: IO (ServerHandle '[HttpBinTest])
--- setupBeforeAllTls = do
---   tls <- defaultTLSSettings
---   runTLSServer tls testProcs testApp
+setupBeforeAllTls :: IO (ServerHandle TmpProcs)
+setupBeforeAllTls = do
+  cp <- genCertPaths
+  let tls = tlsSettings (certificatePath cp) (keyPath cp)
+  runTLSServer tls testProcs testApp
 
+
+genCertPaths :: IO CertPaths
+genCertPaths = do
+  tmpDir <- getCanonicalTemporaryDirectory
+  cpDir <- createTempDirectory tmpDir "tmp-proc-warp-spec"
+  let cp =
+        CertPaths
+          { cpKey = "key.pem"
+          , cpCert = "certificate.pem"
+          , cpDir
+          }
+  generateAndStore cp defaultConfig
+  pure cp
+
+
 suffixAround, suffixBeforeAll, prefixHttp, prefixHttps :: String
 suffixAround = " when the server is restarted for each test"
 suffixBeforeAll = " when the server starts beforeAll tests"
@@ -72,16 +109,9 @@
 prefixHttps = "Warp+HTTPS:"
 
 
-beforeAllSpec :: Spec
-beforeAllSpec = do
-  checkBeforeAll prefixHttp setupBeforeAll statusOfGet
-
-
--- checkBeforeAll prefixHttps setupBeforeAllTls statusOfGet'
-
 checkBeforeAll ::
   String ->
-  IO (ServerHandle '[HttpBinTest]) ->
+  IO (ServerHandle TmpProcs) ->
   (Int -> Text -> IO Int) ->
   Spec
 checkBeforeAll descPrefix setup getter = beforeAll setup $ afterAll shutdown $ do
@@ -93,29 +123,23 @@
       getter (serverPort sh) "test" `shouldReturn` 200
 
 
-setupAround :: ((HandlesOf '[HttpBinTest], Int) -> IO a) -> IO a
+setupAround :: ((HandlesOf TmpProcs, Int) -> IO a) -> IO a
 setupAround = testWithApplication testProcs testApp
 
 
--- setupAroundTls :: ((HandlesOf '[HttpBinTest], Int) -> IO a) -> IO a
--- setupAroundTls cont = do
---   tls <- defaultTLSSettings
---   testWithTLSApplication tls testProcs testApp cont
-
-aroundSpec :: Spec
-aroundSpec = do
-  checkEachTest prefixHttp setupAround statusOfGet
+setupAroundTls :: ((HandlesOf TmpProcs, Int) -> IO a) -> IO a
+setupAroundTls cont = withCertPathsInTmp' $ \cp -> do
+  let tls = Warp.tlsSettings (certificatePath cp) (keyPath cp)
+  testWithTLSApplication tls testProcs testApp cont
 
 
--- checkEachTest prefixHttps setupAroundTls statusOfGet'
-
-checkEachTest ::
+httpSpec ::
   String ->
-  (ActionWith (HandlesOf '[HttpBinTest], Int) -> IO ()) ->
+  (ActionWith (HandlesOf TmpProcs, Int) -> IO ()) ->
   (Int -> Text -> IO Int) ->
   Spec
-checkEachTest descPrefix setup getter = around setup $ do
-  describe (descPrefix ++ suffixAround) $ do
+httpSpec prefix setup getter = around setup $ do
+  describe (prefix ++ suffixAround) $ do
     it "should ping the proc handle" $ \(h, _) ->
       ixPing @"http-bin-test" Proxy h `shouldReturn` OK
 
@@ -151,7 +175,7 @@
                       fail "tmp proc:httpbin:ping failed"
                   )
   catchHttp $ do
-    gotStatus <- handleGet handle "/status/200"
+    gotStatus <- httpGet handle "/status/200"
     if gotStatus == 200
       then pure ()
       else fail "tmp proc:httpbin:incorrect ping status"
diff --git a/test_certs/certificate.csr b/test_certs/certificate.csr
deleted file mode 100644
--- a/test_certs/certificate.csr
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIIElTCCAn0CAQAwUDELMAkGA1UEBhMCSlAxDDAKBgNVBAgMA0ZVSzERMA8GA1UE
-BwwISXRvc2hpbWExDDAKBgNVBAoMA0RpczESMBAGA1UEAwwJbG9jYWxob3N0MIIC
-IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6I1BtufmkS2ztej42UsL9CKF
-dvO64s1qLjlmKSx9pipR6O47mXqo1GLWthisLycHiVEdhy7/tPeWvuWvWQi3Ts/H
-zvDS290tfKNOsCAC8lRAmW6ttLjJXFCJ9orS+mbCCdYKVwg8W99VKDZtv8krgJLl
-s9GfU3kWNyUAL8V0FHSupZnap659qi2uG9sm822eRzLXvk+SjXG4qlbxyNTX+pEh
-1WWNzshDg+lxp+b7rb6a7qUwOtSFyQTBSkDfIgh0w9nEju2TvKQWQACVujxtnr1F
-nnaQ0PoOnz3AUq0O6sGi+Bw35C6aD/yfeF/u7s8Nt7VRa+zkDa9fNLwdBhrvqvDA
-6ZYuQCjDDLmkCburNQNQWI+M4172A6DwGs9qEWHJPCCNqs1P82GMzaKva7BSebjA
-juwpWdaU8T8UuJQZRDauofhEAqlCkrPRU2h+4d9rA2hYA+1rnOi2A8Ze2YTDm+BS
-gU237oZyj4+d5R/kiQPIPXYVFZocN5luvzcg17EbNRqjR+w6ZiQS7M9Ow5tozqCx
-ocZyjkYEGkQwuDtRnzWphWdZguISY5/wGD6cRLgA28Ww0/MNOvs891GDJyBIAiag
-9xBtdNTA7Q1dGLb72Pn3UP/bSLvxSAFTPsE6x8xmkPuNPgx84KHiV+SqxFz9Y9ea
-wMla4rxAbdoVV3J1J00CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQDUbiS9Tkkn
-5ohDf07CZSsMOJRHsbWCe9UX4IjY9nR+FeHszcOY00H2gCoYLdiKA8JWeeeeBDBr
-ymAhl4WQMaMjUQoPAjTY3v+mNZpltLlYzUYsWl6LVXoFGKk4V9tforx6XGzCcicr
-YF1Vmsr9Bp32GKiqESjdaVBKWp+9FFqZQrI7ymKVbXJ9WdckHCsUTnZWJQbN3Doh
-sy/VWW8Jlq6+gDv9gaLBjXtPfIhw+EU/5zURkmZcRNpwW4TTZbOaR58w64ecWuKn
-k0hmqMN0uA4gj2VwxtErJSAZ3EawwqGEZ8j29eKDWwcZS3ptg+dQUQzMuhF7J1OK
-rz1AmdQViuy3NYMNFNsD0cYeZXfGoe4iwpNxeH6lPbsth5vxIs0eGMrLW5/40fgt
-Kp0NTE23dfkaCHolfCRs6s36WhwGooUn0MnisZDclCYPjgmbt6fyZs2273KC2fUK
-Dlb256jVx1imo00muNATChA2nd1ynrdQgniEZZULGd3s6NPVrLgqCu6we6Vcbn6S
-pH+nwSTSY+jwWPUl41dVbNdc7q72z0TLGlPUrk6DwqVJMunjn8j6X1RyjgfckYQH
-LFAneruxFFd9sHYYDoC6Vq8nu+cyHFlDElbI3Vedclh2ddXZOpDZT8pAwWNM11Et
-+9HudI6f7d/0ttbjxMoxWaewGFsFvJRFmw==
------END CERTIFICATE REQUEST-----
diff --git a/test_certs/certificate.pem b/test_certs/certificate.pem
deleted file mode 100644
--- a/test_certs/certificate.pem
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFHDCCAwQCCQCZ1MePuiS6ezANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJK
-UDEMMAoGA1UECAwDRlVLMREwDwYDVQQHDAhJdG9zaGltYTEMMAoGA1UECgwDRGlz
-MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkwMjI2MDY0MzU5WhcNMTkwMzI4MDY0
-MzU5WjBQMQswCQYDVQQGEwJKUDEMMAoGA1UECAwDRlVLMREwDwYDVQQHDAhJdG9z
-aGltYTEMMAoGA1UECgwDRGlzMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQDojUG25+aRLbO16PjZSwv0IoV287rizWou
-OWYpLH2mKlHo7juZeqjUYta2GKwvJweJUR2HLv+095a+5a9ZCLdOz8fO8NLb3S18
-o06wIALyVECZbq20uMlcUIn2itL6ZsIJ1gpXCDxb31UoNm2/ySuAkuWz0Z9TeRY3
-JQAvxXQUdK6lmdqnrn2qLa4b2ybzbZ5HMte+T5KNcbiqVvHI1Nf6kSHVZY3OyEOD
-6XGn5vutvprupTA61IXJBMFKQN8iCHTD2cSO7ZO8pBZAAJW6PG2evUWedpDQ+g6f
-PcBSrQ7qwaL4HDfkLpoP/J94X+7uzw23tVFr7OQNr180vB0GGu+q8MDpli5AKMMM
-uaQJu6s1A1BYj4zjXvYDoPAaz2oRYck8II2qzU/zYYzNoq9rsFJ5uMCO7ClZ1pTx
-PxS4lBlENq6h+EQCqUKSs9FTaH7h32sDaFgD7Wuc6LYDxl7ZhMOb4FKBTbfuhnKP
-j53lH+SJA8g9dhUVmhw3mW6/NyDXsRs1GqNH7DpmJBLsz07Dm2jOoLGhxnKORgQa
-RDC4O1GfNamFZ1mC4hJjn/AYPpxEuADbxbDT8w06+zz3UYMnIEgCJqD3EG101MDt
-DV0YtvvY+fdQ/9tIu/FIAVM+wTrHzGaQ+40+DHzgoeJX5KrEXP1j15rAyVrivEBt
-2hVXcnUnTQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCOi2MIn+PSjIEKz1p4x2b6
-O4trvi3epP7BXIhseU++JhqR0x+hgR/Xmmir5lw5yuRwmnlG005rz9fLEK1q8W1Q
-MZRQDU/2hX3+JJ/QczIaaOqQrnlzwiOj69TZtBxi9nNxMDtzoUA644s+2yngufxr
-PIag7UupoeQVFrkSRgyREdszMKtZ0d7oZ0EZqEod0uUH89kkI3IE3fWW/fUtEIfV
-ymscYPHlvIBCJQ9c2S/wXNxakXjCwYbiHE8yGeEJxBYcmSuZkei/kLvKmBuTmzo0
-8rENCNSyvL1EBDIe9Gp2pvFhYUepjhq8lsbWV7EjMY+hqiMyuHk7v6HS14nmg9fv
-1+3J61NsunHPzqSYzf3YI8aq1r4JaC644XlRQgrVuZtcH+lD785GTn3tBN0eYEen
-6qGThiUIgC5VzuGrRX4FWoZsAE46NWVU0tMmYnpmEAdJUr3PEEFFkNNG1CzobYPK
-e9otNUiRJ5A9PGCHK9auWkH5/7EJECaO5WW8wgBspQYu4GJM/NF5Yioph81X4XSi
-l6TROBWapD2l3Z7v5kYL0N1SqOvdO2XuJKtKN8GTlSXRDHWg24MhGkb66M70H1Mw
-dJMsxq+zd2SEVFn8+MhPwAN3q78l6W9XRxSn7Ox2VY8g9Unz4f2SIWL0AHPeKHAc
-ES2bGzGq8NsKtYeky1Pjow==
------END CERTIFICATE-----
diff --git a/test_certs/key.pem b/test_certs/key.pem
deleted file mode 100644
--- a/test_certs/key.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-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
------END RSA PRIVATE KEY-----
diff --git a/tmp-proc.cabal b/tmp-proc.cabal
--- a/tmp-proc.cabal
+++ b/tmp-proc.cabal
@@ -1,22 +1,16 @@
 cabal-version:      3.0
 name:               tmp-proc
-version:            0.6.1.0
+version:            0.6.2.0
 synopsis:           Run 'tmp' processes in integration tests
 description:
   @tmp-proc@ runs services in docker containers for use in integration tests.
-
   It aims to make using these services become like accessing /tmp/ processes,
   similar to how /tmp/ file or directories are used.
-
   It aspires to provide a user-friendly API, while including useful features
   such as
-
   * launch of multiple services on docker during test setup
-
   * delayed test execution until the launched services are available
-
   * simplified use of connections to the services from a [WAI](https://hackage.haskell.org/package/wai) server under test
-
   * good integration with haskell testing frameworks like [hspec](https://hspec.github.io)
   and [tasty](https://hackage.haskell.org/package/tasty)
 
@@ -27,19 +21,16 @@
 maintainer:         adetokunbo@users.noreply.github.com
 category:           testing, docker
 bug-reports:        https://github.com/adetokunbo/tmp-proc/issues
-homepage:           https://github.com/adetokunbo/tmp-proc/tree/master/tmp-proc#tmp-proc
+homepage:
+  https://github.com/adetokunbo/tmp-proc/tree/master/tmp-proc#tmp-proc
+
 build-type:         Simple
 data-files:
-  test_certs/*.csr
-  test_certs/*.pem
-extra-source-files:
-  ChangeLog.md
-tested-with:
-  GHC == 8.10.7
-  GHC == 9.0.2
-  GHC == 9.2.8
-  GHC == 9.4.5
+  templates/*.mustache
 
+extra-source-files: ChangeLog.md
+tested-with:        GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.5
+
 source-repository head
   type:     git
   location: https://github.com/adetokunbo/tmp-proc.git
@@ -57,12 +48,14 @@
   build-depends:
     , async       ^>=2.2.1
     , base        >=4.14     && <5
-    , bytestring  >=0.10.8.2 && <0.12.2
-    , mtl         >=2.2 && <2.3 || >= 2.3.1 && <2.4
-    , network     >=2.6.3.6  && <3.2
+    , bytestring  >=0.10.8   && <0.11 || >=0.11.3 && <0.13
+    , fmt         >=0.6      && <0.7
+    , mtl         >=2.2      && <2.3  || >=2.3.1 && <2.4
+    , network     >=2.6.3    && <3.3
     , process     ^>=1.6.3.0
-    , text        >=1.2.3 && <2.2
-    , tls         >=1.7 && <2.2
+    , random      >=1.1      && <1.3
+    , text        >=1.2.3    && <2.2
+    , tls         >=1.7      && <2.2
     , unliftio    ^>=0.2.7
     , wai         >=3.2      && <3.3
     , warp        >=3.3      && <3.5
@@ -75,42 +68,55 @@
   type:             exitcode-stdio-1.0
   main-is:          Spec.hs
   autogen-modules:  Paths_tmp_proc
-
   other-modules:
+    Paths_tmp_proc
     Test.Hspec.TmpProc
     Test.HttpBin
+    Test.NginxGateway
     Test.SimpleServer
     Test.System.TmpProc.Hspec
     Test.System.TmpProc.HttpBinSpec
     Test.System.TmpProc.WarpSpec
-    Paths_tmp_proc
 
   hs-source-dirs:   test
   build-depends:
     , base
     , bytestring
-    , data-default
-    , hspec
-    , http-client
-    , http-types
+    , crypton-connection    >=0.3 && <0.4
+    , crypton-x509-system   >=1.6 && <1.8
+    , data-default          >=0.5 && <0.8
+    , directory             >=1.3 && <1.4
+    , filepath              >=1.4 && <1.6
+    , hspec                 >=2.7 && <2.12
+    , http-client           >=0.5 && <0.8
+    , http-client-tls       >=0.3 && <0.4
+    , http-types            >=0.8
+    , mustache              >=2.3 && <2.5
+    , temporary             >=1.2 && <1.5
+    , test-certs            >=0.1 && <0.2
     , text
+    , tls
     , tmp-proc
     , wai
     , warp
+    , warp-tls
+    , unix                  >=2.7 && <2.9
 
   default-language: Haskell2010
   ghc-options:
     -threaded -rtsopts -with-rtsopts=-N -fno-ignore-asserts -Wall
 
-Flag use-doc-tests
+flag use-doc-tests
   description: Include the doctests in the package tests
   default:     False
 
 test-suite doctests
   if flag(use-doc-tests)
-     buildable:     True
+    buildable: True
+
   else
-     buildable:     False
+    buildable: False
+
   type:             exitcode-stdio-1.0
   main-is:          Main.hs
   build-depends:
@@ -122,20 +128,21 @@
   default-language: Haskell2010
   ghc-options:      -threaded
 
-
-Flag build-the-readme
+flag build-the-readme
   description: Allow the readme to build
   default:     False
 
-
 executable readme
-  if os(windows) || !flag(build-the-readme)
+  if (os(windows) || !flag(build-the-readme))
     buildable: False
+
   else
     buildable: True
 
   build-tool-depends: markdown-unlit:markdown-unlit
-  ghc-options:        -pgmL markdown-unlit -threaded -rtsopts -with-rtsopts=-N
+  ghc-options:
+    -pgmL markdown-unlit -threaded -rtsopts -with-rtsopts=-N
+
   main-is:            README.lhs
   default-language:   Haskell2010
   build-depends:
