summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/Apache.hs
blob: 49e3d525acdfe8384b62ab7a2c83dce5458007d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
module Propellor.Property.Apache where

import Propellor
import qualified Propellor.Property.File as File
import qualified Propellor.Property.Apt as Apt
import qualified Propellor.Property.Service as Service

type ConfigFile = [String]

-- | A basic virtual host, publishing a directory, and logging to
-- the combined apache log file.
virtualHost :: HostName -> Port -> FilePath -> RevertableProperty
virtualHost hn (Port p) docroot = siteEnabled hn
	[ "<VirtualHost *:"++show p++">"
	, "ServerName "++hn++":"++show p
	, "DocumentRoot " ++ docroot
	, "ErrorLog /var/log/apache2/error.log"
	, "LogLevel warn"
	, "CustomLog /var/log/apache2/access.log combined"
	, "ServerSignature On"
	, "</VirtualHost>"
	]

siteEnabled :: HostName -> ConfigFile -> RevertableProperty
siteEnabled hn cf = enable <!> disable
  where
	enable = combineProperties ("apache site enabled " ++ hn)
		[ siteAvailable hn cf
			`requires` installed
			`onChange` reloaded
		, check (not <$> isenabled) $
			cmdProperty "a2ensite" ["--quiet", hn]
				`requires` installed
				`onChange` reloaded
		]
	disable = siteDisabled hn
	isenabled = boolSystem "a2query" [Param "-q", Param "-s", Param hn]

siteDisabled :: HostName -> Property NoInfo
siteDisabled hn = combineProperties
	("apache site disabled " ++ hn) 
	(map File.notPresent (siteCfg hn))
		`onChange` cmdProperty "a2dissite" ["--quiet", hn]
		`requires` installed
		`onChange` reloaded

siteAvailable :: HostName -> ConfigFile -> Property NoInfo
siteAvailable hn cf = combineProperties ("apache site available " ++ hn) $
	map (`File.hasContent` (comment:cf)) (siteCfg hn)
  where
	comment = "# deployed with propellor, do not modify"

modEnabled :: String -> RevertableProperty
modEnabled modname = enable <!> disable
  where
	enable = check (not <$> isenabled) $
		cmdProperty "a2enmod" ["--quiet", modname]
			`describe` ("apache module enabled " ++ modname)
			`requires` installed
			`onChange` reloaded
	disable = check isenabled $ 
		cmdProperty "a2dismod" ["--quiet", modname]
			`describe` ("apache module disabled " ++ modname)
			`requires` installed
			`onChange` reloaded
	isenabled = boolSystem "a2query" [Param "-q", Param "-m", Param modname]

-- This is a list of config files because different versions of apache
-- use different filenames. Propellor simply writes them all.
siteCfg :: HostName -> [FilePath]
siteCfg hn =
	-- Debian pre-2.4
	[ "/etc/apache2/sites-available/" ++ hn
	-- Debian 2.4+
	, "/etc/apache2/sites-available/" ++ hn ++ ".conf"
	] 

installed :: Property NoInfo
installed = Apt.installed ["apache2"]

restarted :: Property NoInfo
restarted = Service.restarted "apache2"

reloaded :: Property NoInfo
reloaded = Service.reloaded "apache2"

-- | Configure apache to use SNI to differentiate between
-- https hosts.
--
-- This was off by default in apache 2.2.22. Newver versions enable
-- it by default. This property uses the filename used by the old version.
multiSSL :: Property NoInfo
multiSSL = check (doesDirectoryExist "/etc/apache2/conf.d") $
	"/etc/apache2/conf.d/ssl" `File.hasContent`
		[ "NameVirtualHost *:443"
		, "SSLStrictSNIVHostCheck off"
		]
		`describe` "apache SNI enabled"
		`onChange` reloaded

-- | Config file fragment that can be inserted into a <Directory>
-- stanza to allow global read access to the directory.
--
-- Works with multiple versions of apache that have different ways to do
-- it.
allowAll :: String
allowAll = unlines
	[ "<IfVersion < 2.4>"
	, "Order allow,deny"
	, "allow from all"
	, "</IfVersion>"
	, "<IfVersion >= 2.4>"
	, "Require all granted"
	, "</IfVersion>"
	]