diff --git a/Annex/Ssh.hs b/Annex/Ssh.hs
--- a/Annex/Ssh.hs
+++ b/Annex/Ssh.hs
@@ -56,8 +56,12 @@
 		-- If it did, a more expensive test would be needed.
 		liftIO $ unlessM (doesFileExist overideconfigfile) $
 			viaTmp writeFile overideconfigfile $ unlines
+				-- Make old version of ssh that does
+				-- not know about Include ignore those
+				-- entries.
+				[ "IgnoreUnknown Include"
 				-- ssh expands "~"
-				[ "Include ~/.ssh/config"
+				, "Include ~/.ssh/config"
 				-- ssh will silently skip the file
 				-- if it does not exist
 				, "Include /etc/ssh/ssh_config"
diff --git a/Assistant/WebApp/Types.hs b/Assistant/WebApp/Types.hs
--- a/Assistant/WebApp/Types.hs
+++ b/Assistant/WebApp/Types.hs
@@ -48,17 +48,17 @@
 	}
 
 mkYesodData "WebApp" $(parseRoutesFile "Assistant/WebApp/routes")
+	  
+excludeStatic [] = True
+excludeStatic (p:_) = p /= "static"
 
 instance Yesod WebApp where
 	{- Require an auth token be set when accessing any (non-static) route -}
-	isAuthorized _ _ = checkAuthToken authToken
+	isAuthorized r _ = checkAuthToken authToken r excludeStatic
 
 	{- Add the auth token to every url generated, except static subsite
 	 - urls (which can show up in Permission Denied pages). -}
 	joinPath = insertAuthToken authToken excludeStatic
-	  where
-		excludeStatic [] = True
-		excludeStatic (p:_) = p /= "static"
 
 	makeSessionBackend = webAppSessionBackend
 	jsLoader _ = BottomOfHeadBlocking
diff --git a/Build/LinuxMkLibs.hs b/Build/LinuxMkLibs.hs
--- a/Build/LinuxMkLibs.hs
+++ b/Build/LinuxMkLibs.hs
@@ -34,7 +34,6 @@
 mklibs :: FilePath -> IO ()
 mklibs top = do
 	fs <- dirContentsRecursive top
-	mapM_ symToHardLink fs
 	exes <- filterM checkExe fs
 	libs <- parseLdd <$> readProcess "ldd" exes
 	glibclibs <- glibcLibs
@@ -63,7 +62,18 @@
 installLinkerShim top linker exe = do
 	createDirectoryIfMissing True (top </> shimdir)
 	createDirectoryIfMissing True (top </> exedir)
-	renameFile exe exedest
+	ifM (isSymbolicLink <$> getSymbolicLinkStatus exe)
+		( do
+			sl <- readSymbolicLink exe
+			nukeFile exe
+			nukeFile exedest
+			-- Assume that for a symlink, the destination
+			-- will also be shimmed.
+			let sl' = ".." </> takeFileName sl </> takeFileName sl
+			print (sl', exedest)
+			createSymbolicLink sl' exedest
+		, renameFile exe exedest
+		)
 	link <- relPathDirToFile (top </> exedir) (top ++ linker)
 	unlessM (doesFileExist (top </> exelink)) $
 		createSymbolicLink link (top </> exelink)
@@ -81,15 +91,6 @@
 	exedest = top </> shimdir </> base
 	exelink = exedir </> base
 
-{- Converting symlinks to hard links simplifies the binary shimming
- - process. -}
-symToHardLink :: FilePath -> IO ()
-symToHardLink f = whenM (isSymbolicLink <$> getSymbolicLinkStatus f) $ do
-	l <- readSymbolicLink f
-	let absl = absPathFrom (parentDir f) l
-	nukeFile f
-	createLink absl f
-
 installFile :: FilePath -> FilePath -> IO ()
 installFile top f = do
 	createDirectoryIfMissing True destdir
@@ -101,7 +102,7 @@
 checkExe f
 	| ".so" `isSuffixOf` f = return False
 	| otherwise = ifM (isExecutable . fileMode <$> getFileStatus f)
-		( checkFileExe <$> readProcess "file" [f]
+		( checkFileExe <$> readProcess "file" ["-L", f]
 		, return False
 		)
 
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,26 @@
+git-annex (6.20161111) unstable; urgency=medium
+
+  * Restarting a crashing git process could result in filename encoding
+    issues when not in a unicode locale, as the restarted processes's
+    handles were not read in raw mode.
+  * Make .git/annex/ssh.config file work with versions of ssh older than
+    7.3, which don't support Include. When used with an older version
+    of ssh, any ServerAliveInterval in ~/.ssh/config will be overridden
+    by .git/annex/ssh.config.
+  * S3: Support the special case endpoint needed for the cn-north-1 region.
+  * Webapp: Don't list the Frankfurt S3 region, as this (and some other new
+    regions) need V4 authorization which the aws library does not yet use.
+  * reinject --known: Avoid second, unncessary checksum of file.
+  * OSX: Remove RPATHs from git-annex binary, which are not needed,
+    slow down startup, and break the OSX Sierra linker.
+  * webapp: Explicitly avoid checking for auth in static subsite
+    requests. Yesod didn't used to do auth checks for that, but this may
+    have changed.
+  * Linux standalone: Avoid using hard links in the tarball so it can be
+    untarred on eg, afs which does not support them.
+
+ -- Joey Hess <id@joeyh.name>  Fri, 11 Nov 2016 14:46:39 -0400
+
 git-annex (6.20161031) unstable; urgency=medium
 
   * Assistant, repair: Fix ignoring of git fsck errors due to
diff --git a/Command/Reinject.hs b/Command/Reinject.hs
--- a/Command/Reinject.hs
+++ b/Command/Reinject.hs
@@ -45,7 +45,7 @@
 	| otherwise = notAnnexed src $ do
 		showStart "reinject" dest
 		next $ ifAnnexed dest
-			(perform src)
+			(\key -> perform src key (verifyKeyContent DefaultVerify UnVerified key src))
 			stop
 startSrcDest _ = error "specify a src file and a dest file"
 
@@ -56,7 +56,7 @@
 	case mkb of
 		Nothing -> error "Failed to generate key"
 		Just (key, _) -> ifM (isKnownKey key)
-			( next $ perform src key
+			( next $ perform src key (return True)
 			, do
 				warning "Not known content; skipping"
 				next $ next $ return True
@@ -65,14 +65,14 @@
 notAnnexed :: FilePath -> CommandStart -> CommandStart
 notAnnexed src = ifAnnexed src (error $ "cannot used annexed file as src: " ++ src)
 
-perform :: FilePath -> Key -> CommandPerform
-perform src key = ifM move
+perform :: FilePath -> Key -> Annex Bool -> CommandPerform
+perform src key verify = ifM move
 	( next $ cleanup key
 	, error "failed"
 	)
   where
 	move = checkDiskSpaceToGet key False $
-		ifM (verifyKeyContent DefaultVerify UnVerified key src)
+		ifM verify
 			( do
 				moveAnnex key src
 				return True
diff --git a/Git/CatFile.hs b/Git/CatFile.hs
--- a/Git/CatFile.hs
+++ b/Git/CatFile.hs
@@ -51,7 +51,7 @@
 	<$> startp "--batch"
 	<*> startp "--batch-check=%(objectname) %(objecttype) %(objectsize)"
   where
-	startp p = CoProcess.rawMode =<< gitCoProcessStart restartable
+	startp p = gitCoProcessStart restartable
 		[ Param "cat-file"
 		, Param p
 		] repo
diff --git a/Git/CheckAttr.hs b/Git/CheckAttr.hs
--- a/Git/CheckAttr.hs
+++ b/Git/CheckAttr.hs
@@ -24,7 +24,7 @@
 checkAttrStart :: [Attr] -> Repo -> IO CheckAttrHandle
 checkAttrStart attrs repo = do
 	currdir <- getCurrentDirectory
-	h <- CoProcess.rawMode =<< gitCoProcessStart True params repo
+	h <- gitCoProcessStart True params repo
 	oldgit <- Git.Version.older "1.7.7"
 	return (h, attrs, oldgit, currdir)
   where
diff --git a/Git/CheckIgnore.hs b/Git/CheckIgnore.hs
--- a/Git/CheckIgnore.hs
+++ b/Git/CheckIgnore.hs
@@ -37,7 +37,7 @@
  -}
 checkIgnoreStart :: Repo -> IO (Maybe CheckIgnoreHandle)
 checkIgnoreStart repo = ifM supportedGitVersion
-	( Just <$> (CoProcess.rawMode =<< gitCoProcessStart True params repo')
+	( Just <$> gitCoProcessStart True params repo'
 	, return Nothing
 	)
   where
diff --git a/Git/HashObject.hs b/Git/HashObject.hs
--- a/Git/HashObject.hs
+++ b/Git/HashObject.hs
@@ -20,7 +20,7 @@
 type HashObjectHandle = CoProcess.CoProcessHandle
 
 hashObjectStart :: Repo -> IO HashObjectHandle
-hashObjectStart = CoProcess.rawMode <=< gitCoProcessStart True
+hashObjectStart = gitCoProcessStart True
 	[ Param "hash-object"
 	, Param "-w"
 	, Param "--stdin-paths"
diff --git a/Git/Tree.hs b/Git/Tree.hs
--- a/Git/Tree.hs
+++ b/Git/Tree.hs
@@ -59,7 +59,7 @@
 withMkTreeHandle :: (MonadIO m, MonadMask m) => Repo -> (MkTreeHandle -> m a) -> m a
 withMkTreeHandle repo a = bracketIO setup cleanup (a . MkTreeHandle)
   where
-	setup = CoProcess.rawMode =<< gitCoProcessStart False ps repo
+	setup = gitCoProcessStart False ps repo
 	ps = [Param "mktree", Param "--batch", Param "-z"]
 	cleanup = CoProcess.stop
 
diff --git a/Remote/Helper/AWS.hs b/Remote/Helper/AWS.hs
--- a/Remote/Helper/AWS.hs
+++ b/Remote/Helper/AWS.hs
@@ -50,12 +50,18 @@
 		[ ("US East (N. Virginia)", [S3Region "US", GlacierRegion "us-east-1"])
 		, ("US West (Oregon)", [BothRegion "us-west-2"])
 		, ("US West (N. California)", [BothRegion "us-west-1"])
-		, ("EU (Frankfurt)", [BothRegion "eu-central-1"])
 		, ("EU (Ireland)", [S3Region "EU", GlacierRegion "eu-west-1"])
 		, ("Asia Pacific (Singapore)", [S3Region "ap-southeast-1"])
 		, ("Asia Pacific (Tokyo)", [BothRegion "ap-northeast-1"])
 		, ("Asia Pacific (Sydney)", [S3Region "ap-southeast-2"])
 		, ("South America (São Paulo)", [S3Region "sa-east-1"])
+		-- These need signature V4 support, which has not landed in
+		-- the aws library.
+		-- See https://github.com/aristidb/aws/pull/199
+		-- , ("EU (Frankfurt)", [BothRegion "eu-central-1"])
+		-- , ("Asia Pacific (Seoul)", [S3Region "ap-northeast-2"])
+		-- , ("Asia Pacific (Mumbai)", [S3Region "ap-south-1"])
+		-- , ("US East (Ohio)", [S3Region "us-east-2"])
 		]
 
 	fromServiceRegion (BothRegion s) = s
@@ -69,6 +75,7 @@
 s3HostName :: Region -> B.ByteString
 s3HostName "US" = "s3.amazonaws.com"
 s3HostName "EU" = "s3-eu-west-1.amazonaws.com"
+s3HostName "cn-north-1" = "s3.cn-north-1.amazonaws.com.cn"
 s3HostName r = encodeUtf8 $ T.concat ["s3-", r, ".amazonaws.com"]
 
 s3DefaultHost :: String
diff --git a/Utility/CoProcess.hs b/Utility/CoProcess.hs
--- a/Utility/CoProcess.hs
+++ b/Utility/CoProcess.hs
@@ -13,7 +13,6 @@
 	start,
 	stop,
 	query,
-	rawMode
 ) where
 
 import Common
@@ -44,7 +43,15 @@
 start' :: CoProcessSpec -> IO CoProcessState
 start' s = do
 	(pid, from, to) <- startInteractiveProcess (coProcessCmd s) (coProcessParams s) (coProcessEnv s)
+	rawMode from
+	rawMode to
 	return $ CoProcessState pid to from s
+  where
+	rawMode h = do
+		fileEncoding h
+#ifdef mingw32_HOST_OS
+		hSetNewlineMode h noNewlineTranslation
+#endif
 
 stop :: CoProcessHandle -> IO ()
 stop ch = do
@@ -79,16 +86,3 @@
 			{ coProcessNumRestarts = coProcessNumRestarts (coProcessSpec s) - 1 }
 		putMVar ch s'
 		query ch send receive
-
-rawMode :: CoProcessHandle -> IO CoProcessHandle
-rawMode ch = do
-	s <- readMVar ch
-	raw $ coProcessFrom s
-	raw $ coProcessTo s
-	return ch
-  where
-	raw h = do
-		fileEncoding h
-#ifdef mingw32_HOST_OS
-		hSetNewlineMode h noNewlineTranslation
-#endif
diff --git a/Utility/WebApp.hs b/Utility/WebApp.hs
--- a/Utility/WebApp.hs
+++ b/Utility/WebApp.hs
@@ -182,15 +182,20 @@
  -
  - Note that the usual Yesod error page is bypassed on error, to avoid
  - possibly leaking the auth token in urls on that page!
+ -
+ - If the predicate does not match the route, the auth parameter is not
+ - needed.
  -}
-checkAuthToken :: Yesod.MonadHandler m => (Yesod.HandlerSite m -> AuthToken) -> m Yesod.AuthResult
-checkAuthToken extractAuthToken = do
-	webapp <- Yesod.getYesod
-	req <- Yesod.getRequest
-	let params = Yesod.reqGetParams req
-	if (toAuthToken <$> lookup "auth" params) == Just (extractAuthToken webapp)
-		then return Yesod.Authorized
-		else Yesod.sendResponseStatus unauthorized401 ()
+checkAuthToken :: Yesod.MonadHandler m => Yesod.RenderRoute site => (Yesod.HandlerSite m -> AuthToken) -> Yesod.Route site -> ([T.Text] -> Bool) -> m Yesod.AuthResult
+checkAuthToken extractAuthToken r predicate
+	| not (predicate (fst (Yesod.renderRoute r))) = return Yesod.Authorized
+	| otherwise = do
+		webapp <- Yesod.getYesod
+		req <- Yesod.getRequest
+		let params = Yesod.reqGetParams req
+		if (toAuthToken <$> lookup "auth" params) == Just (extractAuthToken webapp)
+			then return Yesod.Authorized
+			else Yesod.sendResponseStatus unauthorized401 ()
 
 {- A Yesod joinPath method, which adds an auth cgi parameter to every
  - url matching a predicate, containing a token extracted from the
diff --git a/git-annex.cabal b/git-annex.cabal
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -1,5 +1,5 @@
 Name: git-annex
-Version: 6.20161031
+Version: 6.20161111
 Cabal-Version: >= 1.8
 License: GPL-3
 Maintainer: Joey Hess <id@joeyh.name>
