blob: 41cc114808434de872dbf5ce8c712a34116e78a3 [file] [log] [blame]
Skyler Greyc0a62472023-10-18 23:29:13 +00001{ pkgs, ... }: let
2 lib = pkgs.lib;
3in {
4 Host = host: service: {
5 inherit host service;
6 extraHosts = [];
7 secure = true;
8 type = "hosts";
9 };
10 Hosts = hosts: service: {
11 inherit service;
Skyler Grey7de65802023-10-19 22:23:47 +000012 host = builtins.elemAt hosts 0;
13 extraHosts = builtins.tail hosts;
Skyler Greyc0a62472023-10-18 23:29:13 +000014 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;
Skyler Grey7de65802023-10-19 22:23:47 +000025 host = builtins.elemAt hosts 0;
26 extraHosts = builtins.tail hosts;
Skyler Greyc0a62472023-10-18 23:29:13 +000027 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 };
Skyler Grey2a7dd0e2023-10-20 00:07:45 +000038 Redirect = to: {
39 inherit to;
40 permanent = false;
41 type = "redirect";
42 };
43 RedirectPermanent = to: {
44 inherit to;
45 permanent = true;
Skyler Greyc0a62472023-10-18 23:29:13 +000046 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
71 Merge = let
72 # builtins.length and count up
73 _iterateCompose = services: currentConfig: currentPath: secure: priority: i:
Skyler Grey00495a82023-10-20 22:23:25 +000074 if i < builtins.length services
75 then _iterateCompose services (_merge (builtins.elemAt services i) currentConfig currentPath secure priority+i) currentPath secure priority (i+1)
76 else currentConfig;
Skyler Greyc0a62472023-10-18 23:29:13 +000077
78 _iterateMerge = i: current: services:
Skyler Grey00495a82023-10-20 22:23:25 +000079 if i < builtins.length services
80 then _iterateMerge (i+1) (current++[(_merge (builtins.elemAt services i) {} "/" true 1000)]) services
81 else current;
Skyler Greyc0a62472023-10-18 23:29:13 +000082
83 _merge = service: currentConfig: currentPath: secure: priority:
84 if service.type == "hosts"
Skyler Greye5a56792023-10-19 23:44:33 +000085 then _merge service.service (lib.recursiveUpdate currentConfig {
Skyler Greyc0a62472023-10-18 23:29:13 +000086 name = service.host;
87 value = {
88 serverAliases = service.extraHosts;
89
90 enableACME = service.secure;
91 forceSSL = service.secure;
92 listen = [
93 {
94 addr = "0.0.0.0";
95 port = if service.secure then 443 else 80;
96 ssl = service.secure;
97 }
98 ];
99 };
100 }) currentPath service.secure priority
101 else if service.type == "reverseproxy"
Skyler Greye5a56792023-10-19 23:44:33 +0000102 then (lib.recursiveUpdate currentConfig {
Skyler Greyc0a62472023-10-18 23:29:13 +0000103 value.locations.${currentPath} = {
104 proxyPass = service.to;
105 proxyWebsockets = true;
106 recommendedProxySettings = true;
107 };
108 })
109 else if service.type == "php"
Skyler Greye5a56792023-10-19 23:44:33 +0000110 then (lib.recursiveUpdate currentConfig {
Skyler Greyc0a62472023-10-18 23:29:13 +0000111 value.locations.${currentPath} = {
112 root = service.root;
113 index = "index.php index.html index.htm";
114 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
115 };
116 value.locations."~ ^${currentPath}.*\.php$" = {
117 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
118 extraConfig = ''
119 include ${pkgs.nginx}/conf/fastcgi_params;
120 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
121 fastcgi_param REDIRECT_STATUS 200;
122 fastcgi_pass unix:${service.socket};
123 fastcgi_intercept_errors on;
124 ${lib.optionalString secure "fastcgi_param HTTPS on;"}
125 '';
126 };
127 })
128 else if service.type == "redirect"
Skyler Greye5a56792023-10-19 23:44:33 +0000129 then (lib.recursiveUpdate currentConfig {
Skyler Greyc0a62472023-10-18 23:29:13 +0000130 value.locations.${currentPath}.return =
131 if service.permanent
132 then "308 ${service.to}"
133 else "307 ${service.to}";
134 })
135 else if service.type == "directory"
Skyler Greye5a56792023-10-19 23:44:33 +0000136 then (lib.recursiveUpdate currentConfig {
Skyler Greyc0a62472023-10-18 23:29:13 +0000137 value.locations.${currentPath} = {
138 root = service.root;
139 index = "index.html index.htm";
140 tryFiles = "$uri $uri/ =404";
Skyler Grey7de65802023-10-19 22:23:47 +0000141 extraConfig = lib.optionalString (!service.private) "autoindex on;";
Skyler Greyc0a62472023-10-18 23:29:13 +0000142 };
143 })
144 else if service.type == "file"
Skyler Greye5a56792023-10-19 23:44:33 +0000145 then (lib.recursiveUpdate currentConfig {
Skyler Greyc0a62472023-10-18 23:29:13 +0000146 value.locations.${currentPath} = {
147 tryFiles = "${service.path} =404";
148 };
149 })
150 else if service.type == "path"
Skyler Grey7ecfdba2023-10-19 23:19:35 +0000151 then _merge service.service currentConfig service.path service.secure priority
Skyler Greyc0a62472023-10-18 23:29:13 +0000152 else if service.type == "compose"
153 then (_iterateCompose service.services currentConfig currentPath secure priority 0)
154 else throw "Unknown service type: ${service.type}";
155 in (services: lib.pipe services [
156 (_iterateMerge 0 [])
157 builtins.listToAttrs
158 ]);
159
160 # https://www.nginx.com/resources/wiki/start/topics/examples/full/
161
162 /**
163 Internal needs to be a string that is both a host and a port, e.g. generic:1000
164 External should only be a port
165 Protocol should be TCP or UDP
166 */
Skyler Grey00495a82023-10-20 22:23:25 +0000167 Stream = external: internal: protocol: { inherit external internal protocol; };
Skyler Greyc0a62472023-10-18 23:29:13 +0000168
169 Alias = host: alias: {
170 inherit host;
171 aliases = [ alias ];
172 type = "aliases";
173 };
174
175 Aliases = host: aliases: {
176 inherit host aliases;
177 type = "aliases";
178 };
179}
180