blob: 7a79fac12b78789a84e177ef94ca4758a199acf3 [file] [log] [blame]
Skyler Greydb1f1d92023-10-22 16:43:45 +00001{ pkgs, ... }:
2let lib = pkgs.lib;
Skyler Greyc0a62472023-10-18 23:29:13 +00003in {
Skyler Greydb1f1d92023-10-22 16:43:45 +00004 Host = host: service: {
5 inherit host service;
6 extraHosts = [ ];
7 secure = true;
Skyler Grey6706dbc2024-05-05 01:00:34 +00008 specific = false;
9 type = "hosts";
10 };
11 SpecificHost = host: service: {
12 inherit host service;
13 extraHosts = [ ];
14 secure = true;
15 specific = true;
Skyler Greydb1f1d92023-10-22 16:43:45 +000016 type = "hosts";
17 };
18 Hosts = hosts: service: {
19 inherit service;
20 host = builtins.elemAt hosts 0;
21 extraHosts = builtins.tail hosts;
22 secure = true;
Skyler Grey6706dbc2024-05-05 01:00:34 +000023 specific = false;
Skyler Greydb1f1d92023-10-22 16:43:45 +000024 type = "hosts";
25 };
26 InsecureHost = host: service: {
27 inherit host service;
28 extraHosts = [ ];
29 secure = false;
Skyler Grey6706dbc2024-05-05 01:00:34 +000030 specific = false;
Skyler Greydb1f1d92023-10-22 16:43:45 +000031 type = "hosts";
32 };
33 InsecureHosts = hosts: service: {
34 inherit service;
35 host = builtins.elemAt hosts 0;
36 extraHosts = builtins.tail hosts;
37 secure = false;
Skyler Grey6706dbc2024-05-05 01:00:34 +000038 specific = false;
Skyler Greydb1f1d92023-10-22 16:43:45 +000039 type = "hosts";
40 };
41 ReverseProxy = to: {
42 inherit to;
43 type = "reverseproxy";
44 };
45 PHP = root: socket: {
46 inherit root socket;
47 type = "php";
48 };
49 Redirect = to: {
50 inherit to;
51 permanent = false;
52 type = "redirect";
53 };
54 RedirectPermanent = to: {
55 inherit to;
56 permanent = true;
57 type = "redirect";
58 };
59 Directory = root: {
60 inherit root;
61 private = false;
62 type = "directory";
63 };
64 PrivateDirectory = root: {
65 inherit root;
66 private = true;
67 type = "directory";
68 };
69 File = path: {
70 inherit path;
71 type = "file";
72 };
73 Compose = services: {
74 inherit services;
75 type = "compose";
76 };
77 Path = path: service: {
78 inherit path service;
79 type = "path";
80 };
81 Status = statusCode: {
82 inherit statusCode;
83 type = "status";
84 };
Skyler Grey8b911b92023-11-21 21:20:16 +000085 Header = header: value: service: {
86 inherit header value service;
87 type = "header";
88 };
89 CrossOrigin = service: {
90 inherit service;
91 header = "Access-Control-Allow-Origin";
92 value = "*";
93 type = "header";
94 };
Skyler Greyc0a62472023-10-18 23:29:13 +000095
Skyler Greydb1f1d92023-10-22 16:43:45 +000096 Merge = let
Skyler Greyc0a62472023-10-18 23:29:13 +000097 # builtins.length and count up
Skyler Greydb1f1d92023-10-22 16:43:45 +000098 _iterateCompose = services: currentConfig: currentPath: secure: priority: i:
99 if i < builtins.length services then
100 _iterateCompose services
101 (_merge (builtins.elemAt services i) currentConfig currentPath secure
102 (priority + i)) currentPath secure priority (i + 1)
103 else
104 currentConfig;
Skyler Greyc0a62472023-10-18 23:29:13 +0000105
Skyler Greydb1f1d92023-10-22 16:43:45 +0000106 _iterateMerge = i: current: services:
107 if i < builtins.length services then
108 _iterateMerge (i + 1)
109 (current ++ [ (_merge (builtins.elemAt services i) { } "/" true 1000) ])
110 services
111 else
112 current;
Skyler Greyc0a62472023-10-18 23:29:13 +0000113
Skyler Greydb1f1d92023-10-22 16:43:45 +0000114 _merge = service: currentConfig: currentPath: secure: priority:
115 if service.type == "hosts" then
116 _merge service.service (lib.recursiveUpdate currentConfig {
117 name = service.host;
118 value = {
Skyler Grey6706dbc2024-05-05 01:00:34 +0000119 serverAliases = service.extraHosts ++ (if service.specific
120 then []
121 else [ "www.${service.host}" ] ++ (map (host: "www.${host}") service.extraHosts));
Skyler Greydb1f1d92023-10-22 16:43:45 +0000122 enableACME = true;
123 forceSSL = service.secure;
124 addSSL = !service.secure;
125 listenAddresses = [ "0.0.0.0" ];
126 };
127 }) currentPath service.secure priority
128 else if service.type == "reverseproxy" then
129 (lib.recursiveUpdate currentConfig {
130 value.locations.${currentPath} = {
Skyler Grey64d1d302023-10-25 07:26:33 +0000131 proxyPass = if currentPath == "/" then
132 "http://${service.to}"
133 else
134 "http://${service.to}/";
Skyler Greydb1f1d92023-10-22 16:43:45 +0000135 proxyWebsockets = true;
136 recommendedProxySettings = true;
137 };
138 })
139 else if service.type == "php" then
140 (lib.recursiveUpdate currentConfig {
141 value.locations.${currentPath} = {
142 root = service.root;
143 index = "index.php index.html index.htm";
144 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
145 };
146 value.locations."~ ^${currentPath}.*.php$" = {
147 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
148 extraConfig = ''
149 include ${pkgs.nginx}/conf/fastcgi_params;
150 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
151 fastcgi_param REDIRECT_STATUS 200;
152 fastcgi_pass unix:${service.socket};
153 fastcgi_intercept_errors on;
154 ${lib.optionalString secure "fastcgi_param HTTPS on;"}
155 '';
156 };
157 })
158 else if service.type == "redirect" then
159 (lib.recursiveUpdate currentConfig {
160 value.locations.${currentPath}.return = if service.permanent then
161 "308 ${service.to}"
162 else
163 "307 ${service.to}";
164 })
165 else if service.type == "directory" then
166 (lib.recursiveUpdate currentConfig {
167 value.locations.${currentPath} = {
168 root = service.root;
169 index = "index.html index.htm";
170 tryFiles = "$uri $uri/ =404";
171 extraConfig = lib.optionalString (!service.private) "autoindex on;";
172 };
173 })
174 else if service.type == "file" then
175 (lib.recursiveUpdate currentConfig {
176 value.locations.${currentPath} = {
Skyler Grey9b2bb0d2023-11-07 18:26:11 +0000177 root = "/";
Skyler Greydb1f1d92023-10-22 16:43:45 +0000178 tryFiles = "${service.path} =404";
179 };
180 })
181 else if service.type == "path" then
182 _merge service.service currentConfig service.path service.secure
183 priority
Skyler Grey8b911b92023-11-21 21:20:16 +0000184 else if service.type == "header" then
185 _merge service.service
186 (lib.recursiveUpdate currentConfig {
187 value.locations.${currentPath} = {
188 extraConfig =
189 (if
190 builtins.hasAttr "value" currentConfig
191 && builtins.hasAttr "locations" currentConfig.value
192 && builtins.hasAttr currentPath currentConfig.value.locations
193 && builtins.hasAttr "extraConfig" currentConfig.value.locations.${currentPath}
194 then currentConfig.value.locations.${currentPath}.extraConfig else "") +
195 ''
196 add_header ${service.header} "${service.value}";
197 '';
198 };
199 }) currentPath secure priority
Skyler Greydb1f1d92023-10-22 16:43:45 +0000200 else if service.type == "compose" then
201 (_iterateCompose service.services currentConfig currentPath secure
202 priority 0)
203 else if service.type == "status" then
204 (lib.recursiveUpdate currentConfig {
205 value.locations.${currentPath} = {
206 return = "${builtins.toString service.statusCode}";
207 };
208 })
209 else
210 throw "Unknown service type: ${service.type}";
211 in (services:
212 lib.pipe services [ (_iterateMerge 0 [ ]) builtins.listToAttrs ]);
Skyler Greyc0a62472023-10-18 23:29:13 +0000213
Skyler Greydb1f1d92023-10-22 16:43:45 +0000214 # https://www.nginx.com/resources/wiki/start/topics/examples/full/
Skyler Greyc0a62472023-10-18 23:29:13 +0000215
Skyler Greydb1f1d92023-10-22 16:43:45 +0000216 /* *
217 Internal needs to be a string that is both a host and a port, e.g. generic:1000
218 External should only be a port
219 Protocol should be TCP or UDP
220 */
Skyler Grey06e9c2b2023-10-22 22:34:07 +0000221 ProxyStream = external: internal: protocol: {
222 inherit external internal protocol;
223 haproxy = true;
224 };
Skyler Greydb1f1d92023-10-22 16:43:45 +0000225 Stream = external: internal: protocol: {
226 inherit external internal protocol;
Skyler Grey06e9c2b2023-10-22 22:34:07 +0000227 haproxy = false;
Skyler Greydb1f1d92023-10-22 16:43:45 +0000228 };
Skyler Greyc0a62472023-10-18 23:29:13 +0000229
Skyler Greydb1f1d92023-10-22 16:43:45 +0000230 Alias = host: alias: {
231 inherit host;
232 aliases = [ alias ];
233 type = "aliases";
234 };
Skyler Greyc0a62472023-10-18 23:29:13 +0000235
Skyler Greydb1f1d92023-10-22 16:43:45 +0000236 Aliases = host: aliases: {
237 inherit host aliases;
238 type = "aliases";
239 };
Skyler Greyc0a62472023-10-18 23:29:13 +0000240}
241