python312Packages.dissect-extfs: 3.11 -> 3.12
[NixPkgs.git] / nixos / modules / services / web-servers / traefik.nix
blob1a65ce21112ee8e53ba8c4faa6f71fdb36169f8b
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.traefik;
7   jsonValue = with types;
8     let
9       valueType = nullOr (oneOf [
10         bool
11         int
12         float
13         str
14         (lazyAttrsOf valueType)
15         (listOf valueType)
16       ]) // {
17         description = "JSON value";
18         emptyValue.value = { };
19       };
20     in valueType;
21   dynamicConfigFile = if cfg.dynamicConfigFile == null then
22     pkgs.runCommand "config.toml" {
23       buildInputs = [ pkgs.remarshal ];
24       preferLocalBuild = true;
25     } ''
26       remarshal -if json -of toml \
27         < ${
28           pkgs.writeText "dynamic_config.json"
29           (builtins.toJSON cfg.dynamicConfigOptions)
30         } \
31         > $out
32     ''
33   else
34     cfg.dynamicConfigFile;
35   staticConfigFile = if cfg.staticConfigFile == null then
36     pkgs.runCommand "config.toml" {
37       buildInputs = [ pkgs.yj ];
38       preferLocalBuild = true;
39     } ''
40       yj -jt -i \
41         < ${
42           pkgs.writeText "static_config.json" (builtins.toJSON
43             (recursiveUpdate cfg.staticConfigOptions {
44               providers.file.filename = "${dynamicConfigFile}";
45             }))
46         } \
47         > $out
48     ''
49   else
50     cfg.staticConfigFile;
52   finalStaticConfigFile =
53     if cfg.environmentFiles == []
54     then staticConfigFile
55     else "/run/traefik/config.toml";
56 in {
57   options.services.traefik = {
58     enable = mkEnableOption "Traefik web server";
60     staticConfigFile = mkOption {
61       default = null;
62       example = literalExpression "/path/to/static_config.toml";
63       type = types.nullOr types.path;
64       description = ''
65         Path to traefik's static configuration to use.
66         (Using that option has precedence over `staticConfigOptions` and `dynamicConfigOptions`)
67       '';
68     };
70     staticConfigOptions = mkOption {
71       description = ''
72         Static configuration for Traefik.
73       '';
74       type = jsonValue;
75       default = { entryPoints.http.address = ":80"; };
76       example = {
77         entryPoints.web.address = ":8080";
78         entryPoints.http.address = ":80";
80         api = { };
81       };
82     };
84     dynamicConfigFile = mkOption {
85       default = null;
86       example = literalExpression "/path/to/dynamic_config.toml";
87       type = types.nullOr types.path;
88       description = ''
89         Path to traefik's dynamic configuration to use.
90         (Using that option has precedence over `dynamicConfigOptions`)
91       '';
92     };
94     dynamicConfigOptions = mkOption {
95       description = ''
96         Dynamic configuration for Traefik.
97       '';
98       type = jsonValue;
99       default = { };
100       example = {
101         http.routers.router1 = {
102           rule = "Host(`localhost`)";
103           service = "service1";
104         };
106         http.services.service1.loadBalancer.servers =
107           [{ url = "http://localhost:8080"; }];
108       };
109     };
111     dataDir = mkOption {
112       default = "/var/lib/traefik";
113       type = types.path;
114       description = ''
115         Location for any persistent data traefik creates, ie. acme
116       '';
117     };
119     group = mkOption {
120       default = "traefik";
121       type = types.str;
122       example = "docker";
123       description = ''
124         Set the group that traefik runs under.
125         For the docker backend this needs to be set to `docker` instead.
126       '';
127     };
129     package = mkPackageOption pkgs "traefik" { };
131     environmentFiles = mkOption {
132       default = [];
133       type = types.listOf types.path;
134       example = [ "/run/secrets/traefik.env" ];
135       description = ''
136         Files to load as environment file. Environment variables from this file
137         will be substituted into the static configuration file using envsubst.
138       '';
139     };
140   };
142   config = mkIf cfg.enable {
143     systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 traefik traefik - -" ];
145     systemd.services.traefik = {
146       description = "Traefik web server";
147       wants = [ "network-online.target" ];
148       after = [ "network-online.target" ];
149       wantedBy = [ "multi-user.target" ];
150       startLimitIntervalSec = 86400;
151       startLimitBurst = 5;
152       serviceConfig = {
153         EnvironmentFile = cfg.environmentFiles;
154         ExecStartPre = lib.optional (cfg.environmentFiles != [])
155           (pkgs.writeShellScript "pre-start" ''
156             umask 077
157             ${pkgs.envsubst}/bin/envsubst -i "${staticConfigFile}" > "${finalStaticConfigFile}"
158           '');
159         ExecStart = "${cfg.package}/bin/traefik --configfile=${finalStaticConfigFile}";
160         Type = "simple";
161         User = "traefik";
162         Group = cfg.group;
163         Restart = "on-failure";
164         AmbientCapabilities = "cap_net_bind_service";
165         CapabilityBoundingSet = "cap_net_bind_service";
166         NoNewPrivileges = true;
167         LimitNPROC = 64;
168         LimitNOFILE = 1048576;
169         PrivateTmp = true;
170         PrivateDevices = true;
171         ProtectHome = true;
172         ProtectSystem = "full";
173         ReadWritePaths = [ cfg.dataDir ];
174         RuntimeDirectory = "traefik";
175       };
176     };
178     users.users.traefik = {
179       group = "traefik";
180       home = cfg.dataDir;
181       createHome = true;
182       isSystemUser = true;
183     };
185     users.groups.traefik = { };
186   };