blob: 16ef1209a64d6f8ca8796a9b8cc994b2ae077102 [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 };
38 Redirect = to: permanent: {
39 inherit to permanent;
40 type = "redirect";
41 };
42 Directory = root: {
43 inherit root;
44 private = false;
45 type = "directory";
46 };
47 PrivateDirectory = root: {
48 inherit root;
49 private = true;
50 type = "directory";
51 };
52 File = path: {
53 inherit path;
54 type = "file";
55 };
56 Compose = services: {
57 inherit services;
58 type = "compose";
59 };
60 Path = path: service: {
61 inherit path service;
62 type = "path";
63 };
64
65 Merge = let
66 # builtins.length and count up
67 _iterateCompose = services: currentConfig: currentPath: secure: priority: i:
Skyler Grey7de65802023-10-19 22:23:47 +000068 if i > builtins.length services
Skyler Greyc0a62472023-10-18 23:29:13 +000069 then currentConfig
Skyler Grey7de65802023-10-19 22:23:47 +000070 else _iterateCompose services (_merge (builtins.elemAt services i) currentConfig currentPath secure priority+i) currentPath secure priority (i+1);
Skyler Greyc0a62472023-10-18 23:29:13 +000071
72 _iterateMerge = i: current: services:
Skyler Grey7de65802023-10-19 22:23:47 +000073 if i > builtins.length services
Skyler Greyc0a62472023-10-18 23:29:13 +000074 then current
Skyler Grey7de65802023-10-19 22:23:47 +000075 else _iterateMerge (i+1) (current++[_merge (builtins.elemAt services i) {} "/" true 1000]) services;
Skyler Greyc0a62472023-10-18 23:29:13 +000076
77 _merge = service: currentConfig: currentPath: secure: priority:
78 if service.type == "hosts"
79 then _merge service.service (lib.mkMerge currentConfig {
80 name = service.host;
81 value = {
82 serverAliases = service.extraHosts;
83
84 enableACME = service.secure;
85 forceSSL = service.secure;
86 listen = [
87 {
88 addr = "0.0.0.0";
89 port = if service.secure then 443 else 80;
90 ssl = service.secure;
91 }
92 ];
93 };
94 }) currentPath service.secure priority
95 else if service.type == "reverseproxy"
96 then (lib.mkMerge currentConfig {
97 value.locations.${currentPath} = {
98 proxyPass = service.to;
99 proxyWebsockets = true;
100 recommendedProxySettings = true;
101 };
102 })
103 else if service.type == "php"
104 then (lib.mkMerge currentConfig {
105 value.locations.${currentPath} = {
106 root = service.root;
107 index = "index.php index.html index.htm";
108 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
109 };
110 value.locations."~ ^${currentPath}.*\.php$" = {
111 tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
112 extraConfig = ''
113 include ${pkgs.nginx}/conf/fastcgi_params;
114 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
115 fastcgi_param REDIRECT_STATUS 200;
116 fastcgi_pass unix:${service.socket};
117 fastcgi_intercept_errors on;
118 ${lib.optionalString secure "fastcgi_param HTTPS on;"}
119 '';
120 };
121 })
122 else if service.type == "redirect"
123 then (lib.mkMerge currentConfig {
124 value.locations.${currentPath}.return =
125 if service.permanent
126 then "308 ${service.to}"
127 else "307 ${service.to}";
128 })
129 else if service.type == "directory"
130 then (lib.mkMerge currentConfig {
131 value.locations.${currentPath} = {
132 root = service.root;
133 index = "index.html index.htm";
134 tryFiles = "$uri $uri/ =404";
Skyler Grey7de65802023-10-19 22:23:47 +0000135 extraConfig = lib.optionalString (!service.private) "autoindex on;";
Skyler Greyc0a62472023-10-18 23:29:13 +0000136 };
137 })
138 else if service.type == "file"
139 then (lib.mkMerge currentConfig {
140 value.locations.${currentPath} = {
141 tryFiles = "${service.path} =404";
142 };
143 })
144 else if service.type == "path"
Skyler Grey7ecfdba2023-10-19 23:19:35 +0000145 then _merge service.service currentConfig service.path service.secure priority
Skyler Greyc0a62472023-10-18 23:29:13 +0000146 else if service.type == "compose"
147 then (_iterateCompose service.services currentConfig currentPath secure priority 0)
148 else throw "Unknown service type: ${service.type}";
149 in (services: lib.pipe services [
150 (_iterateMerge 0 [])
151 builtins.listToAttrs
152 ]);
153
154 # https://www.nginx.com/resources/wiki/start/topics/examples/full/
155
156 /**
157 Internal needs to be a string that is both a host and a port, e.g. generic:1000
158 External should only be a port
159 Protocol should be TCP or UDP
160 */
161 Stream = external: internal: protocol: ''
162 server {
163 listen ${builtins.toString external} ${protocol};
164 proxy_pass ${internal};
165 }
166 '';
167
168 Alias = host: alias: {
169 inherit host;
170 aliases = [ alias ];
171 type = "aliases";
172 };
173
174 Aliases = host: aliases: {
175 inherit host aliases;
176 type = "aliases";
177 };
178}
179