diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,11 @@
+## 0.3.0.1
+
+Pre-fetch all packages from Hackage to catch Hackage downtime early.
+
+## 0.3.0.0
+
+* Return progress URL from uploadBundle
+
 ## 0.2.1.4
 
 Generate a `core` file in bundles.
diff --git a/Stackage/CompleteBuild.hs b/Stackage/CompleteBuild.hs
--- a/Stackage/CompleteBuild.hs
+++ b/Stackage/CompleteBuild.hs
@@ -157,11 +157,13 @@
     token <- readFile "/auth-token"
     now <- epochTime
     let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
-    ident <- flip uploadBundle man $ setArgs ghcVer def
+    (ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
         { ubContents = serverBundle now (title ghcVer) slug plan
         , ubAuthToken = decodeUtf8 token
         }
     putStrLn $ "New ident: " ++ unSnapshotIdent ident
+    forM_ mloc $ \loc ->
+        putStrLn $ "Track progress at: " ++ loc
 
     postBuild `catchAny` print
 
diff --git a/Stackage/PerformBuild.hs b/Stackage/PerformBuild.hs
--- a/Stackage/PerformBuild.hs
+++ b/Stackage/PerformBuild.hs
@@ -136,6 +136,22 @@
 
 performBuild' :: PerformBuild -> IO [Text]
 performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
+    -- First make sure to fetch all of the dependencies... just in case Hackage
+    -- has an outage. Don't feel like wasting hours of CPU time.
+    pbLog $ encodeUtf8 "Pre-fetching all packages\n"
+    let toDownload = flip map (mapToList $ bpPackages pbPlan)
+            $ \(name, plan) -> unpack $ concat
+                [ display name
+                , "-"
+                , display $ ppVersion plan
+                ]
+    withCheckedProcess
+        (proc "cabal"
+            $ "fetch"
+            : "--no-dependencies"
+            : toDownload)
+        $ \ClosedStream Inherited Inherited -> return ()
+
     let removeTree' fp = whenM (isDirectory fp) (removeTree fp)
     mapM_ removeTree' [pbInstallDest, pbLogDir]
 
diff --git a/Stackage/Upload.hs b/Stackage/Upload.hs
--- a/Stackage/Upload.hs
+++ b/Stackage/Upload.hs
@@ -51,7 +51,7 @@
 newtype SnapshotIdent = SnapshotIdent { unSnapshotIdent :: Text }
     deriving (Show, Eq, Ord, Hashable, IsString)
 
-uploadBundle :: UploadBundle -> Manager -> IO SnapshotIdent
+uploadBundle :: UploadBundle -> Manager -> IO (SnapshotIdent, Maybe Text)
 uploadBundle UploadBundle {..} man = do
     req1 <- parseUrl $ unpack $ unStackageServer ubServer ++ "/upload"
     req2 <- formDataBody formData req1
@@ -67,7 +67,10 @@
             }
     res <- httpLbs req3 man
     case lookup "x-stackage-ident" $ responseHeaders res of
-        Just snapid -> return $ SnapshotIdent $ decodeUtf8 snapid
+        Just snapid -> return
+            ( SnapshotIdent $ decodeUtf8 snapid
+            , decodeUtf8 <$> lookup "location" (responseHeaders res)
+            )
         Nothing -> error $ "An error occurred: " ++ show res
   where
     params = mapMaybe (\(x, y) -> (x, ) <$> y)
diff --git a/stackage.cabal b/stackage.cabal
--- a/stackage.cabal
+++ b/stackage.cabal
@@ -1,5 +1,5 @@
 name:                stackage
-version:             0.2.1.4
+version:             0.3.0.1
 synopsis:            "Stable Hackage," tools for creating a vetted set of packages from Hackage.
 description:         Please see <http://www.stackage.org/package/stackage> for a description and documentation.
 homepage:            https://github.com/fpco/stackage
