grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / web-servers / trafficserver / default.nix
blob1cae7c7e13df28243ede5376d71b22755ddb0863
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.trafficserver;
7   user = config.users.users.trafficserver.name;
8   group = config.users.groups.trafficserver.name;
10   getManualUrl = name: "https://docs.trafficserver.apache.org/en/latest/admin-guide/files/${name}.en.html";
12   yaml = pkgs.formats.yaml { };
14   mkYamlConf = name: cfg:
15     if cfg != null then {
16       "trafficserver/${name}.yaml".source = yaml.generate "${name}.yaml" cfg;
17     } else {
18       "trafficserver/${name}.yaml".text = "";
19     };
21   mkRecordLines = path: value:
22     if isAttrs value then
23       lib.mapAttrsToList (n: v: mkRecordLines (path ++ [ n ]) v) value
24     else if isInt value then
25       "CONFIG ${concatStringsSep "." path} INT ${toString value}"
26     else if isFloat value then
27       "CONFIG ${concatStringsSep "." path} FLOAT ${toString value}"
28     else
29       "CONFIG ${concatStringsSep "." path} STRING ${toString value}";
31   mkRecordsConfig = cfg: concatStringsSep "\n" (flatten (mkRecordLines [ ] cfg));
32   mkPluginConfig = cfg: concatStringsSep "\n" (map (p: "${p.path} ${p.arg}") cfg);
35   options.services.trafficserver = {
36     enable = mkEnableOption "Apache Traffic Server";
38     cache = mkOption {
39       type = types.lines;
40       default = "";
41       example = "dest_domain=example.com suffix=js action=never-cache";
42       description = ''
43         Caching rules that overrule the origin's caching policy.
45         Consult the [upstream
46         documentation](${getManualUrl "cache.config"}) for more details.
47       '';
48     };
50     hosting = mkOption {
51       type = types.lines;
52       default = "";
53       example = "domain=example.com volume=1";
54       description = ''
55         Partition the cache according to origin server or domain
57         Consult the [
58         upstream documentation](${getManualUrl "hosting.config"}) for more details.
59       '';
60     };
62     ipAllow = mkOption {
63       type = types.nullOr yaml.type;
64       default = lib.importJSON ./ip_allow.json;
65       defaultText = literalMD "upstream defaults";
66       example = literalExpression ''
67         {
68           ip_allow = [{
69             apply = "in";
70             ip_addrs = "127.0.0.1";
71             action = "allow";
72             methods = "ALL";
73           }];
74         }
75       '';
76       description = ''
77         Control client access to Traffic Server and Traffic Server connections
78         to upstream servers.
80         Consult the [upstream
81         documentation](${getManualUrl "ip_allow.yaml"}) for more details.
82       '';
83     };
85     logging = mkOption {
86       type = types.nullOr yaml.type;
87       default = lib.importJSON ./logging.json;
88       defaultText = literalMD "upstream defaults";
89       example = { };
90       description = ''
91         Configure logs.
93         Consult the [upstream
94         documentation](${getManualUrl "logging.yaml"}) for more details.
95       '';
96     };
98     parent = mkOption {
99       type = types.lines;
100       default = "";
101       example = ''
102         dest_domain=. method=get parent="p1.example:8080; p2.example:8080" round_robin=true
103       '';
104       description = ''
105         Identify the parent proxies used in an cache hierarchy.
107         Consult the [upstream
108         documentation](${getManualUrl "parent.config"}) for more details.
109       '';
110     };
112     plugins = mkOption {
113       default = [ ];
115       description = ''
116         Controls run-time loadable plugins available to Traffic Server, as
117         well as their configuration.
119         Consult the [upstream
120         documentation](${getManualUrl "plugin.config"}) for more details.
121       '';
123       type = with types;
124         listOf (submodule {
125           options.path = mkOption {
126             type = str;
127             example = "xdebug.so";
128             description = ''
129               Path to plugin. The path can either be absolute, or relative to
130               the plugin directory.
131             '';
132           };
133           options.arg = mkOption {
134             type = str;
135             default = "";
136             example = "--header=ATS-My-Debug";
137             description = "arguments to pass to the plugin";
138           };
139         });
140     };
142     records = mkOption {
143       type = with types;
144         let valueType = (attrsOf (oneOf [ int float str valueType ])) // {
145           description = "Traffic Server records value";
146         };
147         in
148         valueType;
149       default = { };
150       example = { proxy.config.proxy_name = "my_server"; };
151       description = ''
152         List of configurable variables used by Traffic Server.
154         Consult the [
155         upstream documentation](${getManualUrl "records.config"}) for more details.
156       '';
157     };
159     remap = mkOption {
160       type = types.lines;
161       default = "";
162       example = "map http://from.example http://origin.example";
163       description = ''
164         URL remapping rules used by Traffic Server.
166         Consult the [
167         upstream documentation](${getManualUrl "remap.config"}) for more details.
168       '';
169     };
171     splitDns = mkOption {
172       type = types.lines;
173       default = "";
174       example = ''
175         dest_domain=internal.corp.example named="255.255.255.255:212 255.255.255.254" def_domain=corp.example search_list="corp.example corp1.example"
176         dest_domain=!internal.corp.example named=255.255.255.253
177       '';
178       description = ''
179         Specify the DNS server that Traffic Server should use under specific
180         conditions.
182         Consult the [
183         upstream documentation](${getManualUrl "splitdns.config"}) for more details.
184       '';
185     };
187     sslMulticert = mkOption {
188       type = types.lines;
189       default = "";
190       example = "dest_ip=* ssl_cert_name=default.pem";
191       description = ''
192         Configure SSL server certificates to terminate the SSL sessions.
194         Consult the [
195         upstream documentation](${getManualUrl "ssl_multicert.config"}) for more details.
196       '';
197     };
199     sni = mkOption {
200       type = types.nullOr yaml.type;
201       default = null;
202       example = literalExpression ''
203         {
204           sni = [{
205             fqdn = "no-http2.example.com";
206             https = "off";
207           }];
208         }
209       '';
210       description = ''
211         Configure aspects of TLS connection handling for both inbound and
212         outbound connections.
214         Consult the [upstream
215         documentation](${getManualUrl "sni.yaml"}) for more details.
216       '';
217     };
219     storage = mkOption {
220       type = types.lines;
221       default = "/var/cache/trafficserver 256M";
222       example = "/dev/disk/by-id/XXXXX volume=1";
223       description = ''
224         List all the storage that make up the Traffic Server cache.
226         Consult the [
227         upstream documentation](${getManualUrl "storage.config"}) for more details.
228       '';
229     };
231     strategies = mkOption {
232       type = types.nullOr yaml.type;
233       default = null;
234       description = ''
235         Specify the next hop proxies used in an cache hierarchy and the
236         algorithms used to select the next proxy.
238         Consult the [
239         upstream documentation](${getManualUrl "strategies.yaml"}) for more details.
240       '';
241     };
243     volume = mkOption {
244       type = types.nullOr yaml.type;
245       default = "";
246       example = "volume=1 scheme=http size=20%";
247       description = ''
248         Manage cache space more efficiently and restrict disk usage by
249         creating cache volumes of different sizes.
251         Consult the [
252         upstream documentation](${getManualUrl "volume.config"}) for more details.
253       '';
254     };
255   };
257   config = mkIf cfg.enable {
258     environment.etc = {
259       "trafficserver/cache.config".text = cfg.cache;
260       "trafficserver/hosting.config".text = cfg.hosting;
261       "trafficserver/parent.config".text = cfg.parent;
262       "trafficserver/plugin.config".text = mkPluginConfig cfg.plugins;
263       "trafficserver/records.config".text = mkRecordsConfig cfg.records;
264       "trafficserver/remap.config".text = cfg.remap;
265       "trafficserver/splitdns.config".text = cfg.splitDns;
266       "trafficserver/ssl_multicert.config".text = cfg.sslMulticert;
267       "trafficserver/storage.config".text = cfg.storage;
268       "trafficserver/volume.config".text = cfg.volume;
269     } // (mkYamlConf "ip_allow" cfg.ipAllow)
270     // (mkYamlConf "logging" cfg.logging)
271     // (mkYamlConf "sni" cfg.sni)
272     // (mkYamlConf "strategies" cfg.strategies);
274     environment.systemPackages = [ pkgs.trafficserver ];
275     systemd.packages = [ pkgs.trafficserver ];
277     # Traffic Server does privilege handling independently of systemd, and
278     # therefore should be started as root
279     systemd.services.trafficserver = {
280       enable = true;
281       wantedBy = [ "multi-user.target" ];
282     };
284     # These directories can't be created by systemd because:
285     #
286     #   1. Traffic Servers starts as root and switches to an unprivileged user
287     #      afterwards. The runtime directories defined below are assumed to be
288     #      owned by that user.
289     #   2. The bin/trafficserver script assumes these directories exist.
290     systemd.tmpfiles.rules = [
291       "d '/run/trafficserver' - ${user} ${group} - -"
292       "d '/var/cache/trafficserver' - ${user} ${group} - -"
293       "d '/var/lib/trafficserver' - ${user} ${group} - -"
294       "d '/var/log/trafficserver' - ${user} ${group} - -"
295     ];
297     services.trafficserver = {
298       records.proxy.config.admin.user_id = user;
299       records.proxy.config.body_factory.template_sets_dir =
300         "${pkgs.trafficserver}/etc/trafficserver/body_factory";
301     };
303     users.users.trafficserver = {
304       description = "Apache Traffic Server";
305       isSystemUser = true;
306       inherit group;
307     };
308     users.groups.trafficserver = { };
309   };