1{
2 config,
3 lib,
4 name,
5 ...
6}:
7let
8 inherit (lib)
9 literalExpression
10 mkOption
11 nameValuePair
12 types
13 ;
14in
15{
16 options = {
17
18 hostName = mkOption {
19 type = types.str;
20 default = name;
21 description = "Canonical hostname for the server.";
22 };
23
24 serverAliases = mkOption {
25 type = types.listOf types.str;
26 default = [ ];
27 example = [
28 "www.example.org"
29 "www.example.org:8080"
30 "example.org"
31 ];
32 description = ''
33 Additional names of virtual hosts served by this virtual host configuration.
34 '';
35 };
36
37 listen = mkOption {
38 type =
39 with types;
40 listOf (submodule ({
41 options = {
42 port = mkOption {
43 type = types.port;
44 description = "Port to listen on";
45 };
46 ip = mkOption {
47 type = types.str;
48 default = "*";
49 description = "IP to listen on. 0.0.0.0 for IPv4 only, * for all.";
50 };
51 ssl = mkOption {
52 type = types.bool;
53 default = false;
54 description = "Whether to enable SSL (https) support.";
55 };
56 };
57 }));
58 default = [ ];
59 example = [
60 {
61 ip = "195.154.1.1";
62 port = 443;
63 ssl = true;
64 }
65 {
66 ip = "192.154.1.1";
67 port = 80;
68 }
69 {
70 ip = "*";
71 port = 8080;
72 }
73 ];
74 description = ''
75 Listen addresses and ports for this virtual host.
76
77 ::: {.note}
78 This option overrides `addSSL`, `forceSSL` and `onlySSL`.
79
80 If you only want to set the addresses manually and not the ports, take a look at `listenAddresses`.
81 :::
82 '';
83 };
84
85 listenAddresses = mkOption {
86 type = with types; nonEmptyListOf str;
87
88 description = ''
89 Listen addresses for this virtual host.
90 Compared to `listen` this only sets the addresses
91 and the ports are chosen automatically.
92 '';
93 default = [ "*" ];
94 example = [ "127.0.0.1" ];
95 };
96
97 enableSSL = mkOption {
98 type = types.bool;
99 visible = false;
100 default = false;
101 };
102
103 addSSL = mkOption {
104 type = types.bool;
105 default = false;
106 description = ''
107 Whether to enable HTTPS in addition to plain HTTP. This will set defaults for
108 `listen` to listen on all interfaces on the respective default
109 ports (80, 443).
110 '';
111 };
112
113 onlySSL = mkOption {
114 type = types.bool;
115 default = false;
116 description = ''
117 Whether to enable HTTPS and reject plain HTTP connections. This will set
118 defaults for `listen` to listen on all interfaces on port 443.
119 '';
120 };
121
122 forceSSL = mkOption {
123 type = types.bool;
124 default = false;
125 description = ''
126 Whether to add a separate nginx server block that permanently redirects (301)
127 all plain HTTP traffic to HTTPS. This will set defaults for
128 `listen` to listen on all interfaces on the respective default
129 ports (80, 443), where the non-SSL listens are used for the redirect vhosts.
130 '';
131 };
132
133 enableACME = mkOption {
134 type = types.bool;
135 default = false;
136 description = ''
137 Whether to ask Let's Encrypt to sign a certificate for this vhost.
138 Alternately, you can use an existing certificate through {option}`useACMEHost`.
139 '';
140 };
141
142 useACMEHost = mkOption {
143 type = types.nullOr types.str;
144 default = null;
145 description = ''
146 A host of an existing Let's Encrypt certificate to use.
147 This is useful if you have many subdomains and want to avoid hitting the
148 [rate limit](https://letsencrypt.org/docs/rate-limits).
149 Alternately, you can generate a certificate through {option}`enableACME`.
150 *Note that this option does not create any certificates, nor it does add subdomains to existing ones – you will need to create them manually using [](#opt-security.acme.certs).*
151 '';
152 };
153
154 acmeRoot = mkOption {
155 type = types.nullOr types.str;
156 default = "/var/lib/acme/acme-challenge";
157 description = ''
158 Directory for the acme challenge which is PUBLIC, don't put certs or keys in here.
159 Set to null to inherit from config.security.acme.
160 '';
161 };
162
163 sslServerCert = mkOption {
164 type = types.path;
165 example = "/var/host.cert";
166 description = "Path to server SSL certificate.";
167 };
168
169 sslServerKey = mkOption {
170 type = types.path;
171 example = "/var/host.key";
172 description = "Path to server SSL certificate key.";
173 };
174
175 sslServerChain = mkOption {
176 type = types.nullOr types.path;
177 default = null;
178 example = "/var/ca.pem";
179 description = "Path to server SSL chain file.";
180 };
181
182 http2 = mkOption {
183 type = types.bool;
184 default = true;
185 description = ''
186 Whether to enable HTTP 2. HTTP/2 is supported in all multi-processing modules that come with httpd. *However, if you use the prefork mpm, there will
187 be severe restrictions.* Refer to <https://httpd.apache.org/docs/2.4/howto/http2.html#mpm-config> for details.
188 '';
189 };
190
191 adminAddr = mkOption {
192 type = types.nullOr types.str;
193 default = null;
194 example = "admin@example.org";
195 description = "E-mail address of the server administrator.";
196 };
197
198 documentRoot = mkOption {
199 type = types.nullOr types.path;
200 default = null;
201 example = "/data/webserver/docs";
202 description = ''
203 The path of Apache's document root directory. If left undefined,
204 an empty directory in the Nix store will be used as root.
205 '';
206 };
207
208 servedDirs = mkOption {
209 type = types.listOf types.attrs;
210 default = [ ];
211 example = [
212 {
213 urlPath = "/nix";
214 dir = "/home/eelco/Dev/nix-homepage";
215 }
216 ];
217 description = ''
218 This option provides a simple way to serve static directories.
219 '';
220 };
221
222 servedFiles = mkOption {
223 type = types.listOf types.attrs;
224 default = [ ];
225 example = [
226 {
227 urlPath = "/foo/bar.png";
228 file = "/home/eelco/some-file.png";
229 }
230 ];
231 description = ''
232 This option provides a simple way to serve individual, static files.
233
234 ::: {.note}
235 This option has been deprecated and will be removed in a future
236 version of NixOS. You can achieve the same result by making use of
237 the `locations.<name>.alias` option.
238 :::
239 '';
240 };
241
242 extraConfig = mkOption {
243 type = types.lines;
244 default = "";
245 example = ''
246 <Directory /home>
247 Options FollowSymlinks
248 AllowOverride All
249 </Directory>
250 '';
251 description = ''
252 These lines go to httpd.conf verbatim. They will go after
253 directories and directory aliases defined by default.
254 '';
255 };
256
257 enableUserDir = mkOption {
258 type = types.bool;
259 default = false;
260 description = ''
261 Whether to enable serving {file}`~/public_html` as
262 `/~«username»`.
263 '';
264 };
265
266 globalRedirect = mkOption {
267 type = types.nullOr types.str;
268 default = null;
269 example = "http://newserver.example.org/";
270 description = ''
271 If set, all requests for this host are redirected permanently to
272 the given URL.
273 '';
274 };
275
276 logFormat = mkOption {
277 type = types.str;
278 default = "common";
279 example = "combined";
280 description = ''
281 Log format for Apache's log files. Possible values are: combined, common, referer, agent.
282 '';
283 };
284
285 robotsEntries = mkOption {
286 type = types.lines;
287 default = "";
288 example = "Disallow: /foo/";
289 description = ''
290 Specification of pages to be ignored by web crawlers. See <http://www.robotstxt.org/> for details.
291 '';
292 };
293
294 locations = mkOption {
295 type = with types; attrsOf (submodule (import ./location-options.nix));
296 default = { };
297 example = literalExpression ''
298 {
299 "/" = {
300 proxyPass = "http://localhost:3000";
301 };
302 "/foo/bar.png" = {
303 alias = "/home/eelco/some-file.png";
304 };
305 };
306 '';
307 description = ''
308 Declarative location config. See <https://httpd.apache.org/docs/2.4/mod/core.html#location> for details.
309 '';
310 };
311
312 };
313
314 config = {
315
316 locations = builtins.listToAttrs (
317 map (elem: nameValuePair elem.urlPath { alias = elem.file; }) config.servedFiles
318 );
319
320 };
321}