main
1{lib, ...}: rec {
2 # Wrap IPv6 addresses in brackets so they can be used in a URL authority.
3 fmtAddr = isV6: addr:
4 if isV6
5 then "[${addr}]"
6 else addr;
7
8 sanitize = lib.replaceStrings ["." ":" "/" "*"] ["-" "-" "-" "-"];
9
10 templateName = domain: "caddy-reverse-proxy-${sanitize domain}";
11
12 normalizePath = p: let
13 p' =
14 if lib.hasPrefix "/" p
15 then p
16 else "/${p}";
17 in
18 lib.removeSuffix "/" p';
19
20 mkEntry = resolution: domain: conf: {
21 inherit domain resolution;
22 port = conf.port;
23 path =
24 if conf ? path && conf.path != null
25 then normalizePath conf.path
26 else null;
27 stripPath = conf.stripPath or false;
28 upstream = conf.upstream or null;
29 };
30
31 proxyLine = config: e:
32 if e.resolution.kind == "import"
33 then "import ${config.vaultix.templates.${templateName e.domain}.path}"
34 else let
35 upstream =
36 if e.upstream != null
37 then e.upstream
38 else "";
39 in "reverse_proxy http://${e.resolution.address}:${toString e.port}${upstream}";
40
41 entryLines = config: e: [(proxyLine config e)];
42
43 entryBlock = config: e: let
44 lines = entryLines config e;
45 directive =
46 if e.stripPath
47 then "handle_path"
48 else "handle";
49 mkBlock = p: "${directive} ${p} {\n${lib.concatMapStrings (l: "\t${l}\n") lines}}";
50 in [
51 (mkBlock e.path)
52 (mkBlock "${e.path}/*")
53 ];
54
55 fallbackBlock = config: e: let
56 lines = entryLines config e;
57 in "handle {\n${lib.concatMapStrings (l: "\t${l}\n") lines}}";
58
59 forwardAuthBlock = ''
60 forward_auth unix//run/tailscale.nginx-auth.sock {
61 uri /auth
62 header_up Remote-Addr {remote_host}
63 header_up Remote-Port {remote_port}
64 header_up Original-URI {uri}
65 copy_headers {
66 Tailscale-User>X-Webauth-User
67 Tailscale-Name>X-Webauth-Name
68 Tailscale-Login>X-Webauth-Login
69 Tailscale-Tailnet>X-Webauth-Tailnet
70 Tailscale-Profile-Picture>X-Webauth-Profile-Picture
71 }
72 }
73 '';
74}