diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,15 @@
+propellor (3.2.3) unstable; urgency=medium
+
+  * Improve extraction of gpg secret key id list, to work with gpg 2.1.
+  * The propellor wrapper checks if ./config.hs exists; if so it runs
+    using the configuration in the current directory, rather than
+    ~/.propellor/config.hs
+  * Debootstap: Fix too tight permissions lock down of debootstrapped
+    chroots, which prevented non-root users from doing anything in the
+    chroot.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 22 Nov 2016 11:36:18 -0400
+
 propellor (3.2.2) unstable; urgency=medium
 
   * Added Linode.serialGrub property.
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+propellor (3.2.3) unstable; urgency=medium
+
+  * Improve extraction of gpg secret key id list, to work with gpg 2.1.
+  * The propellor wrapper checks if ./config.hs exists; if so it runs
+    using the configuration in the current directory, rather than
+    ~/.propellor/config.hs
+  * Debootstap: Fix too tight permissions lock down of debootstrapped
+    chroots, which prevented non-root users from doing anything in the
+    chroot.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 22 Nov 2016 11:36:18 -0400
+
 propellor (3.2.2) unstable; urgency=medium
 
   * Added Linode.serialGrub property.
diff --git a/joeyconfig.hs b/joeyconfig.hs
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -12,7 +12,6 @@
 import qualified Propellor.Property.Cron as Cron
 import qualified Propellor.Property.Sudo as Sudo
 import qualified Propellor.Property.User as User
-import qualified Propellor.Property.Group as Group
 import qualified Propellor.Property.Hostname as Hostname
 import qualified Propellor.Property.Tor as Tor
 import qualified Propellor.Property.Dns as Dns
@@ -35,7 +34,6 @@
 import qualified Propellor.Property.HostingProvider.DigitalOcean as DigitalOcean
 import qualified Propellor.Property.SiteSpecific.GitHome as GitHome
 import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder
-import qualified Propellor.Property.SiteSpecific.IABak as IABak
 import qualified Propellor.Property.SiteSpecific.Branchable as Branchable
 import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites
 import Propellor.Property.DiskImage
@@ -58,7 +56,6 @@
 	, beaver
 	, pell
 	, keysafe
-	, iabak
 	] ++ monsters
 
 testvm :: Host
@@ -87,7 +84,6 @@
 
 	& Apt.buildDep ["git-annex"] `period` Daily
 
-	& JoeySites.postfixClientRelay (Context "darkstar.kitenet.net")
 	& JoeySites.dkimMilter
 	& JoeySites.alarmClock "*-*-* 7:30" (User "joey")
 		"/usr/bin/timeout 45m /home/joey/bin/goodmorning"
@@ -113,9 +109,6 @@
 gnu = host "gnu.kitenet.net" $ props
 	& Apt.buildDep ["git-annex"] `period` Daily
 
-	& JoeySites.postfixClientRelay (Context "gnu.kitenet.net")
-	& JoeySites.dkimMilter
-
 clam :: Host
 clam = host "clam.kitenet.net" $ props
 	& standardSystem Unstable X86_64
@@ -512,45 +505,6 @@
 		[ "keysafe --store-directory", datadir, "--backup-server", backupdir
 		, "&& rsync -a --delete --max-delete 3 ",  backupdir , rsyncnetbackup
 		]
-
-iabak :: Host
-iabak = host "iabak.archiveteam.org" $ props
-	& ipv4 "124.6.40.227"
-	& Hostname.sane
-	& osDebian Testing X86_64
-	& Systemd.persistentJournal
-	& Cron.runPropellor (Cron.Times "30 * * * *")
-	& Apt.stdSourcesList `onChange` Apt.upgrade
-	& Apt.installed ["git", "ssh"]
-	& Ssh.hostKeys (Context "iabak.archiveteam.org")
-		[ (SshDsa, "ssh-dss AAAAB3NzaC1kc3MAAACBAMhuYTshLxavWCpfyJxg3j/GWyIRlL3VTharsfUTzMOqyMSWantZjflfJX21z2KzFDtPEA711GYztsgMVXMrsPQInaOKNISe/R9cfgnEktKTxeppWTfw0GTNcpCeeecddU0FCPVW3a6yDoT6+Rv0jPvkQoDGmhQ40MhauMrO0mJ9AAAAFQDpCbXG8o/3Sg7wrsp5abizJoQ0yQAAAIEAxxyHo/ZhDPP+EWtDS05s5dwiDMUsxIllk1NeleAOQIyLtFkaifOeskDJybIPWYPGX1trjcPoGuXJ5GBYrRaPiu6FBvYdYMFRLr4uNBsaSHHqlHhBPkP3RzCrdUyau4XyjdE4iA0EQlO+u11A+o3f7aTuJSveM0YRfbqvaatG89EAAACAWd0h0SkRLnGjBzkou0SQfYujFY9ilhWXPWV/oOs+bieDSpvfmnaEfLSinVFRrJPvQp/dtpxPLEm+StrK3w6dmwTZVUM5JEoB1mRjBkVs6gPC9PVVg9qLpzC2/x+r5cTfrffjyRrlPdkwLKpO6oiPxTIxAyCW8ixjafkxe2hAeJo=")
-		, (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDP13oPRLRY0V9ZDWojb8TgHbUdE30Nq3b541TwPmlLMbYPAhldxGHkuXGlX8g9/FYP/1AgkPcxs2Uc61ZV+1Ss7q7t52f4R0bO4WHqxfdXHd9FlLzMLWxMU3aMr693pGlhnUp3/xH6O6/+bNEIo3VGGgv9XDr2cAxypS9J7X9ibHZcZ3BGvoCR+nnFJ00ERG2tREKZBPDWKk76lhCiM21fG/CSmcApXaA45FHDaM9/2Clj1sXvoS72f0hEKpl1m08sUx+F0GPzQESnKqNFl+xXdYPPbfhdrgCnDmx9tL5NnXsJU2beFiuxpICOeB1HV6DJsdlO18WqwXYhOg/2A1H3")
-		, (SshEcdsa, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHb0kXcrF5ThwS8wB0Hez404Zp9bz78ZxEGSqnwuF4d/N3+bymg7/HAj7l/SzRoEXKHsJ7P5320oMxBHeM16Y+k=")
-		]
-	& Apt.installed ["etckeeper", "sudo"]
-	-- vital but generic tools
-	& Apt.installed ["vim", "screen", "tmux", "less", "emacs-nox", "netcat", "nano"]
-	-- tools for creating shards
-	& Apt.installed ["jq", "python3", "python3-aiohttp"]
-	& User.hasSomePassword (User "root")
-	& propertyList "admin accounts"
-		(toProps $ map User.accountFor admins
-		        ++ map (Group.hasUser (Group "staff")) admins
-		        ++ map Sudo.enabledFor admins)
-	& User.hasSomePassword (User "joey")
-	& GitHome.installedFor (User "joey")
-	& Ssh.authorizedKey (User "db48x") "ssh-rsa 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 db48x@anglachel"
-	& Ssh.authorizedKey (User "db48x") "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJQkqIgZ7D8WHW5Y3o+fpZC/4xtv/3IQrORJrTPCt7KY db48x@erebor"
-	& Ssh.authorizedKey (User "hcross") "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP5OhU2Lita9RdjPkX9N0w9wZnmVlednUDEx24bVn4Mk IABAK key - Harry C"
-	& Ssh.authorizedKey (User "kaz") "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHhFYMd9Htlf9wPZzIDyqbYYNwuo3m+kWQ9/pfAD/TE9 Kaz IABAK"
-	& Ssh.authorizedKey (User "yipdw") "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEo2mGPw2TTJMHp7G86hMBh6n9/+abzg1oXIIlkwWwzo trythil@aglarond"
-	& Ssh.noPasswords
-	& IABak.gitServer monsters
-	& IABak.registrationServer monsters
-	& IABak.graphiteServer
-	& IABak.publicFace
-  where
-	admins = map User ["joey", "db48x", "hcross", "kaz", "yipdw"]
 
        --'                        __|II|      ,.
      ----                      __|II|II|__   (  \_,/\
diff --git a/propellor.cabal b/propellor.cabal
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -1,5 +1,5 @@
 Name: propellor
-Version: 3.2.2
+Version: 3.2.3
 Cabal-Version: >= 1.8
 License: BSD2
 Maintainer: Joey Hess <id@joeyh.name>
@@ -158,7 +158,6 @@
     Propellor.Property.SiteSpecific.JoeySites
     Propellor.Property.SiteSpecific.GitAnnexBuilder
     Propellor.Property.SiteSpecific.Branchable
-    Propellor.Property.SiteSpecific.IABak
     Propellor.PropAccum
     Propellor.Utilities
     Propellor.CmdLine
diff --git a/src/Propellor/Gpg.hs b/src/Propellor/Gpg.hs
--- a/src/Propellor/Gpg.hs
+++ b/src/Propellor/Gpg.hs
@@ -33,21 +33,42 @@
 listPubKeys :: IO [KeyId]
 listPubKeys = do
 	keyring <- privDataKeyring
-	map fst <$> listKeys ("--list-public-keys" : useKeyringOpts keyring)
+	let listopts =
+		[ "--list-public-keys"
+		, "--with-colons"
+		, "--fixed-list-mode"
+		] ++ useKeyringOpts keyring
+	gpgbin <- getGpgBin
+	parse . lines <$> readProcess gpgbin listopts
+  where
+	parse = mapMaybe (extract . split ":")
+	extract ("pub":_:_:_:f:_) = Just f
+	extract _ = Nothing
 
+-- Lists all of the user's secret keys.
 listSecretKeys :: IO [(KeyId, String)]
-listSecretKeys = listKeys ["--list-secret-keys"]
-
-listKeys :: [String] -> IO [(KeyId, String)]
-listKeys ps = do
+listSecretKeys = do
 	gpgbin <- getGpgBin
-	parse . lines <$> readProcess gpgbin listopts
+	parse . lines <$> readProcess gpgbin
+		[ "--list-secret-keys"
+		, "--with-colons"
+		, "--fixed-list-mode"
+		]
   where
-	listopts = ps ++ ["--with-colons"]
-	parse = mapMaybe (keyIdField . split ":")
-	keyIdField (t:_:_:_:f:_:_:_:_:n:_)
-		| t == "pub" || t == "sec" = Just (f, n)
-	keyIdField _ = Nothing
+	parse = extract [] Nothing . map (split ":")
+	extract c (Just keyid) (("uid":_:_:_:_:_:_:_:_:userid:_):rest) =
+		extract ((keyid, userid):c) Nothing rest
+	extract c (Just keyid) rest@(("sec":_):_) =
+		extract ((keyid, ""):c) Nothing rest
+	extract c (Just keyid) rest@(("pub":_):_) =
+		extract ((keyid, ""):c) Nothing rest
+	extract c (Just keyid) (_:rest) =
+		extract c (Just keyid) rest
+	extract c _ [] = c
+	extract c _ (("sec":_:_:_:keyid:_):rest) =
+		extract c (Just keyid) rest
+	extract c k (_:rest) =
+		extract c k rest
 
 useKeyringOpts :: FilePath -> [String]
 useKeyringOpts keyring =
diff --git a/src/Propellor/Property/Debootstrap.hs b/src/Propellor/Property/Debootstrap.hs
--- a/src/Propellor/Property/Debootstrap.hs
+++ b/src/Propellor/Property/Debootstrap.hs
@@ -51,18 +51,15 @@
 built target system config = built' (setupRevertableProperty installed) target system config
 
 built' :: Property Linux -> FilePath -> System -> DebootstrapConfig -> Property Linux
-built' installprop target system@(System _ arch) config =
-	check (unpopulated target <||> ispartial) setupprop
-		`requires` installprop
+built' installprop target system@(System _ arch) config = 
+	go `before` oldpermfix
   where
+	go = check (unpopulated target <||> ispartial) setupprop
+		`requires` installprop
+
 	setupprop :: Property Linux
 	setupprop = property ("debootstrapped " ++ target) $ liftIO $ do
 		createDirectoryIfMissing True target
-		-- Don't allow non-root users to see inside the chroot,
-		-- since doing so can allow them to do various attacks
-		-- including hard link farming suid programs for later
-		-- exploitation.
-		modifyFileMode target (removeModes [otherReadMode, otherExecuteMode, otherWriteMode])
 		suite <- case extractSuite system of
 			Nothing -> errorMessage $ "don't know how to debootstrap " ++ show system
 			Just s -> pure s
@@ -86,6 +83,15 @@
 			return True
 		, return False
 		)
+	
+	-- May want to remove this after some appropriate length of time,
+	-- as it's a workaround for chroots set up with too tight
+	-- permissions.
+	oldpermfix :: Property Linux
+	oldpermfix = property ("fixed old chroot file mode") $ do
+		liftIO $ modifyFileMode target $
+			addModes [otherReadMode, otherExecuteMode]
+		return NoChange
 
 extractSuite :: System -> Maybe String
 extractSuite (System (Debian _ s) _) = Just $ Apt.showSuite s
diff --git a/src/Propellor/Property/SiteSpecific/IABak.hs b/src/Propellor/Property/SiteSpecific/IABak.hs
deleted file mode 100644
--- a/src/Propellor/Property/SiteSpecific/IABak.hs
+++ /dev/null
@@ -1,121 +0,0 @@
-module Propellor.Property.SiteSpecific.IABak where
-
-import Propellor.Base
-import qualified Propellor.Property.Apt as Apt
-import qualified Propellor.Property.Git as Git
-import qualified Propellor.Property.Cron as Cron
-import qualified Propellor.Property.File as File
-import qualified Propellor.Property.Apache as Apache
-import qualified Propellor.Property.User as User
-import qualified Propellor.Property.Ssh as Ssh
-
-repo :: String
-repo = "https://github.com/ArchiveTeam/IA.BAK/"
-
-userrepo :: String
-userrepo = "git@gitlab.com:archiveteam/IA.bak.users.git"
-
-publicFace :: Property DebianLike
-publicFace = propertyList "iabak public face" $ props
-	& Git.cloned (User "root") repo "/usr/local/IA.BAK" (Just "server")
-	& Apt.serviceInstalledRunning "apache2"
-	& Cron.niceJob "graph-gen" (Cron.Times "*/10 * * * *") (User "root") "/"
-		"/usr/local/IA.BAK/web/graph-gen.sh"
-
-gitServer :: [Host] -> Property (HasInfo + DebianLike)
-gitServer knownhosts = propertyList "iabak git server" $ props
-	& Git.cloned (User "root") repo "/usr/local/IA.BAK" (Just "server")
-	& Git.cloned (User "root") repo "/usr/local/IA.BAK/client" (Just "master")
-	& Ssh.userKeys (User "root") (Context "IA.bak.users.git") sshKeys
-	& Ssh.knownHost knownhosts "gitlab.com" (User "root")
-	& Git.cloned (User "root") userrepo "/usr/local/IA.BAK/pubkeys" (Just "master")
-	& Apt.serviceInstalledRunning "apache2"
-	& "/usr/lib/cgi-bin/pushme.cgi" `File.isSymlinkedTo` File.LinkTarget "/usr/local/IA.BAK/pushme.cgi"
-	& File.containsLine "/etc/sudoers" "www-data ALL=NOPASSWD:/usr/local/IA.BAK/pushed.sh"
-	& Cron.niceJob "shardstats" (Cron.Times "*/30 * * * *") (User "root") "/"
-		"/usr/local/IA.BAK/shardstats-all"
-	& Cron.niceJob "shardmaint" Cron.Daily (User "root") "/"
-		"/usr/local/IA.BAK/shardmaint-fast; /usr/local/IA.BAK/shardmaint"
-	& Apt.installed ["git-annex"]
-	& Apt.installed ["libmail-sendmail-perl"]
-	& Cron.niceJob "expireemailer" Cron.Daily (User "root") 
-		"/usr/local/IA.BAK"
-		"./expireemailer"
-
-registrationServer :: [Host] -> Property (HasInfo + DebianLike)
-registrationServer knownhosts = propertyList "iabak registration server" $ props
-	& User.accountFor (User "registrar")
-	& Ssh.userKeys (User "registrar") (Context "IA.bak.users.git") sshKeys
-	& Ssh.knownHost knownhosts "gitlab.com" (User "registrar")
-	& Git.cloned (User "registrar") repo "/home/registrar/IA.BAK" (Just "server")
-	& Git.cloned (User "registrar") userrepo "/home/registrar/users" (Just "master")
-	& Apt.serviceInstalledRunning "apache2"
-	& Apt.installed ["perl", "perl-modules"]
-	& link `File.isSymlinkedTo` File.LinkTarget "/home/registrar/IA.BAK/registrar/register.cgi"
-	& cmdProperty "chown" ["-h", "registrar:registrar", link]
-		`changesFile` link
-	& File.containsLine "/etc/sudoers" "www-data ALL=(registrar) NOPASSWD:/home/registrar/IA.BAK/registrar/register.pl"
-	& Apt.installed ["kgb-client"]
-	& File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" anyContext
-		`requires` File.dirExists "/etc/kgb-bot/"
-  where
-	link = "/usr/lib/cgi-bin/register.cgi"
-
-sshKeys :: [(SshKeyType, Ssh.PubKeyText)]
-sshKeys = 
-	[ (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoiE+CPiIQyfWnl/E9iKG3eo4QzlH30vi7xAgKolGaTu6qKy4XPtl+8MNm2Dqn9QEYRVyyOT/XH0yP5dRc6uyReT8dBy03MmLkVbj8Q+nKCz5YOMTxrY3sX6RRXU1zVGjeVd0DtC+rKRT7reoCxef42LAJTm8nCyZu/enAuso5qHqBbqulFz2YXEKfU1SEEXLawtvgGck1KmCyg+pqazeI1eHWXrojQf5isTBKfPQLWVppBkWAf5cA4wP5U1vN9dVirIdw66ds1M8vnGlkTBjxP/HLGBWGYhZHE7QXjXRsk2RIXlHN9q6GdNu8+F3HXS22mst47E4UAeRoiXSMMtF5")
-	]
-
-graphiteServer :: Property (HasInfo + DebianLike)
-graphiteServer = propertyList "iabak graphite server" $ props
-	& Apt.serviceInstalledRunning "apache2"
-	& Apt.installed ["libapache2-mod-wsgi", "graphite-carbon", "graphite-web"]
-	& File.hasContent "/etc/carbon/storage-schemas.conf"
-		[ "[carbon]"
-		, "pattern = ^carbon\\."
-		, "retentions = 60:90d"
-		, "[iabak-connections]"
-		, "pattern = ^iabak\\.shardstats\\.connections"
-		, "retentions = 1h:1y,3h:10y"
-		, "[iabak-default]"
-		, "pattern = ^iabak\\."
-		, "retentions = 10m:30d,1h:1y,3h:10y"
-		, "[default_1min_for_1day]"
-		, "pattern = .*"
-		, "retentions = 60s:1d"
-		]
-	& graphiteCSRF
-	& cmdProperty "graphite-manage" ["syncdb", "--noinput"]
-		`assume` MadeChange
-		`flagFile` "/etc/flagFiles/graphite-syncdb"
-	& cmdProperty "graphite-manage" ["createsuperuser", "--noinput", "--username=joey", "--email=joey@localhost"]
-		`assume` MadeChange
-		`flagFile` "/etc/flagFiles/graphite-user-joey"
-	& cmdProperty "graphite-manage" ["createsuperuser", "--noinput", "--username=db48x", "--email=db48x@localhost"]
-		`assume` MadeChange
-		`flagFile` "/etc/flagFiles/graphite-user-db48x"
-	-- TODO: deal with passwords somehow
-	& File.ownerGroup "/var/lib/graphite/graphite.db" (User "_graphite") (Group "_graphite")
-	& "/etc/apache2/ports.conf" `File.containsLine` "Listen 8080"
-		`onChange` Apache.restarted
-	& Apache.siteEnabled "iabak-graphite-web"
-		[ "<VirtualHost *:8080>"
-		, "        WSGIDaemonProcess _graphite processes=5 threads=5 display-name='%{GROUP}' inactivity-timeout=120 user=_graphite group=_graphite"
-		, "        WSGIProcessGroup _graphite"
-		, "        WSGIImportScript /usr/share/graphite-web/graphite.wsgi process-group=_graphite application-group=%{GLOBAL}"
-		, "        WSGIScriptAlias / /usr/share/graphite-web/graphite.wsgi"
-		, "        Alias /content/ /usr/share/graphite-web/static/"
-		, "        <Location \"/content/\">"
-		, "                SetHandler None"
-		, "        </Location>"
-		, "        ErrorLog ${APACHE_LOG_DIR}/graphite-web_error.log"
-		, "        LogLevel warn"
-		, "        CustomLog ${APACHE_LOG_DIR}/graphite-web_access.log combined"
-		, "</VirtualHost>"
-		]
-  where
-	graphiteCSRF :: Property (HasInfo + DebianLike)
-	graphiteCSRF = withPrivData (Password "csrf-token") (Context "iabak.archiveteam.org") $
-		\gettoken -> property' "graphite-web CSRF token" $ \w ->
-			gettoken $ \token -> ensureProperty w $ File.containsLine
-				"/etc/graphite/local_settings.py" ("SECRET_KEY = '"++ privDataVal token ++"'")
diff --git a/src/Propellor/Property/SiteSpecific/JoeySites.hs b/src/Propellor/Property/SiteSpecific/JoeySites.hs
--- a/src/Propellor/Property/SiteSpecific/JoeySites.hs
+++ b/src/Propellor/Property/SiteSpecific/JoeySites.hs
@@ -513,6 +513,7 @@
 	& Fail2Ban.jailEnabled "postfix-sasl"
 	& "/etc/default/saslauthd" `File.containsLine` "MECHANISMS=sasldb"
 	& Postfix.saslPasswdSet "kitenet.net" (User "errol")
+	& Postfix.saslPasswdSet "kitenet.net" (User "joey")
 
 	& Apt.installed ["maildrop"]
 	& "/etc/maildroprc" `File.hasContent`
@@ -531,7 +532,6 @@
 
 	& "/etc/aliases" `File.hasPrivContentExposed` ctx
 		`onChange` Postfix.newaliases
-	& hasJoeyCAChain
 	& hasPostfixCert ctx
 
 	& "/etc/postfix/mydomain" `File.containsLines`
@@ -578,7 +578,7 @@
 		, "# Filter out client relay lines from headers."
 		, "header_checks = pcre:$config_directory/obscure_client_relay.pcre"
 
-		, "# Password auth for relaying (used by errol)"
+		, "# Password auth for relaying"
 		, "smtpd_sasl_auth_enable = yes"
 		, "smtpd_sasl_security_options = noanonymous"
 		, "smtpd_sasl_local_domain = kitenet.net"
@@ -670,24 +670,6 @@
 		(Postfix.InetService Nothing "ssmtp")
 		"smtpd" Postfix.defServiceOpts
 
--- Configures postfix to relay outgoing mail to kitenet.net, with
--- verification via tls cert.
-postfixClientRelay :: Context -> Property (HasInfo + DebianLike)
-postfixClientRelay ctx = Postfix.mainCfFile `File.containsLines`
-	-- Using smtps not smtp because more networks firewall smtp
-	[ "relayhost = kitenet.net:smtps"
-	, "smtp_tls_CAfile = /etc/ssl/certs/joeyca.pem"
-	, "smtp_tls_cert_file = /etc/ssl/certs/postfix.pem"
-	, "smtp_tls_key_file = /etc/ssl/private/postfix.pem"
-	, "smtp_tls_loglevel = 0"
-	, "smtp_use_tls = yes"
-	]
-	`describe` "postfix client relay"
-	`onChange` Postfix.dedupMainCf
-	`onChange` Postfix.reloaded
-	`requires` hasJoeyCAChain
-	`requires` hasPostfixCert ctx
-
 -- Configures postfix to have the dkim milter, and no other milters.
 dkimMilter :: Property (HasInfo + DebianLike)
 dkimMilter = Postfix.mainCfFile `File.containsLines`
@@ -743,7 +725,73 @@
 	& Apache.modEnabled "cgi"
 	& Apache.modEnabled "speling"
 	& userDirHtml
-	& Apache.httpsVirtualHost' "kitenet.net" "/var/www" letos
+	& Apache.httpsVirtualHost' "kitenet.net" "/var/www" letos kitenetcfg
+	& alias "anna.kitenet.net"
+	& apacheSite "anna.kitenet.net"
+		[ "DocumentRoot /home/anna/html"
+		, "<Directory /home/anna/html/>"
+		, "  Options Indexes ExecCGI"
+		, "  AllowOverride None"
+		, Apache.allowAll
+		, "</Directory>"
+		]
+	& alias "sows-ear.kitenet.net"
+	& alias "www.sows-ear.kitenet.net"
+	& apacheSite "sows-ear.kitenet.net"
+		[ "ServerAlias www.sows-ear.kitenet.net"
+		, "DocumentRoot /srv/web/sows-ear.kitenet.net"
+		, "<Directory /srv/web/sows-ear.kitenet.net>"
+		, "  Options FollowSymLinks"
+		, "  AllowOverride None"
+		, Apache.allowAll
+		, "</Directory>"
+		, "RewriteEngine On"
+		, "RewriteRule .* http://www.sowsearpoetry.org/ [L]"
+		]
+	& alias "wortroot.kitenet.net"
+	& alias "www.wortroot.kitenet.net"
+	& apacheSite "wortroot.kitenet.net"
+		[ "ServerAlias www.wortroot.kitenet.net"
+		, "DocumentRoot /srv/web/wortroot.kitenet.net"
+		, "<Directory /srv/web/wortroot.kitenet.net>"
+		, "  Options FollowSymLinks"
+		, "  AllowOverride None"
+		, Apache.allowAll
+		, "</Directory>"
+		]
+	& alias "creeksidepress.com"
+	& apacheSite "creeksidepress.com"
+		[ "ServerAlias www.creeksidepress.com"
+		, "DocumentRoot /srv/web/www.creeksidepress.com"
+		, "<Directory /srv/web/www.creeksidepress.com>"
+		, "  Options FollowSymLinks"
+		, "  AllowOverride None"
+		, Apache.allowAll
+		, "</Directory>"
+		]
+	& alias "joey.kitenet.net"
+	& apacheSite "joey.kitenet.net"
+		[ "DocumentRoot /var/www"
+		, "<Directory /var/www/>"
+		, "  Options Indexes ExecCGI"
+		, "  AllowOverride None"
+		, Apache.allowAll
+		, "</Directory>"
+
+		, "RewriteEngine On"
+
+		, "# Old ikiwiki filenames for joey's wiki."
+		, "rewritecond $1 !.*/index$"
+		, "rewriterule (.+).html$ http://joeyh.name/$1/ [l]"
+
+		, "rewritecond $1 !.*/index$"
+		, "rewriterule (.+).rss$ http://joeyh.name/$1/index.rss [l]"
+
+		, "# Redirect all to joeyh.name."
+		, "rewriterule (.*) http://joeyh.name$1 [r]"
+		]
+  where
+	kitenetcfg =
 		-- /var/www is empty
 		[ "DocumentRoot /var/www"
 		, "<Directory /var/www>"
@@ -829,70 +877,6 @@
 		, "rewriterule /~kyle/family/wiki/(.*).html http://macleawiki.branchable.com/$1 [L]"
 		, "rewriterule /~kyle/family/wiki/(.*).rss http://macleawiki.branchable.com/$1/index.rss [L]"
 		, "rewriterule /~kyle/family/wiki(.*) http://macleawiki.branchable.com$1 [L]"
-		]
-	& alias "anna.kitenet.net"
-	& apacheSite "anna.kitenet.net"
-		[ "DocumentRoot /home/anna/html"
-		, "<Directory /home/anna/html/>"
-		, "  Options Indexes ExecCGI"
-		, "  AllowOverride None"
-		, Apache.allowAll
-		, "</Directory>"
-		]
-	& alias "sows-ear.kitenet.net"
-	& alias "www.sows-ear.kitenet.net"
-	& apacheSite "sows-ear.kitenet.net"
-		[ "ServerAlias www.sows-ear.kitenet.net"
-		, "DocumentRoot /srv/web/sows-ear.kitenet.net"
-		, "<Directory /srv/web/sows-ear.kitenet.net>"
-		, "  Options FollowSymLinks"
-		, "  AllowOverride None"
-		, Apache.allowAll
-		, "</Directory>"
-		, "RewriteEngine On"
-		, "RewriteRule .* http://www.sowsearpoetry.org/ [L]"
-		]
-	& alias "wortroot.kitenet.net"
-	& alias "www.wortroot.kitenet.net"
-	& apacheSite "wortroot.kitenet.net"
-		[ "ServerAlias www.wortroot.kitenet.net"
-		, "DocumentRoot /srv/web/wortroot.kitenet.net"
-		, "<Directory /srv/web/wortroot.kitenet.net>"
-		, "  Options FollowSymLinks"
-		, "  AllowOverride None"
-		, Apache.allowAll
-		, "</Directory>"
-		]
-	& alias "creeksidepress.com"
-	& apacheSite "creeksidepress.com"
-		[ "ServerAlias www.creeksidepress.com"
-		, "DocumentRoot /srv/web/www.creeksidepress.com"
-		, "<Directory /srv/web/www.creeksidepress.com>"
-		, "  Options FollowSymLinks"
-		, "  AllowOverride None"
-		, Apache.allowAll
-		, "</Directory>"
-		]
-	& alias "joey.kitenet.net"
-	& apacheSite "joey.kitenet.net"
-		[ "DocumentRoot /var/www"
-		, "<Directory /var/www/>"
-		, "  Options Indexes ExecCGI"
-		, "  AllowOverride None"
-		, Apache.allowAll
-		, "</Directory>"
-
-		, "RewriteEngine On"
-
-		, "# Old ikiwiki filenames for joey's wiki."
-		, "rewritecond $1 !.*/index$"
-		, "rewriterule (.+).html$ http://joeyh.name/$1/ [l]"
-
-		, "rewritecond $1 !.*/index$"
-		, "rewriterule (.+).rss$ http://joeyh.name/$1/index.rss [l]"
-
-		, "# Redirect all to joeyh.name."
-		, "rewriterule (.*) http://joeyh.name$1 [r]"
 		]
 
 userDirHtml :: Property DebianLike
diff --git a/src/wrapper.hs b/src/wrapper.hs
--- a/src/wrapper.hs
+++ b/src/wrapper.hs
@@ -6,6 +6,9 @@
 -- This is not the propellor main program (that's config.hs).
 -- This bootstraps ~/.propellor/config.hs, builds it if
 -- it's not already built, and runs it.
+--
+-- If ./config.hs exists and looks like a propellor config file, 
+-- it instead builds and runs in the current working directory.
 
 module Main where
 
@@ -14,31 +17,65 @@
 import Propellor.Bootstrap
 import Utility.Monad
 import Utility.Directory
+import Utility.FileMode
 import Utility.Process
 import Utility.Process.NonConcurrent
 
 import System.Environment (getArgs)
 import System.Exit
-import System.Posix.Directory
+import System.Posix
+import Data.List
 import Control.Monad.IfElse
+import Control.Applicative
+import Prelude
 
 main :: IO ()
 main = withConcurrentOutput $ go =<< getArgs
   where
 	go ["--init"] = interactiveInit
-	go args = ifM (doesDirectoryExist =<< dotPropellor)
-		( do
-			checkRepoUpToDate
-			buildRunConfig args
-		, error "Seems that ~/.propellor/ does not exist. To set it up, run: propellor --init"
+	go args = ifM configInCurrentWorkingDirectory
+		( buildRunConfig args
+		, ifM (doesDirectoryExist =<< dotPropellor)
+			( do
+				checkRepoUpToDate
+				changeWorkingDirectory =<< dotPropellor
+				buildRunConfig args
+			, error "Seems that ~/.propellor/ does not exist. To set it up, run: propellor --init"
+			)
 		)
 
 buildRunConfig :: [String] -> IO ()
 buildRunConfig args = do
-	changeWorkingDirectory =<< dotPropellor
 	unlessM (doesFileExist "propellor") $ do
 		buildPropellor Nothing
 		putStrLn ""
 		putStrLn ""
 	(_, _, _, pid) <- createProcessNonConcurrent (proc "./propellor" args) 
 	exitWith =<< waitForProcessNonConcurrent pid
+
+configInCurrentWorkingDirectory :: IO Bool
+configInCurrentWorkingDirectory = ifM (doesFileExist "config.hs")
+	( do
+		-- This is a security check to avoid using the current
+		-- working directory as the propellor configuration
+		-- if it's not owned by the user, or is world-writable,
+		-- or group writable. (Some umasks may make directories
+		-- group writable, but typical ones do not.)
+		s <- getFileStatus "."
+		uid <- getRealUserID
+		if fileOwner s /= uid
+			then unsafe "you don't own the current directory"
+			else if checkMode groupWriteMode (fileMode s)
+				then unsafe "the current directory is group writable"
+				else if checkMode otherWriteMode (fileMode s)
+					then unsafe "the current directory is world-writable"
+					else ifM mentionspropellor
+						( return True
+						, notusing "it does not seem to be a propellor config file"
+						)
+	, return False
+	)
+  where
+	unsafe s = notusing (s ++ ". This seems unsafe.")
+	notusing s = error $ "Not using ./config.hs because " ++ s
+	mentionspropellor = ("Propellor" `isInfixOf`) <$> readFile "config.hs"
