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