diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Joel Taylor
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/selenium-server.cabal b/selenium-server.cabal
new file mode 100644
--- /dev/null
+++ b/selenium-server.cabal
@@ -0,0 +1,37 @@
+name:                selenium-server
+version:             0.1.0.0
+synopsis:            Run the selenium standalone server for usage with webdriver
+description:         Run the selenium standalone server for usage with webdriver
+homepage:            https://github.com/joelteon/selenium-server.git
+license:             MIT
+license-file:        LICENSE
+author:              Joel Taylor
+maintainer:          me@joelt.io
+category:            Testing
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Test.WebDriver.Server
+  other-modules:       Test.WebDriver.Server.Download
+                       Test.WebDriver.Server.Poll
+  build-depends:       base >=4.6 && <4.7
+                     , conduit
+                     , directory
+                     , filepath
+                     , http-conduit
+                     , http-conduit-downloader
+                     , network
+                     , process
+                     , random
+                     , regex-tdfa
+                     , utf8-string
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+
+test-suite test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      tests
+  main-is:             main.hs
+  build-depends:       base, hspec, selenium-server, text, webdriver >= 0.5.3.2
+  default-language:    Haskell2010
diff --git a/src/Test/WebDriver/Server.hs b/src/Test/WebDriver/Server.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/WebDriver/Server.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE CPP #-}
+
+module Test.WebDriver.Server (
+    -- *** Running the server
+    withServer,
+    defaultSettings,
+    -- *** Configuring the server
+    ServerLocation(..),
+    ServerSettings(..)
+) where
+
+import Control.Exception
+import Network
+import System.IO
+import System.Process
+import qualified Test.WebDriver.Server.Download as Download
+import Test.WebDriver.Server.Poll
+
+-- | Where the server can be found. 'Remote' means @selenium-server@ won't be
+-- started.
+data ServerLocation = Local | Remote HostName PortID
+                    deriving Show
+
+-- | Server settings.
+data ServerSettings = ServerSettings
+                    { serverLocation :: ServerLocation
+                    , jarLocation :: Maybe FilePath
+                    , serverVersion :: Maybe String
+                    } deriving Show
+
+-- | Default server settings: start a local selenium instance, and
+-- download the server jar if none is found.
+defaultSettings :: ServerSettings
+defaultSettings = ServerSettings Local Nothing Nothing
+
+-- | Execute the given 'IO' action with a selenium server running.
+withServer :: ServerSettings -> IO a -> IO a
+withServer ss act = case serverLocation ss of
+    Remote{} -> error "not handled yet"
+    Local -> do
+        jarfile <- case jarLocation ss of
+                       Nothing -> Download.downloadJar (serverVersion ss)
+                       Just f -> return f
+        blackHole <- openFile
+#ifdef WINDOWS
+                         "NUL"
+#else
+                         "/dev/null"
+#endif
+                         AppendMode
+        bracket (do (_,_,_,ch) <- createProcess
+                        (proc "java" ["-jar", jarfile, "-port", "4444"])
+                            { std_in = UseHandle blackHole
+                            , std_out = UseHandle blackHole
+                            , std_err = CreatePipe }
+                    waitForServer
+                    return ch)
+                (\h -> terminateProcess h >> hClose blackHole)
+                (const act)
diff --git a/src/Test/WebDriver/Server/Download.hs b/src/Test/WebDriver/Server/Download.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/WebDriver/Server/Download.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.WebDriver.Server.Download (
+    downloadJar
+) where
+
+import Data.ByteString.UTF8
+import qualified Data.Conduit as C
+import Data.Conduit.Binary (sinkFile)
+import Network.HTTP.Conduit
+import Network.HTTP.Conduit.Downloader
+import System.Directory
+import System.FilePath
+import Text.Regex.TDFA
+import Text.Regex.TDFA.ByteString
+
+downloadJar :: Maybe String -> IO FilePath
+downloadJar Nothing = do
+    latest <- latestJarVersion
+    downloadJar (Just latest)
+
+downloadJar (Just v) = do
+    userdata <- getAppUserDataDirectory "selenium-hs"
+    let fname = "selenium-server-standalone-" ++ v ++ ".jar"
+        jarpath = userdata </> fname
+    e <- doesFileExist jarpath
+    if e
+        then return jarpath
+        else do
+            createDirectoryIfMissing True userdata
+            req <- parseUrl $ "http://selenium.googlecode.com/files/" ++ fname
+            withManager $ \man -> do
+                response <- http req man
+                responseBody response C.$$+- sinkFile jarpath
+            return jarpath
+
+latestJarVersion :: IO String
+latestJarVersion = do
+    bod <- urlGetContents "http://code.google.com/p/selenium/downloads/list"
+    let Right reg = compile defaultCompOpt defaultExecOpt
+                        "selenium-server-standalone-([0-9]+\\.[0-9]+\\.[0-9]+)\\.jar"
+        Right (Just (_,_,_,[vers])) = regexec reg bod
+    return $ toString vers
diff --git a/src/Test/WebDriver/Server/Poll.hs b/src/Test/WebDriver/Server/Poll.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/WebDriver/Server/Poll.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Test.WebDriver.Server.Poll where
+
+import Control.Concurrent
+import Control.Exception
+import Control.Monad
+import Network
+
+waitForServer :: IO ()
+waitForServer = void $ go 0 where
+    go x | x >= (30 :: Int) = error "Timed out after 30 seconds waiting for selenium server."
+    go n = do
+        threadDelay 1000000
+        connectTo "127.0.0.1" (PortNumber 4444)
+            `catch` (\(_ :: IOException) -> go (n + 1))
diff --git a/tests/main.hs b/tests/main.hs
new file mode 100644
--- /dev/null
+++ b/tests/main.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Test.Hspec
+import Test.WebDriver
+import Test.WebDriver.Server
+import Test.WebDriver.Commands.Wait
+
+main :: IO ()
+main = hspec $
+    describe "The server" $
+        it "runs" $ do
+            v <- withServer defaultSettings $
+                runSession defaultSession defaultCaps $ do
+                    openPage "https://joelt.io"
+                    link <- findElem (ByLinkText "stuff")
+                    click link
+                    waitUntil 2000 getTitle
+            v `shouldBe` "joelt.io | everything"
