diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # ChangeLog
 
+## 0.1.27
+
+* New API: `runWithSockets` for servers.
+
 ## 0.1.26
 
 * fix syntax error, for GHC 9.2
diff --git a/Network/QUIC/Parameters.hs b/Network/QUIC/Parameters.hs
--- a/Network/QUIC/Parameters.hs
+++ b/Network/QUIC/Parameters.hs
@@ -289,7 +289,7 @@
 -- | An example parameters obsoleted in the near future.
 --
 -- >>> defaultParameters
--- Parameters {originalDestinationConnectionId = Nothing, maxIdleTimeout = 30000, statelessResetToken = Nothing, maxUdpPayloadSize = 2048, initialMaxData = 1048576, initialMaxStreamDataBidiLocal = 262144, initialMaxStreamDataBidiRemote = 262144, initialMaxStreamDataUni = 262144, initialMaxStreamsBidi = 64, initialMaxStreamsUni = 3, ackDelayExponent = 3, maxAckDelay = 25, disableActiveMigration = False, preferredAddress = Nothing, activeConnectionIdLimit = 5, initialSourceConnectionId = Nothing, retrySourceConnectionId = Nothing, grease = Nothing, greaseQuicBit = True, versionInformation = Nothing}
+-- Parameters {originalDestinationConnectionId = Nothing, maxIdleTimeout = 30000, statelessResetToken = Nothing, maxUdpPayloadSize = 2048, initialMaxData = 16777216, initialMaxStreamDataBidiLocal = 262144, initialMaxStreamDataBidiRemote = 262144, initialMaxStreamDataUni = 262144, initialMaxStreamsBidi = 64, initialMaxStreamsUni = 3, ackDelayExponent = 3, maxAckDelay = 25, disableActiveMigration = False, preferredAddress = Nothing, activeConnectionIdLimit = 5, initialSourceConnectionId = Nothing, retrySourceConnectionId = Nothing, grease = Nothing, greaseQuicBit = True, versionInformation = Nothing}
 defaultParameters :: Parameters
 defaultParameters =
     baseParameters
diff --git a/Network/QUIC/Server.hs b/Network/QUIC/Server.hs
--- a/Network/QUIC/Server.hs
+++ b/Network/QUIC/Server.hs
@@ -2,6 +2,7 @@
 module Network.QUIC.Server (
     -- * Running a QUIC server
     run,
+    runWithSockets,
     stop,
 
     -- * Configuration
diff --git a/Network/QUIC/Server/Reader.hs b/Network/QUIC/Server/Reader.hs
--- a/Network/QUIC/Server/Reader.hs
+++ b/Network/QUIC/Server/Reader.hs
@@ -147,8 +147,7 @@
 ----------------------------------------------------------------
 
 runDispatcher :: Dispatch -> ServerConfig -> ListenSocket -> IO ThreadId
-runDispatcher d conf mysock =
-    forkFinally (dispatcher d conf mysock) $ \_ -> UDP.stop mysock
+runDispatcher d conf mysock = forkIO $ dispatcher d conf mysock
 
 dispatcher :: Dispatch -> ServerConfig -> ListenSocket -> IO ()
 dispatcher d conf mysock = handleLogUnit logAction $ do
diff --git a/Network/QUIC/Server/Run.hs b/Network/QUIC/Server/Run.hs
--- a/Network/QUIC/Server/Run.hs
+++ b/Network/QUIC/Server/Run.hs
@@ -5,6 +5,7 @@
 
 module Network.QUIC.Server.Run (
     run
+  , runWithSockets
   , stop
   ) where
 
@@ -43,7 +44,7 @@
 run :: ServerConfig -> (Connection -> IO ()) -> IO ()
 run conf server = NS.withSocketsDo $ handleLogUnit debugLog $ do
     baseThreadId <- myThreadId
-    E.bracket setup teardown $ \(dispatch,_) -> do
+    E.bracket setup teardown $ \(dispatch,_,_) -> do
         onServerReady $ scHooks conf
         forever $ do
             acc <- accept dispatch
@@ -57,7 +58,36 @@
         -- fixme: the case where sockets cannot be created.
         ssas <- mapM UDP.serverSocket $ scAddresses conf
         tids <- mapM (runDispatcher dispatch conf) ssas
+        return (dispatch, tids, ssas)
+    teardown (dispatch, tids, ssas) = do
+        clearDispatch dispatch
+        mapM_ killThread tids
+        mapM_ UDP.stop ssas
+
+-- | Running a QUIC server.
+--   The action is executed with a new connection
+--   in a new lightweight thread.
+runWithSockets :: [NS.Socket] -> ServerConfig -> (Connection -> IO ()) -> IO ()
+runWithSockets ssas conf server = NS.withSocketsDo $ handleLogUnit debugLog $ do
+    baseThreadId <- myThreadId
+    E.bracket setup teardown $ \(dispatch,_) -> do
+        onServerReady $ scHooks conf
+        forever $ do
+            acc <- accept dispatch
+            void $ forkIO (runServer conf server dispatch baseThreadId acc)
+  where
+    doDebug = isJust $ scDebugLog conf
+    debugLog msg | doDebug   = stdoutLogger ("run: " <> msg)
+                 | otherwise = return ()
+    setup = do
+        dispatch <- newDispatch conf
+        -- fixme: the case where sockets cannot be created.
+        ssas' <- mapM mkSocket ssas
+        tids <- mapM (runDispatcher dispatch conf) ssas'
         return (dispatch, tids)
+    mkSocket s = do
+        sa <- NS.getSocketName s
+        return $ ListenSocket s sa False -- interface specific
     teardown (dispatch, tids) = do
         clearDispatch dispatch
         mapM_ killThread tids
diff --git a/quic.cabal b/quic.cabal
--- a/quic.cabal
+++ b/quic.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               quic
-version:            0.1.26
+version:            0.1.27
 license:            BSD3
 license-file:       LICENSE
 maintainer:         kazu@iij.ad.jp
