When running a warp application using run
, it listens on all IP adresses.
For security reasons, I want to listen on localhost
only, handling remote access using a reverse proxy.
How do I need to call run
to only listen on a specific host/IP?
Note: This question intentionally shows no research effort as it was answered Q&A-Style.
The currently accepted answer got broken by changes to conduit and/or warp. Warp no longer exports a Host
constructor. But you don't need it, because the HostPreference
type supports the OverloadedStrings extension, so you can just use a string directly.
This example also eliminates the deprecation warnings by switching to setPort
and setHost
.
{-# LANGUAGE OverloadedStrings #-}
import Network.Wai (responseLBS)
import Network.Wai.Handler.Warp
import Network.HTTP.Types (status200)
import Network.HTTP.Types.Header (hContentType)
main = do
let port = 3000
putStrLn $ "Listening on port " ++ show port
let settings = setPort port $ setHost "127.0.0.1" defaultSettings
runSettings settings app
app req = return $
responseLBS status200 [(hContentType, "text/plain")] "Hello world!"
run
itself can't do that. you need to use runSettings
:
The Settings
parameter you want to pass it contains the information about the hosts it listens on.
The relevant type here is HostPreference
. Although it allows you to specify different wildcards, including IPv6Only
, we'll use the Host
constructor here.
Based on this answer, I'll show a minimal example to listen on localhost only.
Note that accessors like settingsHost
are marked deprecated, but the official documentation for warp 2.1.2.1 still shows an example using settingsTimeout
here.
{-# LANGUAGE OverloadedStrings #-}
import Network.Wai (responseLBS)
import Network.Wai.Handler.Warp
import Network.HTTP.Types (status200)
import Network.HTTP.Types.Header (hContentType)
main = do
let port = 3000
putStrLn $ "Listening on port " ++ show port
let settings = defaultSettings { settingsPort = port,
settingsHost = Host "127.0.0.1" }
runSettings settings app
app req = return $
responseLBS status200 [(hContentType, "text/plain")] "Hello world!"