diff --git a/Benchmark.hs b/Benchmark.hs
--- a/Benchmark.hs
+++ b/Benchmark.hs
@@ -20,7 +20,6 @@
 import Data.Time.Clock
 import Control.DeepSeq
 import Control.Monad
-import Data.Monoid
 import Data.Maybe
 
 data BenchmarkResult t = BenchmarkResult { expectedBenchmark :: t, actualBenchmark :: t }
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,14 @@
+keysafe (0.20200214) unstable; urgency=medium
+
+  * Updated many dependencies.
+  * Support building with ghc 8.x.
+  * Stackage lts-14.25.
+  * Downgrade purism's keysafe server from recommended to alternate,
+    mostly because the server is down, and AFAIK has been down for years,
+    and I don't currently know if they plan to ever provide it again.
+
+ -- Joey Hess <id@joeyh.name>  Fri, 14 Feb 2020 13:38:54 -0400
+
 keysafe (0.20180326) unstable; urgency=medium
 
   * Updated to argon2-1.3.
diff --git a/CmdLine.hs b/CmdLine.hs
--- a/CmdLine.hs
+++ b/CmdLine.hs
@@ -14,7 +14,6 @@
 import Tunables
 import qualified Gpg
 import Options.Applicative
-import Data.Monoid
 import qualified Data.ByteString.UTF8 as BU8
 import qualified Data.Text as T
 import System.Directory
diff --git a/Encryption.hs b/Encryption.hs
--- a/Encryption.hs
+++ b/Encryption.hs
@@ -12,7 +12,6 @@
 import Cost
 import ExpensiveHash
 import ByteStrings
-import Data.Monoid
 import Data.Maybe
 import qualified Raaz
 import qualified Raaz.Cipher.AES as Raaz
diff --git a/ExpensiveHash.hs b/ExpensiveHash.hs
--- a/ExpensiveHash.hs
+++ b/ExpensiveHash.hs
@@ -15,7 +15,6 @@
 import qualified Data.ByteString as B
 import qualified Crypto.Argon2 as Argon2
 import Raaz.Core.Encode
-import Data.Monoid
 
 -- | A hash that is expensive to calculate.
 --
diff --git a/HTTP/Client.hs b/HTTP/Client.hs
--- a/HTTP/Client.hs
+++ b/HTTP/Client.hs
@@ -73,8 +73,8 @@
 	go lasterr [] = return $ Left $
 		maybe "no known address" (\err -> "server failure: " ++ show err) lasterr
 	go _ (url:urls) = do
-		manager <- torableManager
-		res <- runClientM a (ClientEnv manager url)
+		mymanager <- torableManager
+		res <- runClientM a (ClientEnv mymanager url Nothing)
 		case res of
 			Left err -> go (Just err) urls
 			Right r -> return (Right r)
diff --git a/Serialization.hs b/Serialization.hs
--- a/Serialization.hs
+++ b/Serialization.hs
@@ -13,7 +13,6 @@
 import qualified Data.ByteString as B
 import qualified Data.ByteString.UTF8 as BU8
 import qualified Data.Text as T
-import Data.Monoid
 import Data.Word
 
 -- | A SecretKeySource is serialized in the form "keytype value".
diff --git a/Servers.hs b/Servers.hs
--- a/Servers.hs
+++ b/Servers.hs
@@ -23,11 +23,11 @@
 		[ServerAddress "vzgrspuxbtnlrtup.onion" 4242]
 		"Provided by Joey Hess. Digital Ocean VPS, located in Indonesia"
 
-	, mk Recommended $ Server (ServerName "keysafe.puri.sm")
+	, mk Alternate $ Server (ServerName "keysafe.puri.sm")
 		[ServerAddress "hlmjmeth356s5ekm.onion" 4242]
 		"Provided by Purism. Located in the EU (Cyprus)"
-		-- Note that while Joey Hess is employed by Purism,
-		-- he does not have access to this server or its data,
+		-- Note that while Joey Hess was employed by Purismat one
+		-- point, he never had access to this server or its data,
 		-- and Purism has policy to never allow him such access.
 		-- This is important since he runs keysafe.joeyh.name.
 
diff --git a/Share.hs b/Share.hs
--- a/Share.hs
+++ b/Share.hs
@@ -20,7 +20,6 @@
 import qualified Data.Text.Encoding as E
 import qualified Data.Set as S
 import Data.Word
-import Data.Monoid
 
 data ShareIdents = ShareIdents
 	{ identsStream :: [S.Set StorableObjectIdent]
diff --git a/Storage.hs b/Storage.hs
--- a/Storage.hs
+++ b/Storage.hs
@@ -19,7 +19,6 @@
 import ByteStrings
 import Data.Maybe
 import Data.List
-import Data.Monoid
 import Control.Monad
 import Control.Concurrent.Thread.Delay
 import Control.Concurrent.Async
diff --git a/Storage/Local.hs b/Storage/Local.hs
--- a/Storage/Local.hs
+++ b/Storage/Local.hs
@@ -20,7 +20,6 @@
 import Utility.Exception
 import qualified Data.ByteString as B
 import qualified Data.ByteString.UTF8 as U8
-import Data.Monoid
 import Data.List
 import Data.Maybe
 import System.IO
@@ -52,7 +51,7 @@
 	section = Section n
 
 localStorageOverride :: FilePath -> IO (Maybe Storage)
-localStorageOverride d = onError' accesserror $ do
+localStorageOverride d = onStorageError' accesserror $ do
 	-- Check that the directory can be written to.
 	createDirectoryIfMissing True d
 	-- Use a filename as long as used for keysafe share files.
@@ -67,7 +66,7 @@
 		return Nothing
 
 store :: Section -> GetShareDir -> StorableObjectIdent -> Share -> IO StoreResult
-store section getsharedir i s = onError (StoreFailure . show) $ do
+store section getsharedir i s = onStorageError (StoreFailure . show) $ do
 	dir <- getsharedir section
 	createDirectoryIfMissing True dir
 	let dest = dir </> shareFile i
@@ -85,7 +84,7 @@
 			return StoreSuccess
 
 retrieve :: Section -> GetShareDir -> ShareNum -> StorableObjectIdent -> IO RetrieveResult
-retrieve section getsharedir n i = onError (RetrieveFailure . show) $ do
+retrieve section getsharedir n i = onStorageError (RetrieveFailure . show) $ do
 	dir <- getsharedir section
 	fd <- openFd (dir </> shareFile i) ReadOnly Nothing defaultFileFlags
 	h <- fdToHandle fd
@@ -103,14 +102,14 @@
 -- Note that the contents of shares is never changed, so it's ok to set the
 -- mtime to the epoch; backup programs won't be confused.
 obscure :: Section -> GetShareDir -> IO ObscureResult
-obscure section getsharedir = onError (ObscureFailure . show) $ do
+obscure section getsharedir = onStorageError (ObscureFailure . show) $ do
 	dir <- getsharedir section
 	fs <- filter isShareFile <$> getDirectoryContents dir
 	mapM_ (\f -> setFileTimes (dir </> f) 0 0) fs
 	return ObscureSuccess
 
 count :: Section -> GetShareDir -> IO CountResult
-count section getsharedir = onError (CountFailure . show) $ do
+count section getsharedir = onStorageError (CountFailure . show) $ do
 	dir <- getsharedir section
 	exists <- doesDirectoryExist dir
 	if exists
@@ -156,11 +155,11 @@
 				| share' == share -> movesuccess f
 			_ -> return StoreAlreadyExists
 
-onError :: (IOException -> a) -> IO a -> IO a
-onError f = onError' (pure . f)
+onStorageError :: (IOException -> a) -> IO a -> IO a
+onStorageError f = onStorageError' (pure . f)
 
-onError' :: (IOException -> IO a) -> IO a -> IO a
-onError' f a = do
+onStorageError' :: (IOException -> IO a) -> IO a -> IO a
+onStorageError' f a = do
 	v <- try a
 	case v of
 		Left e -> f e
diff --git a/Tests.hs b/Tests.hs
--- a/Tests.hs
+++ b/Tests.hs
@@ -20,7 +20,6 @@
 import qualified Data.ByteString.UTF8 as BU8
 import qualified Data.ByteString as B
 import qualified Data.Set as S
-import Data.Monoid
 
 type TestDesc = B.ByteString
 
diff --git a/Types.hs b/Types.hs
--- a/Types.hs
+++ b/Types.hs
@@ -51,7 +51,7 @@
 
 -- | A name associated with a key stored in keysafe.
 newtype Name = Name B.ByteString
-	deriving (Eq, Show, Monoid)
+	deriving (Eq, Show, Monoid, Semigroup)
 
 -- | Source of the secret key stored in keysafe.
 data SecretKeySource = GpgKey KeyId | KeyFile FilePath
diff --git a/Types/Cost.hs b/Types/Cost.hs
--- a/Types/Cost.hs
+++ b/Types/Cost.hs
@@ -26,12 +26,14 @@
 data UsingHardware = UsingCPU | UsingGPU | UsingASIC
 	deriving (Show)
 
-instance Monoid (Cost t) where
-	mempty = CPUCost (Seconds 0) (Divisibility 1)
-	CPUCost (Seconds a) (Divisibility x) `mappend` CPUCost (Seconds b) (Divisibility y) =
+instance Semigroup (Cost t) where
+	CPUCost (Seconds a) (Divisibility x) <> CPUCost (Seconds b) (Divisibility y) =
 		-- Take maximum divisibility, to avoid over-estimating
 		-- the total cost.
 		CPUCost (Seconds (a+b)) (Divisibility $ max x y)
+
+instance Monoid (Cost t) where
+	mempty = CPUCost (Seconds 0) (Divisibility 1)
 
 -- | Operations whose cost can be measured.
 data DecryptionOp
diff --git a/Types/Storage.hs b/Types/Storage.hs
--- a/Types/Storage.hs
+++ b/Types/Storage.hs
@@ -16,7 +16,7 @@
 -- | All known locations where shares can be stored, ordered with
 -- preferred locations first.
 newtype StorageLocations = StorageLocations [Storage]
-	deriving (Monoid)
+	deriving (Monoid, Semigroup)
 
 newtype LocalStorageDirectory = LocalStorageDirectory FilePath
 
diff --git a/keysafe.cabal b/keysafe.cabal
--- a/keysafe.cabal
+++ b/keysafe.cabal
@@ -1,5 +1,5 @@
 Name: keysafe
-Version: 0.20180326
+Version: 0.20200214
 Cabal-Version: >= 1.8
 Maintainer: Joey Hess <joey@kitenet.net>
 Author: Joey Hess
@@ -35,10 +35,10 @@
     -- These are core cryptographic dependencies. It's possible that
     -- changes to these could break backup/restore, so when loosening
     -- the version ranges, it's important to run keysafe --test
-      secret-sharing == 1.0.*
+      secret-sharing == 1.0.1.0
     , argon2 == 1.3.*
-    , raaz == 0.1.1
-    , base (>= 4.5 && < 5.0)
+    , raaz == 0.2.1
+    , base (>= 4.12 && < 5.0)
     , bytestring == 0.10.*
     , text == 1.2.*
     , text-short == 0.1.*
@@ -46,28 +46,28 @@
     -- keysafe backs up and restores.
     , deepseq == 1.4.*
     , random == 1.1.*
-    , time (>= 1.5 && < 1.7)
-    , containers == 0.5.*
+    , time (>= 1.5 && < 1.10)
+    , containers == 0.6.*
     , utf8-string == 1.0.*
     , unix == 2.7.*
     , filepath == 1.4.*
     , split == 0.2.*
     , directory (>= 1.2 && < 1.4)
-    , process (>= 1.2 && < 1.5)
-    , optparse-applicative (>= 0.12 && < 0.14)
+    , process (>= 1.2 && < 1.7)
+    , optparse-applicative (>= 0.12 && < 0.16)
     , readline == 1.0.*
     , zxcvbn-c == 1.0.*
-    , servant (>= 0.7 && < 0.12)
-    , servant-server (>= 0.7 && < 0.12)
-    , servant-client (>= 0.7 && < 0.12)
-    , aeson (>= 0.11 && < 1.2)
+    , servant (>= 0.7 && < 0.18)
+    , servant-server (>= 0.7 && < 0.18)
+    , servant-client (>= 0.7 && < 0.18)
+    , aeson (>= 0.11 && < 1.5)
     , wai == 3.2.*
     , warp == 3.2.*
-    , http-client (>= 0.5.3 && < 0.6)
+    , http-client (>= 0.5.3 && < 0.7)
     , transformers (>= 0.4 && < 0.6)
-    , stm == 2.4.*
+    , stm == 2.5.*
     , socks == 0.5.*
-    , network == 2.6.*
+    , network == 2.8.*
     , token-bucket == 0.1.*
     , bloomfilter == 2.0.*
     , disk-free-space == 0.1.*
@@ -75,9 +75,9 @@
     , unbounded-delays == 0.1.*
     , fast-logger == 2.4.*
     , SafeSemaphore == 0.10.*
-    , async == 2.1.*
-    , unix-compat == 0.4.*
-    , exceptions == 0.8.*
+    , async == 2.2.*
+    , unix-compat (>= 0.4 && < 0.6)
+    , exceptions == 0.10.*
     , random-shuffle == 0.0.*
     , MonadRandom (>= 0.4 && < 0.6)
   Other-Modules:
diff --git a/keysafe.hs b/keysafe.hs
--- a/keysafe.hs
+++ b/keysafe.hs
@@ -32,7 +32,6 @@
 import Data.Maybe
 import Data.Time.Clock
 import Data.Time.Calendar
-import Data.Monoid
 import Data.List
 import Control.DeepSeq
 import Control.Concurrent.Async
