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