forked from input-output-hk/marlowe-deploy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp-services.nix
131 lines (118 loc) · 3.69 KB
/
http-services.nix
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{ lib, options, config, ... }:
let
inherit (lib)
mkOption types mapAttrs mkIf listToAttrs imap0 attrNames mkMerge mapAttrs';
static-sites-options.options = {
domain = mkOption {
type = types.str;
description = "The domain to host the site on";
};
root = mkOption {
type = types.path;
description = "The static file root directory to serve";
};
index-fallback = mkOption {
type = types.bool;
description =
"Whether to serve index.html if a non-existent file is requested (useful for react client-side routing)";
default = false;
};
};
proxied-services-options.options = {
domain = mkOption {
type = types.str;
description = "The domain to host the site on";
};
prefix = mkOption {
type = types.str;
description =
"The path prefix (of the domain) to serve from this service";
default = "/";
};
systemdConfig = mkOption {
type = types.functionTo types.attrs;
description =
"A function taking a port number and returning a systemd config (`systemd.services.*`) serving the backend at that port";
};
};
cfg = config.http-services;
static-virtual-hosts = mapAttrs' (_: static-cfg: {
# TODO: If we have two static-sites at the same domain, this will silently clobber one (should error instead)
name = static-cfg.domain;
value = {
forceSSL = true;
enableACME = true;
inherit (static-cfg) root;
locations =
mkIf static-cfg.index-fallback { "/".tryFiles = "$uri /index.html"; };
};
}) cfg.static-sites;
port-base = 8000;
proxy-defs = listToAttrs (imap0 (idx: name:
let
proxy-cfg = cfg.proxied-services.${name};
port = port-base + idx;
in {
inherit name;
value = {
inherit (proxy-cfg) domain;
vhost = {
forceSSL = true;
enableACME = true;
locations.${proxy-cfg.prefix} = {
proxyPass = "http://localhost:${toString port}";
};
};
service = proxy-cfg.systemdConfig port;
};
}) (attrNames cfg.proxied-services));
proxied-virtual-hosts = mapAttrs' (_: def: {
# TODO: If we have two proxied-services at the same domain, this will silently clobber one (should error unless at different prefixes, should merge if different prefixes)
name = def.domain;
value = def.vhost;
}) proxy-defs;
in {
options = {
http-services = {
static-sites = mkOption {
type = types.attrsOf (types.submodule static-sites-options);
description = "Static sites to serve";
default = { };
};
proxied-services = mkOption {
type = types.attrsOf (types.submodule proxied-services-options);
description = "Proxied http services to serve";
default = { };
};
};
};
config =
let any-hosts = static-virtual-hosts != { } || proxied-virtual-hosts != { };
in {
services.nginx = {
enable = any-hosts;
virtualHosts = mkMerge [
static-virtual-hosts
proxied-virtual-hosts
{
default = {
locations."/".return = "404";
default = true;
rejectSSL = true;
};
}
];
recommendedOptimisation = true;
recommendedProxySettings = true;
};
systemd.services = mapAttrs
(_: def: mkMerge [ def.service { wantedBy = [ "nginx.service" ]; } ])
proxy-defs;
networking.firewall.allowedTCPPorts = mkIf any-hosts [ 80 443 ];
security.acme = mkIf any-hosts {
acceptTerms = true;
# TODO change to proper admin
defaults.email = "[email protected]";
};
};
}