diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
 # Revision history for spacecookie
 
+## 0.2.1.0 Systemd Support
+
+* Improved systemd support.
+  * Support for the notify service type
+  * Support for socket activation and socket (fd) storage
+  * To make use of these new features you'll have to update your service files
+* Added `defaultConfig` value to prevent future breakage in software using the
+  library when the `GopherConfig` type is extended.
+* Pretty print IPv6 addresses in logging
+
+## 0.2.0.1 Hackage release
+
+Fixed a problem hindering the hackage release.
+
 ## 0.2.0.0 initial release
 
 * First version. Released on an unsuspecting world. Includes:
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-	 ____                                       _    _      
-	/ ___| _ __   __ _  ___ ___  ___ ___   ___ | | _(_) ___ 
+	 ____                                       _    _
+	/ ___| _ __   __ _  ___ ___  ___ ___   ___ | | _(_) ___
 	\___ \| '_ \ / _` |/ __/ _ \/ __/ _ \ / _ \| |/ / |/ _ \
 	 ___) | |_) | (_| | (_|  __/ (_| (_) | (_) |   <| |  __/
 	|____/| .__/ \__,_|\___\___|\___\___/ \___/|_|\_\_|\___|
@@ -18,7 +18,8 @@
 * is RFC1436-compliant
 * supports info-line in menus (compatible protocol extension)
 * supports gophermaps (see below)
-* includes a library for custom gopher applications
+* provides a library for custom gopher applications ([see documentation](http://hackage.haskell.org/package/spacecookie/docs/Network-Gopher.html))
+* can integrate with systemd using socket activation
 
 ## Configuration
 
@@ -26,7 +27,7 @@
 
 Let's have a quick look at the options:
 
-option     | meaning                                                 
+option     | meaning
 -----------|--------------------------------------------------------------------------------------------------------
 `hostname` | The hostname your spacecookie will be reachable through.
 `user`     | The user that just run spacecookie. It is used to drop root priveleges after binding the server socket.
@@ -39,13 +40,34 @@
 
 	spacecookie /path/to/spacecookie.json
 
-Of course it is more convenient to run it as a system wide demon. For that reason a systemd `spacecookie.service` is provided. You can use it like this:
+Spacecookie runs as a simple process and doesn't fork or write a PID file.
+Therefore you'll need to use a supervisor to run it as a proper daemon.
 
-	systemctl enable spacecookie.service
-	systemctl start  spacecookie.service
+### With systemd
 
-Please note that you have to move the necessary file in place manually at the moment.
+Spacecookie supports systemd socket activation. To set it up you'll need
+to install `spacecookie.service` and `spacecookie.socket` like so:
 
+	cp ./etc/spacecookie.{service,socket} /etc/systemd/system/
+	systemctl daemon-reload
+	systemctl enable spacecookie.socket
+	systemctl start  spacecookie.socket
+	systemctl start  spacecookie.service # optional, started by the socket automatically if needed
+
+Don't forget to change the paths in the systemd files and match the user name in
+`spacecookie.socket` with the one in `spacecookie.json`!
+
+### Without systemd
+
+Spacecookie does **not** require systemd nor depend on it. Since socket
+activation only uses an environment variable and a type unix socket, it
+is very lightweight and can be utilized without using a systemd library
+or dbus.
+
+Spacecookie currently fully supports any GNU/Linux. It should be pretty
+easy to, for example, write a [runit](http://smarden.org/runit/) service
+file.
+
 ## Adding Content
 
 Spacecookie acts as a simple file server, only excluding files that start with a dot.
@@ -73,3 +95,10 @@
 * "Links" to other servers are like file/directory menu entries but the server's hostname and its port must be added (tab-separated).
 
 The file type characters are defined in [RFC1436](https://tools.ietf.org/html/rfc1436#page-10). Detailed documentation on the gophermap format [can be found here](./docs/gophermap-pygopherd.txt).
+
+## HTTP Support?
+
+Spacecookie will never support HTTP to keep the code simple and clean. You can
+however use an HTTP to Gopher Proxy with Spacecookie just fine. Any proxy
+supporting RFC1436 should work, my own [gopher-proxy](https://github.com/sternenseemann/gopher-proxy)
+might work for you.
diff --git a/etc/spacecookie.service b/etc/spacecookie.service
--- a/etc/spacecookie.service
+++ b/etc/spacecookie.service
@@ -1,10 +1,13 @@
 [Unit]
 Description=Spacecookie Gopher Daemon
-After=network.target
+Requires=spacecookie.socket
 
 [Service]
-Type=simple
-ExecStart=/usr/local/bin/spacecookie /usr/local/etc/spacecookie.json
+Type=notify
+ExecStart=/path/to/spacecookie /path/to/spacecookie.json
+FileDescriptorStoreMax=1
+NotifyAccess=main
+StandardError=journal
 
 [Install]
 WantedBy=multi-user.target
diff --git a/etc/spacecookie.socket b/etc/spacecookie.socket
new file mode 100644
--- /dev/null
+++ b/etc/spacecookie.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=Socket for the Spacecookie Gopher Daemon
+
+[Socket]
+BindIPv6Only=both
+SocketGroup=spacecookie
+SocketUser=spacecookie
+
+ListenStream=[::]:70
diff --git a/server/Main.hs b/server/Main.hs
--- a/server/Main.hs
+++ b/server/Main.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 import Config
+import Systemd
+
 import Network.Gopher
 import Network.Gopher.Util (santinizePath, uEncode)
 import Network.Gopher.Util.Gophermap
@@ -18,6 +20,7 @@
 import System.Environment
 import System.FilePath.Posix (takeFileName, takeExtension, (</>), dropDrive, splitDirectories)
 import System.Posix.Directory (changeWorkingDirectory)
+import System.Socket (close)
 
 main :: IO ()
 main = do
@@ -29,7 +32,11 @@
       case config' of
         Just config -> do
           changeWorkingDirectory (rootDirectory config)
-          runGopher (GopherConfig (serverName config) (serverPort config) ((Just (runUserName config)))) spacecookie
+          let cfg = GopherConfig (serverName config) (serverPort config) ((Just (runUserName config)))
+          runGopherManual (systemdSocket cfg)
+                          (notifyReady >> pure ())
+                          (\s -> notifyStopping >> systemdStoreOrClose s)
+                          cfg spacecookie
         Nothing -> error "failed to parse config"
     _ -> error "config file must be given"
 
diff --git a/server/Systemd.hs b/server/Systemd.hs
new file mode 100644
--- /dev/null
+++ b/server/Systemd.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE BlockArguments #-}
+module Systemd
+  ( systemdSocket
+  , notifyReady
+  , notifyStopping
+  , systemdStoreOrClose
+  ) where
+
+import Control.Concurrent.MVar (newMVar, takeMVar, mkWeakMVar)
+import Control.Exception.Base
+import Control.Monad (when, void)
+import Foreign.C.Types (CInt (..))
+import GHC.Conc (closeFdWith)
+import Network.Gopher (setupGopherSocket, GopherConfig (..))
+import System.Exit
+import System.Posix.Types (Fd (..))
+import System.Socket hiding (Error (..))
+import System.Socket.Family.Inet6
+import System.Socket.Type.Stream
+import System.Socket.Protocol.TCP
+import System.Socket.Unsafe (Socket (..))
+import System.Systemd.Daemon (notifyReady, notifyStopping)
+import System.Systemd.Daemon.Fd (storeFd, getActivatedSockets)
+
+foreign import ccall unsafe "close"
+  c_close :: CInt -> IO CInt
+
+-- TODO Check Socket type, ...
+data SystemdException = IncorrectNum | InvalidFd
+  deriving (Eq, Ord)
+
+instance Show SystemdException where
+  show IncorrectNum = "SystemdException: Only exactly one Socket is supported"
+  show InvalidFd    = "SystemdException: Invalid File Descriptor received"
+instance Exception SystemdException
+
+systemdSocket :: GopherConfig -> IO (Socket Inet6 Stream TCP)
+systemdSocket cfg = getActivatedSockets >>= \sockets ->
+  case sockets of
+    Nothing -> setupGopherSocket cfg
+    Just [fd] -> toSocket fd
+    Just _ -> throwIO IncorrectNum
+  where toSocket :: Fd -> IO (Socket Inet6 Stream TCP)
+        toSocket fd = do
+          when (fd < 0) $ throwIO InvalidFd
+          mfd <- newMVar (fromIntegral fd)
+          let s = Socket mfd
+          _ <- mkWeakMVar mfd (close s)
+          pure s
+
+systemdStoreOrClose :: Socket Inet6 Stream TCP -> IO ()
+systemdStoreOrClose s = do
+  fd <- toFd s
+  res <- storeFd fd
+  case res of
+    Just () -> return ()
+    Nothing -> closeFdWith (void . c_close . fromIntegral) fd
+  where toFd :: Socket Inet6 Stream TCP -> IO Fd
+        toFd (Socket mvar) = fmap (Fd . fromIntegral) (takeMVar mvar)
diff --git a/spacecookie.cabal b/spacecookie.cabal
--- a/spacecookie.cabal
+++ b/spacecookie.cabal
@@ -1,20 +1,23 @@
 name:                spacecookie
-version:             0.2.0.1
-synopsis:            gopher server daemon
-description:         simple gopher server daemon
+version:             0.2.1.0
+synopsis:            Gopher Library and Server Daemon
+description:         Simple gopher library that allows writing custom gopher
+                     applications. Also includes a fully-featured gopher server
+                     daemon complete with gophermap-support built on top of it.
 license:             GPL-3
 license-file:        LICENSE
 author:              Lukas Epple
 maintainer:          git@lukasepple.de
 category:            Network
 build-type:          Simple
-cabal-version:       >=1.10
+cabal-version:       >=2.0
 homepage:            https://github.com/sternenseemann/spacecookie
 bug-reports:         https://github.com/sternenseemann/spacecookie/issues
 extra-source-files:  CHANGELOG.md
                      README.md
                      etc/spacecookie.json
                      etc/spacecookie.service
+                     etc/spacecookie.socket
                      docs/gophermap
                      docs/gophermap-pygopherd.txt
                      docs/rfc1436.txt
@@ -34,9 +37,11 @@
                      , aeson
                      , attoparsec
                      , spacecookie
+                     , systemd >= 2.1.0
   hs-source-dirs:      server
   default-language:    Haskell2010
   other-modules:       Config
+                     , Systemd
 
 library
   hs-source-dirs:      src
diff --git a/src/Network/Gopher.hs b/src/Network/Gopher.hs
--- a/src/Network/Gopher.hs
+++ b/src/Network/Gopher.hs
@@ -28,6 +28,8 @@
 * 'ErrorResponse': gopher way to show an error (e. g. if a file is not found). A 'ErrorResponse' results in a menu response with a single entry.
 
 If you use 'runGopher', it is the same story like in the example above, but you can do 'IO' effects. To see a more elaborate example, have a look at the server code in this package.
+
+Note: In practice it is probably best to use record update syntax on 'defaultConfig' which won't break your application every time the config record fields are changed.
 -}
 
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -35,9 +37,12 @@
   -- * Main API
     runGopher
   , runGopherPure
+  , runGopherManual
   , GopherConfig (..)
+  , defaultConfig
   -- * Helper Functions
   , gophermapToDirectoryResponse
+  , setupGopherSocket
   -- * Representations
   -- ** Responses
   , GopherResponse (..)
@@ -82,6 +87,10 @@
                  , cRunUserName   :: Maybe String -- ^ user to run the process as
                  }
 
+-- | Default 'GopherConfig' describing a server on @localhost:70@.
+defaultConfig :: GopherConfig
+defaultConfig = GopherConfig "localhost" 70 Nothing
+
 data Env
   = Env { serverSocket :: Socket Inet6 Stream TCP
         , serverName   :: ByteString
@@ -113,6 +122,9 @@
   (logger, _) <- logger <$> ask
   liftIO $ logger (\t -> "[" <> toLogStr t <> "]" <> (toLogStr logMsg) <> "\n")
 
+prettyAddr :: SocketAddress Inet6 -> String
+prettyAddr (SocketAddressInet6 addr port _ _) = drop 13 (show addr) <> ":" <> show (fromIntegral port)
+
 receiveRequest :: Socket Inet6 Stream TCP -> IO ByteString
 receiveRequest sock = receiveRequest' sock mempty
   where lengthLimit = 1024
@@ -133,21 +145,44 @@
   setGroupID $ userGroupID user
   setUserID $ userID user
 
+-- | Auxiliary function that sets up the listening socket for
+--   'runGopherManual' correctly and starts to listen.
+setupGopherSocket :: GopherConfig -> IO (Socket Inet6 Stream TCP)
+setupGopherSocket cfg = do
+  sock <- (socket :: IO (Socket Inet6 Stream TCP))
+  setSocketOption sock (ReuseAddress True)
+  setSocketOption sock (V6Only False)
+  bind sock (SocketAddressInet6 inet6Any (fromInteger (cServerPort cfg)) 0 0)
+  listen sock 5
+  pure sock
+
 -- | Run a gopher application that may cause effects in 'IO'.
 --   The application function is given the gopher request (path)
 --   and required to produce a GopherResponse.
 runGopher :: GopherConfig -> (String -> IO GopherResponse) -> IO ()
-runGopher cfg f = bracket
-  (socket :: IO (Socket Inet6 Stream TCP))
-  close
+runGopher cfg f = runGopherManual (setupGopherSocket cfg) (pure ()) close cfg f
+
+-- | Same as 'runGopher', but allows you to setup the 'Socket' manually
+--   and calls an action of type @IO ()@ as soon as the server is ready
+--   to accept requests. When the server terminates, it calls the action
+--   of type @Socket Inet6 Stream TCP -> IO ()@ to clean up the socket.
+--
+--   Spacecookie assumes the 'Socket' is properly set up to listen on the
+--   port and host specified in the 'GopherConfig' (i. e. 'bind' and
+--   'listen' have been called). This can be achieved using 'setupGopherSocket'.
+--
+--   This is intended for supporting systemd socket activation and storage.
+--   Only use, if you know what you are doing.
+runGopherManual :: IO (Socket Inet6 Stream TCP) -> IO () -> (Socket Inet6 Stream TCP -> IO ())
+                -> GopherConfig -> (String -> IO GopherResponse) -> IO ()
+runGopherManual sock ready term cfg f = bracket
+  sock
+  term
   (\sock -> do
     env <- initEnv sock (cServerName cfg) (fromInteger (cServerPort cfg)) f
     gopherM env $ do
-      liftIO $ setSocketOption sock (ReuseAddress True)
-      liftIO $ setSocketOption sock (V6Only False)
-      liftIO $ bind sock (SocketAddressInet6 inet6Any (fromInteger (cServerPort cfg)) 0 0)
-      liftIO $ listen sock 5
-      log. LogInfo $ "Now listening [::]:" ++ show (cServerPort cfg)
+      addr <- liftIO $ getAddress sock
+      log . LogInfo $ "Now listening on " ++ prettyAddr addr
 
       -- Change UID and GID if necessary
       if isJust (cRunUserName cfg)
@@ -156,6 +191,8 @@
           log . LogInfo $ "Dropped privileges to " ++ fromJust (cRunUserName cfg)
         else log .LogInfo $ "Privileges were not dropped"
 
+      liftIO $ ready
+
       (forever (acceptAndHandle sock) `catchError`
         (\e -> do
           log . LogError $ show e
@@ -164,25 +201,25 @@
 forkGopherM :: GopherM () -> GopherM ThreadId
 forkGopherM action = ask >>= liftIO . forkIO . (flip gopherM) action
 
-handleIncoming :: Socket Inet6 Stream TCP -> Inet6Address -> GopherM ()
+handleIncoming :: Socket Inet6 Stream TCP -> SocketAddress Inet6 -> GopherM ()
 handleIncoming clientSock addr = do
   req <- liftIO $ uDecode . stripNewline <$> receiveRequest clientSock
-  log . LogInfo $ "Got request '" ++ req ++ "' from " ++ show addr
+  log . LogInfo $ "Got request '" ++ req ++ "' from " ++ prettyAddr addr
 
   fun <- serverFun <$> ask
   res <- liftIO (fun req) >>= response
 
   liftIO $ sendAll clientSock res msgNoSignal
   liftIO $ close clientSock
-  log . LogInfo $ "Closed connection succesfully to " ++ show addr
+  log . LogInfo $ "Closed connection succesfully to " ++ prettyAddr addr
 
 acceptAndHandle :: Socket Inet6 Stream TCP -> GopherM ()
 acceptAndHandle sock = do
-  (clientSock, (SocketAddressInet6 addr _ _ _)) <- liftIO $ accept sock
-  log . LogInfo $ "Accepted Connection from " ++ show addr
+  (clientSock, addr) <- liftIO $ accept sock
+  log . LogInfo $ "Accepted Connection from " ++ prettyAddr addr
   forkGopherM $ handleIncoming clientSock addr `catchError` (\e -> do
     liftIO (close clientSock)
-    log . LogError $ "Closed connection to " ++ show addr ++ " after error: " ++ show e)
+    log . LogError $ "Closed connection to " ++ prettyAddr addr ++ " after error: " ++ show e)
   return ()
 
 -- | Run a gopher application that may not cause effects in 'IO'.
