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    maxSize = conf.maxSize or null;
30  };
31
32  proxyLine = config: e:
33    if e.resolution.kind == "import"
34    then "import ${config.vaultix.templates.${templateName e.domain}.path}"
35    else let
36      upstream =
37        if e.upstream != null
38        then e.upstream
39        else "";
40    in "reverse_proxy http://${e.resolution.address}:${toString e.port}${upstream}";
41
42  maxSizeLines = e:
43    if e.maxSize == null
44    then []
45    else [
46      "request_body {"
47      "  max_size ${e.maxSize}"
48      "}"
49    ];
50
51  entryLines = config: e: maxSizeLines e ++ [(proxyLine config e)];
52
53  entryBlock = config: e: let
54    lines = entryLines config e;
55    directive =
56      if e.stripPath
57      then "handle_path"
58      else "handle";
59    mkBlock = p: "${directive} ${p} {\n${lib.concatMapStrings (l: "\t${l}\n") lines}}";
60  in [
61    (mkBlock e.path)
62    (mkBlock "${e.path}/*")
63  ];
64
65  fallbackBlock = config: e: let
66    lines = entryLines config e;
67  in "handle {\n${lib.concatMapStrings (l: "\t${l}\n") lines}}";
68
69  forwardAuthBlock = let
70    podmanRanges = [
71      "10.88.0.0/16"
72      "10.89.0.0/16"
73      "10.90.0.0/16"
74      "10.91.0.0/16"
75      "10.92.0.0/16"
76      "10.93.0.0/16"
77      "10.94.0.0/16"
78      "10.95.0.0/16"
79      "fd00::/8"
80    ];
81  in ''
82    @tailnet-clients {
83      not remote_ip ${lib.concatStringsSep " " podmanRanges}
84    }
85    forward_auth @tailnet-clients unix//run/tailscale.nginx-auth.sock {
86        uri /auth
87        header_up Remote-Addr {remote_host}
88        header_up Remote-Port {remote_port}
89        header_up Original-URI {uri}
90        copy_headers {
91            Tailscale-User>X-Webauth-User
92            Tailscale-Name>X-Webauth-Name
93            Tailscale-Login>X-Webauth-Login
94            Tailscale-Tailnet>X-Webauth-Tailnet
95            Tailscale-Profile-Picture>X-Webauth-Profile-Picture
96        }
97    }
98  '';
99}