1 { config, lib, pkgs, ... }:
6 cfg = config.services.traefik;
7 jsonValue = with types;
9 valueType = nullOr (oneOf [
14 (lazyAttrsOf valueType)
17 description = "JSON value";
18 emptyValue.value = { };
21 dynamicConfigFile = if cfg.dynamicConfigFile == null then
22 pkgs.runCommand "config.toml" {
23 buildInputs = [ pkgs.remarshal ];
24 preferLocalBuild = true;
26 remarshal -if json -of toml \
28 pkgs.writeText "dynamic_config.json"
29 (builtins.toJSON cfg.dynamicConfigOptions)
34 cfg.dynamicConfigFile;
35 staticConfigFile = if cfg.staticConfigFile == null then
36 pkgs.runCommand "config.toml" {
37 buildInputs = [ pkgs.yj ];
38 preferLocalBuild = true;
42 pkgs.writeText "static_config.json" (builtins.toJSON
43 (recursiveUpdate cfg.staticConfigOptions {
44 providers.file.filename = "${dynamicConfigFile}";
52 finalStaticConfigFile =
53 if cfg.environmentFiles == []
55 else "/run/traefik/config.toml";
57 options.services.traefik = {
58 enable = mkEnableOption (lib.mdDoc "Traefik web server");
60 staticConfigFile = mkOption {
62 example = literalExpression "/path/to/static_config.toml";
63 type = types.nullOr types.path;
64 description = lib.mdDoc ''
65 Path to traefik's static configuration to use.
66 (Using that option has precedence over `staticConfigOptions` and `dynamicConfigOptions`)
70 staticConfigOptions = mkOption {
71 description = lib.mdDoc ''
72 Static configuration for Traefik.
75 default = { entryPoints.http.address = ":80"; };
77 entryPoints.web.address = ":8080";
78 entryPoints.http.address = ":80";
84 dynamicConfigFile = mkOption {
86 example = literalExpression "/path/to/dynamic_config.toml";
87 type = types.nullOr types.path;
88 description = lib.mdDoc ''
89 Path to traefik's dynamic configuration to use.
90 (Using that option has precedence over `dynamicConfigOptions`)
94 dynamicConfigOptions = mkOption {
95 description = lib.mdDoc ''
96 Dynamic configuration for Traefik.
101 http.routers.router1 = {
102 rule = "Host(`localhost`)";
103 service = "service1";
106 http.services.service1.loadBalancer.servers =
107 [{ url = "http://localhost:8080"; }];
112 default = "/var/lib/traefik";
114 description = lib.mdDoc ''
115 Location for any persistent data traefik creates, ie. acme
123 description = lib.mdDoc ''
124 Set the group that traefik runs under.
125 For the docker backend this needs to be set to `docker` instead.
130 default = pkgs.traefik;
131 defaultText = literalExpression "pkgs.traefik";
132 type = types.package;
133 description = lib.mdDoc "Traefik package to use.";
136 environmentFiles = mkOption {
138 type = types.listOf types.path;
139 example = [ "/run/secrets/traefik.env" ];
140 description = lib.mdDoc ''
141 Files to load as environment file. Environment variables from this file
142 will be substituted into the static configuration file using envsubst.
147 config = mkIf cfg.enable {
148 systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 traefik traefik - -" ];
150 systemd.services.traefik = {
151 description = "Traefik web server";
152 after = [ "network-online.target" ];
153 wantedBy = [ "multi-user.target" ];
154 startLimitIntervalSec = 86400;
157 EnvironmentFile = cfg.environmentFiles;
158 ExecStartPre = lib.optional (cfg.environmentFiles != [])
159 (pkgs.writeShellScript "pre-start" ''
161 ${pkgs.envsubst}/bin/envsubst -i "${staticConfigFile}" > "${finalStaticConfigFile}"
163 ExecStart = "${cfg.package}/bin/traefik --configfile=${finalStaticConfigFile}";
167 Restart = "on-failure";
168 AmbientCapabilities = "cap_net_bind_service";
169 CapabilityBoundingSet = "cap_net_bind_service";
170 NoNewPrivileges = true;
172 LimitNOFILE = 1048576;
174 PrivateDevices = true;
176 ProtectSystem = "full";
177 ReadWriteDirectories = cfg.dataDir;
178 RuntimeDirectory = "traefik";
182 users.users.traefik = {
189 users.groups.traefik = { };