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