blob: 3ad045ef9306be9c948f704a7feb02ec63cc6cf1 [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;
8 type = "hosts";
9 };
10 Hosts = hosts: service: {
11 inherit service;
12 host = builtins.elemAt hosts 0;
13 extraHosts = builtins.tail hosts;
14 secure = true;
15 type = "hosts";
16 };
17 InsecureHost = host: service: {
18 inherit host service;
19 extraHosts = [ ];
20 secure = false;
21 type = "hosts";
22 };
23 InsecureHosts = hosts: service: {
24 inherit service;
25 host = builtins.elemAt hosts 0;
26 extraHosts = builtins.tail hosts;
27 secure = false;
28 type = "hosts";
29 };
30 ReverseProxy = to: {
31 inherit to;
32 type = "reverseproxy";
33 };
34 PHP = root: socket: {
35 inherit root socket;
36 type = "php";
37 };
38 Redirect = to: {
39 inherit to;
40 permanent = false;
41 type = "redirect";
42 };
43 RedirectPermanent = to: {
44 inherit to;
45 permanent = true;
46 type = "redirect";
47 };
48 Directory = root: {
49 inherit root;
50 private = false;
51 type = "directory";
52 };
53 PrivateDirectory = root: {
54 inherit root;
55 private = true;
56 type = "directory";
57 };
58 File = path: {
59 inherit path;
60 type = "file";
61 };
62 Compose = services: {
63 inherit services;
64 type = "compose";
65 };
66 Path = path: service: {
67 inherit path service;
68 type = "path";
69 };
70 Status = statusCode: {
71 inherit statusCode;
72 type = "status";
73 };
Skyler Greyc0a62472023-10-18 23:29:13 +000074
Skyler Greydb1f1d92023-10-22 16:43:45 +000075 Merge = let
Skyler Greyc0a62472023-10-18 23:29:13 +000076 # builtins.length and count up
Skyler Greydb1f1d92023-10-22 16:43:45 +000077 _iterateCompose = services: currentConfig: currentPath: secure: priority: i:
78 if i < builtins.length services then
79 _iterateCompose services
80 (_merge (builtins.elemAt services i) currentConfig currentPath secure
81 (priority + i)) currentPath secure priority (i + 1)
82 else
83 currentConfig;
Skyler Greyc0a62472023-10-18 23:29:13 +000084
Skyler Greydb1f1d92023-10-22 16:43:45 +000085 _iterateMerge = i: current: services:
86 if i < builtins.length services then
87 _iterateMerge (i + 1)
88 (current ++ [ (_merge (builtins.elemAt services i) { } "/" true 1000) ])
89 services
90 else
91 current;
Skyler Greyc0a62472023-10-18 23:29:13 +000092
Skyler Greydb1f1d92023-10-22 16:43:45 +000093 _merge = service: currentConfig: currentPath: secure: priority:
94 if service.type == "hosts" then
95 _merge service.service (lib.recursiveUpdate currentConfig {
96 name = service.host;
97 value = {
Skyler Grey64d1d302023-10-25 07:26:33 +000098 serverAliases = service.extraHosts ++ [ "www.${service.host}" ]
99 ++ (map (host: "www.${host}") service.extraHosts);
Skyler Greyc0a62472023-10-18 23:29:13 +0000100
Skyler Greydb1f1d92023-10-22 16:43:45 +0000101 enableACME = true;
102 forceSSL = service.secure;
103 addSSL = !service.secure;
104 listenAddresses = [ "0.0.0.0" ];
105 };
106 }) currentPath service.secure priority
107 else if service.type == "reverseproxy" then
108 (lib.recursiveUpdate currentConfig {
109 value.locations.${currentPath} = {
Skyler Grey64d1d302023-10-25 07:26:33 +0000110 proxyPass = if currentPath == "/" then
111 "http://${service.to}"
112 else
113 "http://${service.to}/";
Skyler Greydb1f1d92023-10-22 16:43:45 +0000114 proxyWebsockets = true;
115 recommendedProxySettings = true;
116 };
117 })
118 else if service.type == "php" then
119 (lib.recursiveUpdate currentConfig {
120 value.locations.${currentPath} = {
121 root = service.root;
122 index = "index.php index.html index.htm";
123 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
124 };
125 value.locations."~ ^${currentPath}.*.php$" = {
126 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
127 extraConfig = ''
128 include ${pkgs.nginx}/conf/fastcgi_params;
129 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
130 fastcgi_param REDIRECT_STATUS 200;
131 fastcgi_pass unix:${service.socket};
132 fastcgi_intercept_errors on;
133 ${lib.optionalString secure "fastcgi_param HTTPS on;"}
134 '';
135 };
136 })
137 else if service.type == "redirect" then
138 (lib.recursiveUpdate currentConfig {
139 value.locations.${currentPath}.return = if service.permanent then
140 "308 ${service.to}"
141 else
142 "307 ${service.to}";
143 })
144 else if service.type == "directory" then
145 (lib.recursiveUpdate currentConfig {
146 value.locations.${currentPath} = {
147 root = service.root;
148 index = "index.html index.htm";
149 tryFiles = "$uri $uri/ =404";
150 extraConfig = lib.optionalString (!service.private) "autoindex on;";
151 };
152 })
153 else if service.type == "file" then
154 (lib.recursiveUpdate currentConfig {
155 value.locations.${currentPath} = {
156 tryFiles = "${service.path} =404";
157 };
158 })
159 else if service.type == "path" then
160 _merge service.service currentConfig service.path service.secure
161 priority
162 else if service.type == "compose" then
163 (_iterateCompose service.services currentConfig currentPath secure
164 priority 0)
165 else if service.type == "status" then
166 (lib.recursiveUpdate currentConfig {
167 value.locations.${currentPath} = {
168 return = "${builtins.toString service.statusCode}";
169 };
170 })
171 else
172 throw "Unknown service type: ${service.type}";
173 in (services:
174 lib.pipe services [ (_iterateMerge 0 [ ]) builtins.listToAttrs ]);
Skyler Greyc0a62472023-10-18 23:29:13 +0000175
Skyler Greydb1f1d92023-10-22 16:43:45 +0000176 # https://www.nginx.com/resources/wiki/start/topics/examples/full/
Skyler Greyc0a62472023-10-18 23:29:13 +0000177
Skyler Greydb1f1d92023-10-22 16:43:45 +0000178 /* *
179 Internal needs to be a string that is both a host and a port, e.g. generic:1000
180 External should only be a port
181 Protocol should be TCP or UDP
182 */
Skyler Grey06e9c2b2023-10-22 22:34:07 +0000183 ProxyStream = external: internal: protocol: {
184 inherit external internal protocol;
185 haproxy = true;
186 };
Skyler Greydb1f1d92023-10-22 16:43:45 +0000187 Stream = external: internal: protocol: {
188 inherit external internal protocol;
Skyler Grey06e9c2b2023-10-22 22:34:07 +0000189 haproxy = false;
Skyler Greydb1f1d92023-10-22 16:43:45 +0000190 };
Skyler Greyc0a62472023-10-18 23:29:13 +0000191
Skyler Greydb1f1d92023-10-22 16:43:45 +0000192 Alias = host: alias: {
193 inherit host;
194 aliases = [ alias ];
195 type = "aliases";
196 };
Skyler Greyc0a62472023-10-18 23:29:13 +0000197
Skyler Greydb1f1d92023-10-22 16:43:45 +0000198 Aliases = host: aliases: {
199 inherit host aliases;
200 type = "aliases";
201 };
Skyler Greyc0a62472023-10-18 23:29:13 +0000202}
203